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,30 @@ 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 ( this . platform . is ( 'pwa' ) ) {
25+ // Display the photo by reading into base64 format
26+ for ( let photo of this . photos ) {
27+ // Read each saved photo's data from the Filesystem
28+ const readFile = await Filesystem . readFile ( {
29+ path : photo . filepath ,
30+ directory : FilesystemDirectory . Data
31+ } ) ;
32+
33+ // Web platform only: Save the photo into the base64 field
34+ photo . base64 = `data:image/jpeg;base64,${ readFile . data } ` ;
35+ }
36+ }
1937 }
2038
2139 /* Use the device camera to take a photo:
@@ -27,7 +45,7 @@ export class PhotoService {
2745 // Store a reference to all photo filepaths using Storage API:
2846 // https://capacitor.ionicframework.com/docs/apis/storage
2947 */
30- public async takePhoto ( ) {
48+ public async addNewToGallery ( ) {
3149 // Take a photo
3250 const capturedPhoto = await Camera . getPhoto ( {
3351 resultType : CameraResultType . Uri , // file-based data; provides best performance
@@ -38,40 +56,85 @@ export class PhotoService {
3856 const savedImageFile = await this . savePicture ( capturedPhoto ) ;
3957
4058 // Add new photo to Photos array
41- this . photos . unshift ( {
42- filepath : savedImageFile ,
43- webviewPath : Capacitor . convertFileSrc ( savedImageFile )
44- } ) ;
59+ this . photos . unshift ( savedImageFile ) ;
4560
4661 // Cache all photo data for future retrieval
4762 Storage . set ( {
4863 key : this . PHOTO_STORAGE ,
49- value : JSON . stringify ( this . photos )
64+ value : this . platform . is ( 'hybrid' )
65+ ? JSON . stringify ( this . photos )
66+ : JSON . stringify ( this . photos . map ( p => {
67+ // Don't save the base64 representation of the photo data,
68+ // since it's already saved on the Filesystem
69+ const photoCopy = { ...p } ;
70+ delete photoCopy . base64 ;
71+
72+ return photoCopy ;
73+ } ) )
5074 } ) ;
5175 }
5276
5377 // Save picture to file on device
5478 private async savePicture ( cameraPhoto : CameraPhoto ) {
55- // Read the file into its base64 version
56- const readFile = await Filesystem . readFile ( {
57- path : cameraPhoto . path
58- } ) ;
79+ // Convert photo to base64 format, required by Filesystem API to save
80+ const base64Data = await this . readAsBase64 ( cameraPhoto ) ;
5981
60- // Write the file to the data directory (instead of temp storage)
82+ // Write the file to the data directory
6183 const fileName = new Date ( ) . getTime ( ) + '.jpeg' ;
6284 await Filesystem . writeFile ( {
6385 path : fileName ,
64- data : readFile . data ,
86+ data : base64Data ,
6587 directory : FilesystemDirectory . Data
6688 } ) ;
6789
68- // Get the new, complete filepath
69- const fileUri = await Filesystem . getUri ( {
70- directory : FilesystemDirectory . Data ,
71- path : fileName
72- } ) ;
90+ // Get platform-specific photo filepaths
91+ return await this . getPhotoFile ( cameraPhoto , fileName ) ;
92+ }
7393
74- return fileUri . uri ;
94+ // Read camera photo into base64 format based on the platform the app is running on
95+ private async readAsBase64 ( cameraPhoto : CameraPhoto ) {
96+ // "hybrid" will detect Cordova or Capacitor
97+ if ( this . platform . is ( 'hybrid' ) ) {
98+ // Read the file into base64 format
99+ const file = await Filesystem . readFile ( {
100+ path : cameraPhoto . path
101+ } ) ;
102+
103+ return file . data ;
104+ }
105+ else {
106+ // Fetch the photo, read as a blob, then convert to base64 format
107+ const response = await fetch ( cameraPhoto . webPath ) ;
108+ const blob = await response . blob ( ) ;
109+
110+ return await this . convertBlobToBase64 ( blob ) as string ;
111+ }
112+ }
113+
114+ // Retrieve the photo metadata based on the platform the app is running on
115+ private async getPhotoFile ( cameraPhoto , fileName ) {
116+ if ( this . platform . is ( 'hybrid' ) ) {
117+ // Get the new, complete filepath of the photo saved on filesystem
118+ const fileUri = await Filesystem . getUri ( {
119+ directory : FilesystemDirectory . Data ,
120+ path : fileName
121+ } ) ;
122+
123+ // Display the new image by rewriting the 'file://' path to HTTP
124+ // Details: https://ionicframework.com/docs/building/webview#file-protocol
125+ return {
126+ filepath : fileUri . uri ,
127+ webviewPath : Capacitor . convertFileSrc ( fileUri . uri ) ,
128+ } ;
129+ }
130+ else {
131+ // Use webPath to display the new image instead of base64 since it's
132+ // already loaded into memory
133+ return {
134+ filepath : fileName ,
135+ webviewPath : cameraPhoto . webPath
136+ } ;
137+ }
75138 }
76139
77140 // Delete picture by removing it from reference data and the filesystem
@@ -92,9 +155,19 @@ export class PhotoService {
92155 directory : FilesystemDirectory . Data
93156 } ) ;
94157 }
158+
159+ convertBlobToBase64 = blob => new Promise ( ( resolve , reject ) => {
160+ const reader = new FileReader ;
161+ reader . onerror = reject ;
162+ reader . onload = ( ) => {
163+ resolve ( reader . result ) ;
164+ } ;
165+ reader . readAsDataURL ( blob ) ;
166+ } ) ;
95167}
96168
97169class Photo {
98170 filepath : string ;
99171 webviewPath : string ;
172+ base64 ?: string ;
100173}
0 commit comments