Skip to main content

将照片保存到文件系统

¥Saving Photos to the Filesystem

我们现在可以拍摄多张照片并将它们显示在应用第二个选项卡上的照片库中。然而,这些照片目前并未永久存储,因此当应用关闭时,它们将被删除。

¥We’re now able to take multiple photos and display them in a photo gallery on the second tab of our app. These photos, however, are not currently being stored permanently, so when the app is closed, they will be deleted.

文件系统 API

¥Filesystem API

幸运的是,将它们保存到文件系统只需几个步骤。首先在 PhotoService 类 (src/app/services/photo.service.ts) 中创建一个新的类方法 savePicture()。我们传入 photo 对象,它代表新捕获的设备照片:

¥Fortunately, saving them to the filesystem only takes a few steps. Begin by creating a new class method, savePicture(), in the PhotoService class (src/app/services/photo.service.ts). We pass in the photo object, which represents the newly captured device photo:

private async savePicture(photo: Photo) { }

我们可以在 addNewToGallery() 中立即使用这个新方法:

¥We can use this new method immediately in addNewToGallery():

public async addNewToGallery() {
// Take a photo
const capturedPhoto = await Camera.getPhoto({
resultType: CameraResultType.Uri, // file-based data; provides best performance
source: CameraSource.Camera, // automatically take a new photo with the camera
quality: 100 // highest quality (0 to 100)
});

// Save the picture and add it to photo collection
const savedImageFile = await this.savePicture(capturedPhoto);
this.photos.unshift(savedImageFile);
}

我们将使用 Capacitor 文件系统 API 将照片保存到文件系统。首先,将照片转换为 base64 格式,然后将数据提供给文件系统的 writeFile 函数。你可能还记得,我们通过将 tab2.page.html 中每个图片的源路径(src 属性)设置为 webviewPath 属性来在屏幕上显示每张照片。因此,设置它然后返回新的 Photo 对象。

¥We’ll use the Capacitor Filesystem API to save the photo to the filesystem. To start, convert the photo to base64 format, then feed the data to the Filesystem’s writeFile function. As you’ll recall, we display each photo on the screen by setting each image’s source path (src attribute) in tab2.page.html to the webviewPath property. So, set it then return the new Photo object.

private async savePicture(photo: Photo) {
// Convert photo to base64 format, required by Filesystem API to save
const base64Data = await this.readAsBase64(photo);

// Write the file to the data directory
const fileName = Date.now() + '.jpeg';
const savedFile = await Filesystem.writeFile({
path: fileName,
data: base64Data,
directory: Directory.Data
});

// Use webPath to display the new image instead of base64 since it's
// already loaded into memory
return {
filepath: fileName,
webviewPath: photo.webPath
};
}

readAsBase64() 是我们接下来定义的辅助函数。通过单独的方法进行组织非常有用,因为它需要少量特定于平台(Web 与移动)的逻辑 - 稍后会详细介绍。现在,实现在网络上运行的逻辑:

¥readAsBase64() is a helper function we’ll define next. It's useful to organize via a separate method since it requires a small amount of platform-specific (web vs. mobile) logic - more on that in a bit. For now, implement the logic for running on the web:

private async readAsBase64(photo: Photo) {
// Fetch the photo, read as a blob, then convert to base64 format
const response = await fetch(photo.webPath!);
const blob = await response.blob();

return await this.convertBlobToBase64(blob) as string;
}

private convertBlobToBase64 = (blob: Blob) => new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onerror = reject;
reader.onload = () => {
resolve(reader.result);
};
reader.readAsDataURL(blob);
});

在网络上获取 Base64 格式的相机照片似乎比在移动设备上要困难一些。实际上,我们只是使用内置的 Web API:fetch() 是一种将文件读取为 Blob 格式的巧妙方法,然后使用 FileReader 的 readAsDataURL() 将照片 Blob 转换为 Base64。

¥Obtaining the camera photo as base64 format on the web appears to be a bit trickier than on mobile. In reality, we’re just using built-in web APIs: fetch() as a neat way to read the file into blob format, then FileReader’s readAsDataURL() to convert the photo blob to base64.

我们开始吧!每次拍摄新照片时,它都会自动保存到文件系统中。

¥There we go! Each time a new photo is taken, it’s now automatically saved to the filesystem.