11import { Injectable } from '@angular/core' ;
22import { Plugins , CameraResultType , Capacitor , FilesystemDirectory , CameraPhoto , CameraSource } from '@capacitor/core' ;
3+ import { Platform } from '@ionic/angular' ;
34
45const { Camera, Filesystem, Storage } = Plugins ;
56
@@ -9,13 +10,31 @@ const { Camera, Filesystem, Storage } = Plugins;
910export class PhotoService {
1011 public photos : Photo [ ] = [ ] ;
1112 private PHOTO_STORAGE : string = "photos" ;
13+ private platform : Platform ;
1214
13- constructor ( ) { }
15+ constructor ( platform : Platform ) {
16+ this . platform = platform ;
17+ }
1418
1519 async loadSaved ( ) {
1620 // Retrieve cached photo array data
1721 const photos = await Storage . get ( { key : this . PHOTO_STORAGE } ) ;
1822 this . photos = JSON . parse ( photos . value ) || [ ] ;
23+
24+ // If running on the web...
25+ if ( ! this . platform . is ( 'hybrid' ) ) {
26+ // Display the photo by reading into base64 format
27+ for ( let photo of this . photos ) {
28+ // Read each saved photo's data from the Filesystem
29+ const readFile = await Filesystem . readFile ( {
30+ path : photo . filepath ,
31+ directory : FilesystemDirectory . Data
32+ } ) ;
33+
34+ // Web platform only: Save the photo into the base64 field
35+ photo . base64 = `data:image/jpeg;base64,${ readFile . data } ` ;
36+ }
37+ }
1938 }
2039
2140 /* Use the device camera to take a photo:
@@ -27,7 +46,7 @@ export class PhotoService {
2746 // Store a reference to all photo filepaths using Storage API:
2847 // https://capacitor.ionicframework.com/docs/apis/storage
2948 */
30- public async takePhoto ( ) {
49+ public async addNewToGallery ( ) {
3150 // Take a photo
3251 const capturedPhoto = await Camera . getPhoto ( {
3352 resultType : CameraResultType . Uri , // file-based data; provides best performance
@@ -38,40 +57,85 @@ export class PhotoService {
3857 const savedImageFile = await this . savePicture ( capturedPhoto ) ;
3958
4059 // Add new photo to Photos array
41- this . photos . unshift ( {
42- filepath : savedImageFile ,
43- webviewPath : Capacitor . convertFileSrc ( savedImageFile )
44- } ) ;
60+ this . photos . unshift ( savedImageFile ) ;
4561
4662 // Cache all photo data for future retrieval
4763 Storage . set ( {
4864 key : this . PHOTO_STORAGE ,
49- value : JSON . stringify ( this . photos )
65+ value : this . platform . is ( 'hybrid' )
66+ ? JSON . stringify ( this . photos )
67+ : JSON . stringify ( this . photos . map ( p => {
68+ // Don't save the base64 representation of the photo data,
69+ // since it's already saved on the Filesystem
70+ const photoCopy = { ...p } ;
71+ delete photoCopy . base64 ;
72+
73+ return photoCopy ;
74+ } ) )
5075 } ) ;
5176 }
5277
5378 // Save picture to file on device
5479 private async savePicture ( cameraPhoto : CameraPhoto ) {
55- // Read the file into its base64 version
56- const readFile = await Filesystem . readFile ( {
57- path : cameraPhoto . path
58- } ) ;
80+ // Convert photo to base64 format, required by Filesystem API to save
81+ const base64Data = await this . readAsBase64 ( cameraPhoto ) ;
5982
60- // Write the file to the data directory (instead of temp storage)
83+ // Write the file to the data directory
6184 const fileName = new Date ( ) . getTime ( ) + '.jpeg' ;
6285 await Filesystem . writeFile ( {
6386 path : fileName ,
64- data : readFile . data ,
87+ data : base64Data ,
6588 directory : FilesystemDirectory . Data
6689 } ) ;
6790
68- // Get the new, complete filepath
69- const fileUri = await Filesystem . getUri ( {
70- directory : FilesystemDirectory . Data ,
71- path : fileName
72- } ) ;
91+ // Get platform-specific photo filepaths
92+ return await this . getPhotoFile ( cameraPhoto , fileName ) ;
93+ }
7394
74- return fileUri . uri ;
95+ // Read camera photo into base64 format based on the platform the app is running on
96+ private async readAsBase64 ( cameraPhoto : CameraPhoto ) {
97+ // "hybrid" will detect Cordova or Capacitor
98+ if ( this . platform . is ( 'hybrid' ) ) {
99+ // Read the file into base64 format
100+ const file = await Filesystem . readFile ( {
101+ path : cameraPhoto . path
102+ } ) ;
103+
104+ return file . data ;
105+ }
106+ else {
107+ // Fetch the photo, read as a blob, then convert to base64 format
108+ const response = await fetch ( cameraPhoto . webPath ) ;
109+ const blob = await response . blob ( ) ;
110+
111+ return await this . convertBlobToBase64 ( blob ) as string ;
112+ }
113+ }
114+
115+ // Retrieve the photo metadata based on the platform the app is running on
116+ private async getPhotoFile ( cameraPhoto , fileName ) {
117+ if ( this . platform . is ( 'hybrid' ) ) {
118+ // Get the new, complete filepath of the photo saved on filesystem
119+ const fileUri = await Filesystem . getUri ( {
120+ directory : FilesystemDirectory . Data ,
121+ path : fileName
122+ } ) ;
123+
124+ // Display the new image by rewriting the 'file://' path to HTTP
125+ // Details: https://ionicframework.com/docs/building/webview#file-protocol
126+ return {
127+ filepath : fileUri . uri ,
128+ webviewPath : Capacitor . convertFileSrc ( fileUri . uri ) ,
129+ } ;
130+ }
131+ else {
132+ // Use webPath to display the new image instead of base64 since it's
133+ // already loaded into memory
134+ return {
135+ filepath : fileName ,
136+ webviewPath : cameraPhoto . webPath
137+ } ;
138+ }
75139 }
76140
77141 // Delete picture by removing it from reference data and the filesystem
@@ -92,9 +156,19 @@ export class PhotoService {
92156 directory : FilesystemDirectory . Data
93157 } ) ;
94158 }
159+
160+ convertBlobToBase64 = blob => new Promise ( ( resolve , reject ) => {
161+ const reader = new FileReader ;
162+ reader . onerror = reject ;
163+ reader . onload = ( ) => {
164+ resolve ( reader . result ) ;
165+ } ;
166+ reader . readAsDataURL ( blob ) ;
167+ } ) ;
95168}
96169
97170class Photo {
98171 filepath : string ;
99172 webviewPath : string ;
173+ base64 ?: string ;
100174}
0 commit comments