一,需求背景
有这样一个需求,将页面上的某个自定义组件以图片的形式保存至相册。
二,需求拆解
根据需求分析,可将需求拆解成两步:
1,将组件转换成图片资源;
2,将图片保存到相册
其中,第2步又有两种情况:
1,App具有申请受限权限:ohos.permission.WRITE_IMAGEVIDEO 的能力;
2,App不具有申请受限权限的能力
三,方案实现
1,将组件转换成图片资源
通过组件的截图能力获取图片资源PixelMap
componentSnapshot.get(viewId).then((pixelMap: PixelMap) => {})
viewId:指组件id,在使用自定义组件时为组件添加的id
如:
Image($r('app.media.image')).width('38vp').height('38vp').id('image')
详细说明请查看官方文档
2,将图片保存到相册
1> 有受限权限:ohos.permission.WRITE_IMAGEVIDEO 时:
let helper = photoAccessHelper.getPhotoAccessHelper(context);let uri = await helper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'jpeg');let file = await fileIo.open(uri, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);let imagePackerApi = image.createImagePacker();let packOpts: image.PackingOption = { format: 'image/jpeg', quality: quality };imagePackerApi.packToFile(snapImage, file.fd, packOpts, (err: BusinessError) => {if (err) {console.error(`Failed to pack the image to file.code ${err.code},message is ${err.message}`);} else {console.info('Succeeded in packing the image to file.');imagePackerApi.release((err: BusinessError) => {if (err) {console.error(`Failed to release the image source instance.code ${err.code},message is ${err.message}`);} else {console.info('Succeeded in releasing the image source instance.');fileIo.close(file.fd);}})}})
2> 不具备申请受限权限能力时
首先要将第一步生成的PixelMap对象保存到应用的沙箱目录下
//将PixelMap转成ArrayBuffer 对象
const imagePacker: image.ImagePacker = image.createImagePacker()
const buffer: ArrayBuffer = await imagePacker.packToData(pixelMap, {format: 'image/png',quality: 100
})
/*** 将文件保存在应用的沙箱目录下,默认是txt文件*/static saveToPrivate(context: common.UIAbilityContext,buffer: string | ArrayBuffer,fileName?: string): Promise<string> {const filesDir: string = context.filesDirlet name: string | undefined = fileNameif (!name || name.length === 0) {name = new Date().toTimeString() + ".txt"}console.info('fileName is ' + name)const filePath: string = filesDir + "/" + nameconst file: fileIo.File = fileIo.openSync(filePath, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE)return new Promise((resolve, reject) => {fileIo.write(file.fd, buffer).then((length: number) => {console.log("write file success, length: " + length)resolve(fileUri.getUriFromPath(filePath))}).catch((error: BusinessError) => {console.log("write file fail, message: " + error.message);reject('')}).finally(() => {fileIo.closeSync(file)})})}
将图片资源保存到沙箱目录下,并获取到对应的fileUri,注意这里是fileUri因为后面保存到相册要用到。
方案一:使用安全控件SaveButton 保存到相册
// 设置安全控件按钮属性saveButtonOptions: SaveButtonOptions = {icon: SaveIconStyle.FULL_FILLED,text: SaveDescription.SAVE_IMAGE,buttonType: ButtonType.Capsule} SaveButton(this.saveButtonOptions) // 创建安全控件按钮.onClick(async (event, result: SaveButtonOnClickResult) => {if (result == SaveButtonOnClickResult.SUCCESS) {try {let context = getContext();let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context);// 上一步报错到沙箱目录下的fileUrilet fileUri = "file://adfad"let assetChangeRequest: photoAccessHelper.MediaAssetChangeRequest = photoAccessHelper.MediaAssetChangeRequest.createImageAssetRequest(context,fileUri);await phAccessHelper.applyChanges(assetChangeRequest);console.info('createAsset successfully, uri: ' + assetChangeRequest.getAsset().uri);} catch (err) {console.error(`create asset failed with error: ${err.code}, ${err.message}`);}} else {console.error('SaveButtonOnClickResult create asset failed');}})
方案二:使用弹窗授权保存到相册
/*** 将指定uris路径下的图片或视频拷贝到相册中* @param uris 需保存到媒体库中的图片/视频文件对应的媒体库uri。* 仅支持处理图片、视频uri。不支持手动拼接的uri,需调用接口获取* @returns true:保存成功,false:保存失败*/static async copyMediaToGallery(context: common.UIAbilityContext,uris: Array<string> | string,photoType: photoAccessHelper.PhotoType = photoAccessHelper.PhotoType.IMAGE): Promise<boolean> {try {const photoHelper = photoAccessHelper.getPhotoAccessHelper(context)if (typeof uris === 'string') {uris = [uris]}let photoConfigs: Array<photoAccessHelper.PhotoCreationConfig> = []const fileNameExt: string = photoType === photoAccessHelper.PhotoType.IMAGE ? 'jpg' : 'mp4'uris.forEach(() => {photoConfigs.push({fileNameExtension: fileNameExt,photoType: photoType,})})const desFileUris: Array<string> = await photoHelper.showAssetsCreationDialog(uris, photoConfigs)if (uris.length !== desFileUris.length) {return false}for (let i = 0; i < uris.length; i++) {const srcFile: fileIo.File = fileIo.openSync(uris[i], fileIo.OpenMode.READ_ONLY)const desFile: fileIo.File = fileIo.openSync(desFileUris[i], fileIo.OpenMode.WRITE_ONLY)fileIo.copyFileSync(srcFile.fd, desFile.fd)fileIo.close(srcFile)fileIo.close(desFile)}console.info('copyPhotoToGallery success')return true} catch (err) {console.info('copyPhotoToGallery error: ' + err.code + ',' + err.message)return false}}
参考文档:
componentSnapshot(组件截图)
保存媒体库资源