欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 教育 > 高考 > HarmonyOS(50) 截图保存功能实现

HarmonyOS(50) 截图保存功能实现

2024/10/24 20:18:31 来源:https://blog.csdn.net/chunqiuwei/article/details/141154586  浏览:    关键词:HarmonyOS(50) 截图保存功能实现

componentSnapshot实现截图

  • 前言
  • 权限配置和申请
    • 权限配置
    • 权限申请
  • componentSnapshot截图实现
  • 将PixelMap转换成图片格式
  • 保存截图到系统相册
  • 保存截图到应用沙箱
  • 全部源码
  • 参考资料

前言

HarmonyOS提供了componentSnapshot实现组件截图功能,可以将UI截图成为image.PixelMap,然后可以将PixlMap保存到本地,运行效果如下图:
在这里插入图片描述
通过这篇博文你可以了解到:

  • HarmonyOS的权限申请方法
  • 截图功能的具体实现实现方法
  • 截图PixelMap转换成图片格式的方法
  • 异步和并发的简单使用
  • 将截图保存到系统相册的实现方法
  • 将截图保存到应用沙箱的实现方法

权限配置和申请

截图保存的功能,截图需要使用componentSnapshot,保存到系统相册需要在module.json5配置权限限“ohos.permission.WRITE_IMAGEVIDEO”

权限配置

在这里插入图片描述

    "requestPermissions": [{"name": "ohos.permission.WRITE_IMAGEVIDEO","reason": "$string:reason","usedScene": {"abilities": ["EntryAbility"],"when": "inuse"}}]

配置权限有个when属性,其有两个值:inuse(使用时)、always(始终),其他相关参数详见官方文档
在这里插入图片描述

权限申请

const permissions: Array<Permissions> = ['ohos.permission.WRITE_IMAGEVIDEO'];
function reqPermissionsFromUser(permissions: Array<Permissions>, context: common.UIAbilityContext): void {let atManager: abilityAccessCtrl.AtManager =abilityAccessCtrl.createAtManager();// requestPermissionsFromUser会判断权限的授权状态来决定是否唤起弹窗atManager.requestPermissionsFromUser(context, permissions).then((data) => {let grantStatus: Array<number> = data.authResults;let length: number = grantStatus.length;for (let i = 0; i < length; i++) {if (grantStatus[i] === 0) {// 用户授权,可以继续访问目标操作} else {// 用户拒绝授权,提示用户必须授权才能访问当前页面的功能,并引导用户到系统设置中打开相应的权限return;}}// 授权成功}).catch((err: BusinessError) => {console.error(`Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`);})
}

上述方法可以在两处地方调用:在UIAbility和在UI中向用户申请授权。

  • 在UIAbility申请权限,在 windowStage.loadContent完成后申请
// 使用UIExtensionAbility:将 UIAbility 替换为UIExtensionAbility
export default class EntryAbility extends UIAbility {onWindowStageCreate(windowStage: window.WindowStage): void {// ...windowStage.loadContent('pages/Index', (err, data) => {reqPermissionsFromUser(permissions, this.context);// ...});}// ...
}
  • 在UI中申请权限,可以在aboutToApper方法中申请


struct Index {aboutToAppear() {// 使用UIExtensionAbility:将common.UIAbilityContext 替换为common.UIExtensionContextconst context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;reqPermissionsFromUser(permissions, context);}build() {// ...}
}

向用户申请权限的更多细节,参考官方文档

componentSnapshot截图实现

该组件使用起来很简单,比如给组件设置一个id,将id传给componentSnapshot.get即可实现,代码如下,实现效果见文章开头gif图片。
在这里插入图片描述
详细的截图功能,参考官方文档。

将PixelMap转换成图片格式

将PixelMap转成图片格式,因为是耗时任务,所以使用异步操作,使用Promise保存返回值,Promise是一种用于处理异步操作的对象,可以将异步操作转换为类似于同步操作的风格,以方便代码编写和维护。Promise提供了一个状态机制来管理异步操作的不同阶段,并提供了一些方法来注册回调函数以处理异步操作的成功或失败的结果,详见异步并发概述 (Promise和async/await)。

  // 将pixelMap转成图片格式transferPixelMap2Buffer(pixelMap: image.PixelMap): Promise<ArrayBuffer> {return new Promise((resolve, reject) => {/*** 设置打包参数* format:图片打包格式,只支持 jpg 和 webp* quality:JPEG 编码输出图片质量 0-100* bufferSize:图片大小,默认 10M*/let packOpts: image.PackingOption = { format: 'image/jpeg', quality: 98 };// 创建ImagePacker实例const imagePackerApi = image.createImagePacker();imagePackerApi.packing(pixelMap, packOpts).then((buffer: ArrayBuffer) => {resolve(buffer);}).catch((err: BusinessError) => {reject();})})}

保存截图到系统相册

注意使用async修饰,设置为异步执行。async/await是一种用于处理异步操作的Promise语法糖,通过使用async关键字声明一个函数为异步函数,并使用await关键字等待Promise的解析(完成或拒绝),以同步的方式编写异步操作的代码。async函数是一个返回Promise对象的函数,用于表示一个异步操作。在async函数内部,可以使用await关键字等待一个Promise对象的解析,并返回其解析值,注意下面代码最后一行 fileIo.close(file.fd)返回的是Promise<void>

  // 保存到系统相册async savePixmap2SysHelper() {if (!this.pixmap) {return;}const imgBuffer = await this.transferPixelMap2Buffer(this.pixmap);// 获取相册管理模块的实例,用于访问和修改相册中的媒体文件。let helper = photoAccessHelper.getPhotoAccessHelper(getContext(this));// 指定待创建的文件类型和后缀,创建图片或视频资源,使用callback方式返回结果。const uri = await helper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'png');const file = await fileIo.open(uri, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);await fileIo.write(file.fd, imgBuffer);//注意declare function close(file: number | File): Promise<void>await fileIo.close(file.fd);}

保存截图到应用沙箱

应用沙箱是一种以安全防护为目的的隔离机制,避免数据受到恶意路径穿越访问。在这种沙箱的保护机制下,应用可见的目录范围即为“应用沙箱目录”,详见官方文档

在这里插入图片描述

   context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;//获取文件目录 filesDir: string = this.context.filesDir;// 将pixelMap转成图片格式transferPixelMap2Buffer(pixelMap: image.PixelMap): Promise<ArrayBuffer> {return new Promise((resolve, reject) => {/*** 设置打包参数* format:图片打包格式,只支持 jpg 和 webp* quality:JPEG 编码输出图片质量* bufferSize:图片大小,默认 10M*/let packOpts: image.PackingOption = { format: 'image/jpeg', quality: 98 };// 创建ImagePacker实例const imagePackerApi = image.createImagePacker();imagePackerApi.packing(pixelMap, packOpts).then((buffer: ArrayBuffer) => {resolve(buffer);}).catch((err: BusinessError) => {reject();})})}

全部源码

import { componentSnapshot } from '@kit.ArkUI';
import { image } from '@kit.ImageKit';
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { abilityAccessCtrl, common, Permissions } from '@kit.AbilityKit';
import { intl } from '@kit.LocalizationKit';
import { fileIo } from '@kit.CoreFileKit';
const permissions: Array<Permissions> = ['ohos.permission.WRITE_IMAGEVIDEO'];
function reqPermissionsFromUser(permissions: Array<Permissions>, context: common.UIAbilityContext): void {let atManager: abilityAccessCtrl.AtManager =abilityAccessCtrl.createAtManager();// requestPermissionsFromUser会判断权限的授权状态来决定是否唤起弹窗atManager.requestPermissionsFromUser(context, permissions).then((data) => {let grantStatus: Array<number> = data.authResults;let length: number = grantStatus.length;for (let i = 0; i < length; i++) {if (grantStatus[i] === 0) {// 用户授权,可以继续访问目标操作} else {// 用户拒绝授权,提示用户必须授权才能访问当前页面的功能,并引导用户到系统设置中打开相应的权限return;}}// 授权成功}).catch((err: BusinessError) => {console.error(`Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`);})
}


export struct ComponentScreenshot { message: string = 'Hello World'; timerSecond: number = 20; pixmap: image.PixelMap | null = null; isAutoPlay: boolean = true; showControls: boolean = false; curRate: number = 1; context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext; filesDir: string = this.context.filesDir;// controller: VideoController = new VideoController();aboutToAppear(): void {reqPermissionsFromUser(permissions, this.context);}// 组件截图clickToComponentSnapshot() {componentSnapshot.get('root', (error: Error, pixmap: image.PixelMap) => {if (error) {console.log('error: ' + JSON.stringify(error));return;}console.log('截图成功');this.pixmap = pixmap;})}// 保存到系统相册async savePixmap2SysHelper() {if (!this.pixmap) {return;}const imgBuffer = await this.transferPixelMap2Buffer(this.pixmap);// 获取相册管理模块的实例,用于访问和修改相册中的媒体文件。let helper = photoAccessHelper.getPhotoAccessHelper(getContext(this));// 指定待创建的文件类型和后缀,创建图片或视频资源,使用callback方式返回结果。const uri = await helper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'png');const file = await fileIo.open(uri, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);await fileIo.write(file.fd, imgBuffer);await fileIo.close(file.fd);}// 保存到应用沙箱async savePixmap2SystemFileManager() {if (!this.pixmap) {return;}const imgBuffer = await this.transferPixelMap2Buffer(this.pixmap);console.log("fileDir=="+this.filesDir);const file = fileIo.openSync(this.filesDir + `/${DateUtil.getTimeStamp()}.png`,fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);await fileIo.write(file.fd, imgBuffer);await fileIo.close(file.fd);}// 将pixelMap转成图片格式transferPixelMap2Buffer(pixelMap: image.PixelMap): Promise<ArrayBuffer> {return new Promise((resolve, reject) => {/*** 设置打包参数* format:图片打包格式,只支持 jpg 和 webp* quality:JPEG 编码输出图片质量* bufferSize:图片大小,默认 10M*/let packOpts: image.PackingOption = { format: 'image/jpeg', quality: 98 };// 创建ImagePacker实例const imagePackerApi = image.createImagePacker();imagePackerApi.packing(pixelMap, packOpts).then((buffer: ArrayBuffer) => {resolve(buffer);}).catch((err: BusinessError) => {reject();})})}build() {Column() {Row().height(40).padding(5).position({ x: 0, y: 0 }).width('100%').zIndex(1).justifyContent(FlexAlign.End).expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])Text(this.message).fontColor(Color.White).fontSize(20).margin(50)Button('点击进行组件截图').fontSize(20).margin(10).width('80%').position({x: 20,y: 500}).onClick(() => {this.clickToComponentSnapshot();})if (this.pixmap) {Button('保存到系统相册').fontSize(20).margin(10).width('80%').position({x: 20,y: 550}).onClick(() => {this.savePixmap2SysHelper();})Button('保存到应用沙箱').fontSize(20).margin(10).width('80%').position({x: 20,y: 600}).onClick(() => {this.savePixmap2SystemFileManager();})}}.id('root').height('100%').width('100%').backgroundColor('#b5b5b5').expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])}
}
class DateUtil {static getFormatTimeStr(timestamp: number) {const date = new Date(timestamp);let dateFormat3 = new intl.DateTimeFormat('zh-CN', {year: 'numeric',month: '2-digit',day: '2-digit',hour: '2-digit',minute: '2-digit',second: '2-digit'});let formattedDate3 = dateFormat3.format(date);return formattedDate3;}/* 获取当前时间戳 */static getTimeStamp(): number {const timeStamp = (new Date()).getTime();return timeStamp;}
}

参考资料

@ohos.screenshot (屏幕截图)
组件截图怎么将pixelMap存储到系统相册或应用沙箱
@ohos.arkui.componentSnapshot (组件截图)
权限配置相关字段说明
向用户申请授权
异步并发概述 (Promise和async/await)。
应用沙箱

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com