一,需求背景
有这样一个需求,将页面上的某个自定义组件以图片的形式保存至相册。
二,需求拆解
根据需求分析,可将需求拆解成两步:
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.filesDir
let name: string | undefined = fileName
if (!name || name.length === 0) {
name = new Date().toTimeString() + ".txt"
}
console.info('fileName is ' + name)
const filePath: string = filesDir + "/" + name
const 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);
// 上一步报错到沙箱目录下的fileUri
let 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
}
}
参考文档: