Issue
I am new to React and Ionic and builded the Ionic React photo gallery app with the help of this ionic tutorial. Now I also want to add additional info like its date, its location, some inputfields,... to the image when it is displayed but I just did not figure out how.
This is the code from the tutorial:
import { useState, useEffect } from "react";
import { isPlatform } from '@ionic/react';
import { Camera, CameraResultType, CameraSource, Photo } from '@capacitor/camera';
import { Filesystem, Directory } from '@capacitor/filesystem'
import { Storage } from '@capacitor/storage'
import { Capacitor } from '@capacitor/core';
import internal from "assert";
import { defaultMaxListeners } from "stream";
const PHOTO_STORAGE = "photos";
export function usePhotoGallery() {
const [photos, setPhotos] = useState<UserPhoto[]>([]);
useEffect(() => {
const loadSaved = async () => {
const {value} = await Storage.get({key: PHOTO_STORAGE });
const photosInStorage = (value ? JSON.parse(value) : []) as UserPhoto[];
// If running on the web...
if (!isPlatform('hybrid')) {
for (let photo of photosInStorage) {
const file = await Filesystem.readFile({
path: photo.filepath,
directory: Directory.Data
});
// Web platform only: Load the photo as base64 data
photo.webviewPath = `data:image/jpeg;base64,${file.data}`;
}
}
setPhotos(photosInStorage);
};
loadSaved();
}, []);
const takePhoto = async () => {
const cameraPhoto = await Camera.getPhoto({
resultType: CameraResultType.Uri,
source: CameraSource.Camera,
quality: 100
});
const fileName = new Date().getTime() + '.jpeg';
const savedFileImage = await savePicture(cameraPhoto, fileName);
const newPhotos = [savedFileImage, ...photos];
setPhotos(newPhotos);
Storage.set({key: PHOTO_STORAGE,value: JSON.stringify(newPhotos)});
};
const savePicture = async (photo: Photo, fileName: string): Promise<UserPhoto> => {
let base64Data: string;
// "hybrid" will detect Cordova or Capacitor;
if (isPlatform('hybrid')) {
const file = await Filesystem.readFile({
path: photo.path!
});
base64Data = file.data;
} else {
base64Data = await base64FromPath(photo.webPath!);
}
const savedFile = await Filesystem.writeFile({
path: fileName,
data: base64Data,
directory: Directory.Data
});
if (isPlatform('hybrid')) {
// Display the new image by rewriting the 'file://' path to HTTP
// Details: https://ionicframework.com/docs/building/webview#file-protocol
return {
filepath: savedFile.uri,
webviewPath: Capacitor.convertFileSrc(savedFile.uri),
};
}
else {
// Use webPath to display the new image instead of base64 since it's
// already loaded into memory
return {
filepath: fileName,
webviewPath: photo.webPath
};
}
};
const deletePhoto = async (photo: UserPhoto) => {
// Remove this photo from the Photos reference data array
const newPhotos = photos.filter(p => p.filepath !== photo.filepath);
// Update photos array cache by overwriting the existing photo array
Storage.set({key: PHOTO_STORAGE, value: JSON.stringify(newPhotos) });
// delete photo file from filesystem
const filename = photo.filepath.substr(photo.filepath.lastIndexOf('/') + 1);
await Filesystem.deleteFile({
path: filename,
directory: Directory.Data
});
setPhotos(newPhotos);
};
return {
deletePhoto,
photos,
takePhoto
};
}
export interface UserPhoto {
filepath: string;
webviewPath?: string;
}
export async function base64FromPath(path: string): Promise<string> {
const response = await fetch(path);
const blob = await response.blob();
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onerror = reject;
reader.onload = () => {
if (typeof reader.result === 'string') {
resolve(reader.result);
} else {
reject('method did not return a string')
}
};
reader.readAsDataURL(blob);
});
}
I managed to get the date and location with the Geolocation Plugin but I have no clue how to bind it to the taken photo...
I assume that I have to add the desired data via function base64FromPath()
for web and const file = await Filesystem.readFile()
for mobile? And afterwards display with the export interface UserPhoto
part but I am completly lost and do not know where to start. Any suggestions welcome!
Solution
I found a way might not be the prettiest or directest but it seems to work for me.
Within the takePhoto
function I get the location and date and then pass it on via the savePicture
function. Inside the savePicture
function I return latitude
, longitude
and time
and therefore can access it through the loadSaved
function within the photo
object. Inside interface UserPhoto
the 3 variables need also to be declared.
Here is the updated code if somebody would like to make a suggestion:
import { useState, useEffect } from "react";
import { isPlatform } from '@ionic/react';
import { Geolocation, Geoposition } from '@ionic-native/geolocation';
import { Camera, CameraResultType, CameraSource, CameraDirection, Photo } from '@capacitor/camera';
import { Filesystem, Directory } from '@capacitor/filesystem'
import { Storage } from '@capacitor/storage'
import { Capacitor } from '@capacitor/core';
import { stringify } from "querystring";
const PHOTO_STORAGE = "photos";
export function usePhotoGallery() {
const [photos, setPhotos] = useState<UserPhoto[]>([]);
useEffect(() => {
const loadSaved = async () => {
const {value} = await Storage.get({key: PHOTO_STORAGE });
const photosInStorage = (value ? JSON.parse(value) : []) as UserPhoto[];
// If running on the web...
if (!isPlatform('hybrid')) {
for (let photo of photosInStorage) {
const file = await Filesystem.readFile({
path: photo.filepath,
directory: Directory.Data
});
// Web platform only: Load the photo as base64 data
photo.webviewPath = `data:image/jpeg;base64,${file.data}`;
}
}
setPhotos(photosInStorage);
};
loadSaved();
}, []);
const takePhoto = async () => {
const position = await Geolocation.getCurrentPosition();
const latitude = position.coords.latitude
const longitude = position.coords.longitude
const time = new Date(position.timestamp).toLocaleString()
const cameraPhoto = await Camera.getPhoto({
resultType: CameraResultType.Uri,
source: CameraSource.Camera,
direction: CameraDirection.Rear,
quality: 100
});
const fileName = new Date().getTime() + '.jpeg';
const savedFileImage = await savePicture(cameraPhoto, fileName, latitude, longitude, time);
const newPhotos = [savedFileImage, ...photos];
setPhotos(newPhotos);
Storage.set({key: PHOTO_STORAGE,value: JSON.stringify(newPhotos)});
};
const savePicture = async (photo: Photo, fileName: string, latitude: number, longitude: number, time:string): Promise<UserPhoto> => {
let base64Data: string;
// "hybrid" will detect Cordova or Capacitor;
if (isPlatform('hybrid')) {
const file = await Filesystem.readFile({
path: photo.path!
});
base64Data = file.data;
} else {
base64Data = await base64FromPath(photo.webPath!);
}
console.log("base64Data")
console.log(base64Data)
let savedFile = await Filesystem.writeFile({
path: fileName,
data: base64Data,
directory: Directory.Data
});
console.log(savedFile)
if (isPlatform('hybrid')) {
// Display the new image by rewriting the 'file://' path to HTTP
// Details: https://ionicframework.com/docs/building/webview#file-protocol
return {
filepath: savedFile.uri,
webviewPath: Capacitor.convertFileSrc(savedFile.uri),
latitude: latitude,
longitude: longitude,
time: time
};
}
else {
// Use webPath to display the new image instead of base64 since it's
// already loaded into memory
return {
filepath: fileName,
webviewPath: photo.webPath,
latitude: latitude,
longitude: longitude,
time: time
};
}
};
const deletePhoto = async (photo: UserPhoto) => {
// Remove this photo from the Photos reference data array
const newPhotos = photos.filter(p => p.filepath !== photo.filepath);
// Update photos array cache by overwriting the existing photo array
Storage.set({key: PHOTO_STORAGE, value: JSON.stringify(newPhotos) });
// delete photo file from filesystem
const filename = photo.filepath.substr(photo.filepath.lastIndexOf('/') + 1);
await Filesystem.deleteFile({
path: filename,
directory: Directory.Data
});
setPhotos(newPhotos);
};
return {
deletePhoto,
photos,
takePhoto
};
}
export interface UserPhoto {
filepath: string;
webviewPath?: string;
latitude: number;
longitude: number;
time: string;
}
export async function base64FromPath(path: string): Promise<string> {
const response = await fetch(path);
const blob = await response.blob();
//const blob = new Blob(neu)
return new Promise((resolve, reject) => {
const reader = new FileReader();
console.log(reader)
reader.onerror = reject;
reader.onload = () => {
if (typeof reader.result === 'string') {
resolve(reader.result);
} else {
reject('method did not return a string')
}
};
reader.readAsDataURL(blob);
});
}
To access is in my UI.tsx I use eg {photo.latitude}
to display the taken latitude value
Answered By - jonsken
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.