一,需求背景
有這樣一個需求,將頁面上的某個自定義組件以圖片的形式保存至相冊。
二,需求拆解
根據需求分析,可將需求拆解成兩步:
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(組件截圖)
保存媒體庫資源