
回复
@TOC
从功能上来说,保存图片到相机涉及到的权限是ohos.permission.WRITE_IMAGEVIDEO,仅特殊场景与功能才可申请此权限,例如应用需要克隆、备份或同步图片/视频类文件。还要一种方式是使用安全控件来临时申请权限。
// 保存至图库按钮
Button() {
Row() {
Image($r('app.media.ic_download'))
.width(20)
.height(20)
.fillColor(Color.White)
.margin({ right: 5 })
Text('保存至图库')
.fontSize(18)
.fontWeight(FontWeight.Bold)
.fontColor(Color.White)
}
}
.width('42%')
.height('6%')
.borderRadius(20)
.backgroundColor(`#${this.movie.bgColor}`)
.onClick(() => {
// TODO: 实现保存至图库逻辑
console.log('保存至图库');
})
.margin({ left: 10, right: 10 })
需要申请权限,在模块的module.json5中进行配置
{
"name": "ohos.permission.READ_IMAGEVIDEO",
"usedScene": {
"abilities": [
"EntryAbility"
],
"when": "inuse"
},
"reason": "$string:WRITE_IMAGEVIDEO"
},
{
"name": "ohos.permission.WRITE_IMAGEVIDEO",
"usedScene": {
"abilities": [
"EntryAbility"
],
"when": "inuse"
},
"reason": "$string:WRITE_IMAGEVIDEO"
}
进行下载操作时,进行申请权限
/**
* 创建申请权限明细(非安全控件使用时使用)
* @returns
*/
async reqPermissionsFromUser(): Promise<number[]> {
let atManager = abilityAccessCtrl.createAtManager();
let grantStatus = await atManager.requestPermissionsFromUser(this.context, ['ohos.permission.WRITE_IMAGEVIDEO']);
return grantStatus.authResults;
}
/**
* 用户申请权限(非安全控件使用时使用)
*/
async requestPermission() {
let grantStatus = await this.reqPermissionsFromUser();
for (let i = 0; i < grantStatus.length; i++) {
if (grantStatus[i] === 0) {
// 用户授权,可以继续访问目标操作
}
}
}
SaveButton({icon:SaveIconStyle.FULL_FILLED, text: SaveDescription.SAVE_IMAGE, buttonType: ButtonType.ROUNDED_RECTANGLE })
.fontColor(Color.White)
.fontWeight(FontWeight.Medium)
.onClick(async (event: ClickEvent, result: SaveButtonOnClickResult) => {
// TODO: 实现保存至图库逻辑
console.log('保存至图库');
})
/**
* 获取网络图片的原始二进制数据
* @param url
* @param callback
*/
async getPicArrayBuffer(url:string,callback:(buf:ArrayBuffer|null)=>void) {
http.createHttp()
.request(url,
(error: Error, data: http.HttpResponse) => {
let arrayBuf:ArrayBuffer|null = null;
if (error) {
// SilToast.showToast(this.uiContext,'图片保存失败'),这里不做处理,自行处理
arrayBuf = null;
}else{
// 判断网络获取到的资源是否为ArrayBuffer类型
if (data.result instanceof ArrayBuffer) {
arrayBuf = data.result as ArrayBuffer;
}
}
callback(arrayBuf);
}
)
}
/**
* 保存ArrayBuffer到图库
* @param buffer:图片ArrayBuffer
* @returns
*/
async saveImageToPhoto(buffer: ArrayBuffer | string): Promise<void> {
const helper = photoAccessHelper.getPhotoAccessHelper(this.context); // 获取相册管理模块的实例
const uri = await helper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'jpg'); // 指定待创建的文件类型、后缀和创建选项,创建图片或视频资源
const file = await fs.open(uri, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
let r = await fs.write(file.fd, buffer);
await fs.close(file.fd);
// SilToast.showToast(this.uiContext,"图片保存成功")
}
/**
* 获取已加载的组件的截图(传入组件的组件id标识,找到对应组件进行截图)
* 推荐使用,保存速度不是一般的快
* @param componentId
* @param callback
*/
getComponentSnapshot(componentId:string,callback:(buf:ArrayBuffer|null)=>void){
this.uiContext.getComponentSnapshot().get(componentId, async (error: Error, pixelMap: image.PixelMap) => {
if (error) {
/// 获取失败
callback(null);
console.log("error: " + JSON.stringify(error))
return;
}
let packOpts: image.PackingOption = { format: "image/jpeg", quality: 98 }
const imagePackerApi: image.ImagePacker = image.createImagePacker();
imagePackerApi.packToData(pixelMap, packOpts)
.then((data: ArrayBuffer) => {
callback(data)
console.info('Succeeded in packing the image.');
}).catch((error: BusinessError) => {
callback(null)
console.error(`Failed to pack the image.code ${error.code},message is ${error.message}`);
})
});
}
/**
* 保存ArrayBuffer到图库
* @param buffer:图片ArrayBuffer
* @returns
*/
async saveImageToPhoto(buffer: ArrayBuffer | string): Promise<void> {
const helper = photoAccessHelper.getPhotoAccessHelper(this.context); // 获取相册管理模块的实例
const uri = await helper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'jpg'); // 指定待创建的文件类型、后缀和创建选项,创建图片或视频资源
const file = await fs.open(uri, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
let r = await fs.write(file.fd, buffer);
await fs.close(file.fd);
// SilToast.showToast(this.uiContext,"图片保存成功")
}
使用安全控件实现权限的直接访问为例。
import { PicSaveManager } from '../utils/PicSaveManager';
import { SilToast } from '../utils/SilToastUtils';
// 图片下载管理
private picSaveManager:PicSaveManager = new PicSaveManager(this.getUIContext());
/// 使用安全控件实现权限的直接访问
SaveButton({icon:SaveIconStyle.FULL_FILLED, text: SaveDescription.SAVE_IMAGE, buttonType: ButtonType.ROUNDED_RECTANGLE })
.fontColor(Color.White)
.fontWeight(FontWeight.Medium)
.onClick(async (event: ClickEvent, result: SaveButtonOnClickResult) => {
if (result == SaveButtonOnClickResult.SUCCESS) {
// 方法1:从网络请求下载,然后保存到相册
// this.picSaveManager.getPicArrayBuffer(this.movie.poster_url, async (bufArray)=>{
// if(bufArray == null){
// SilToast.showToast(this.getUIContext(),'图片保存失败')
// }else{
// // 保存图片到相册
// await this.picSaveManager.saveImageToPhoto(bufArray);
// SilToast.showToast(this.getUIContext(),'图片保存成功')
// }
// });
/// 方法2:获取已加载图片的截图,然后保存到相册(保存速度不是一般的快)
this.picSaveManager.getComponentSnapshot('moviePic', async (bufArray)=>{
if(bufArray == null){
SilToast.showToast(this.getUIContext(),'图片保存失败')
}else{
// 保存图片到相册
await this.picSaveManager.saveImageToPhoto(bufArray);
SilToast.showToast(this.getUIContext(),'图片保存成功')
}
})
}
})
import { abilityAccessCtrl, common } from '@kit.AbilityKit';
import { http } from '@kit.NetworkKit';
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import { fileIo as fs } from '@kit.CoreFileKit';
import { UIContext } from '@kit.ArkUI';
import { image } from '@kit.ImageKit';
import { BusinessError } from '@kit.BasicServicesKit';
export class PicSaveManager{
private uiContext:UIContext;
private context:common.UIAbilityContext;
/// 初始化时,获取到context
constructor(uiContext:UIContext) {
this.uiContext = uiContext;
this.context = uiContext.getHostContext() as common.UIAbilityContext;
}
/**
* 获取网络图片的原始二进制数据
* @param url
* @param callback
*/
async getPicArrayBuffer(url:string,callback:(buf:ArrayBuffer|null)=>void) {
http.createHttp()
.request(url,
(error: Error, data: http.HttpResponse) => {
let arrayBuf:ArrayBuffer|null = null;
if (error) {
// SilToast.showToast(this.uiContext,'图片保存失败'),这里不做处理,自行处理
arrayBuf = null;
}else{
// 判断网络获取到的资源是否为ArrayBuffer类型
if (data.result instanceof ArrayBuffer) {
arrayBuf = data.result as ArrayBuffer;
}
}
callback(arrayBuf);
}
)
}
/**
* 获取已加载的组件的截图(传入组件的组件id标识,找到对应组件进行截图)
* 推荐使用,保存速度不是一般的快
* @param componentId
* @param callback
*/
getComponentSnapshot(componentId:string,callback:(buf:ArrayBuffer|null)=>void){
this.uiContext.getComponentSnapshot().get(componentId, async (error: Error, pixelMap: image.PixelMap) => {
if (error) {
/// 获取失败
callback(null);
console.log("error: " + JSON.stringify(error))
return;
}
let packOpts: image.PackingOption = { format: "image/jpeg", quality: 98 }
const imagePackerApi: image.ImagePacker = image.createImagePacker();
imagePackerApi.packToData(pixelMap, packOpts)
.then((data: ArrayBuffer) => {
callback(data)
console.info('Succeeded in packing the image.');
}).catch((error: BusinessError) => {
callback(null)
console.error(`Failed to pack the image.code ${error.code},message is ${error.message}`);
})
});
}
/**
* 保存ArrayBuffer到图库
* @param buffer:图片ArrayBuffer
* @returns
*/
async saveImageToPhoto(buffer: ArrayBuffer | string): Promise<void> {
const helper = photoAccessHelper.getPhotoAccessHelper(this.context); // 获取相册管理模块的实例
const uri = await helper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'jpg'); // 指定待创建的文件类型、后缀和创建选项,创建图片或视频资源
const file = await fs.open(uri, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
let r = await fs.write(file.fd, buffer);
await fs.close(file.fd);
// SilToast.showToast(this.uiContext,"图片保存成功")
}
/**
* 创建申请权限明细(非安全控件使用时使用)
* @returns
*/
async reqPermissionsFromUser(): Promise<number[]> {
let atManager = abilityAccessCtrl.createAtManager();
let grantStatus = await atManager.requestPermissionsFromUser(this.context, ['ohos.permission.WRITE_IMAGEVIDEO']);
return grantStatus.authResults;
}
/**
* 用户申请权限(非安全控件使用时使用)
*/
async requestPermission() {
let grantStatus = await this.reqPermissionsFromUser();
for (let i = 0; i < grantStatus.length; i++) {
if (grantStatus[i] === 0) {
// 用户授权,可以继续访问目标操作
}
}
}
}