写在前面
本文基于项目中的文件,详细说明组件截图及保存到相册的实现逻辑。 适合 HarmonyOS 开发初学者理解如何在 ArkTS 中完成组件截图、图片保存至缓存路径与图片保存至相册的操作。
一、整体流程
- 对特定组件截图
- 将图片压缩并写入到缓存目录
- 将图片保存到本地相册
二、代码实现
typescript
// 模块导入
import { componentSnapshot, promptAction } from "@kit.ArkUI"
import { image } from "@kit.ImageKit"
import { fileIo, fileUri } from "@kit.CoreFileKit"
import { photoAccessHelper } from "@kit.MediaLibraryKit"
async saveImg() {
// 1. 对特定组件截图
const pixelMap = await componentSnapshot.get('share')
// 2. 将图片压缩并写入到缓存目录
const packer = image.createImagePacker()
const arrayBuffer = await packer.packToData(pixelMap, { format: 'image/jpeg', quality: 70 })
const cxt = getContext()
const imgPath = cxt.cacheDir + '/' + Date.now() + '.jpeg'
const imgFile =
fileIo.openSync(imgPath, fileIo.OpenMode.CREATE | fileIo.OpenMode.READ_WRITE)
fileIo.closeSync(imgFile)
// 3. 将图片保存到本地相册
const imgUri = fileUri.getUriFromPath(imgPath)
const request = photoAccessHelper.MediaAssetChangeRequest.createImageAssetRequest(cxt, imgUri)
const helper = photoAccessHelper.getPhotoAccessHelper(cxt)
await helper.applyChanges(request)
promptAction.showToast({ message: '图片已保存到本地' })
}
三、结构说明
1. 对特定组件截图
typescript
import { componentSnapshot } from "@kit.ArkUI"
@Component
struct PreviewComponent {
@State id: string = 'share';
build() {
Column() {
// 需要截图的组件
Image($r('app.media.banner'))
.id(this.id)
Button('保存截图')
.onClick(() => this.saveImg())
}
}
async saveImg() {
// 1. 对特定组件截图
const pixelMap = await componentSnapshot.get('share')
//......
}
}
说明:
- 将需要截图的组件的id填入
componentSnapshot.get
的参数中 - 结果为pixelMap格式的图片数据
2. 将图片压缩并写入到缓存目录
typescript
import { image } from "@kit.ImageKit"
import { fileIo } from "@kit.CoreFileKit"
async saveImg() {
//......
// 2. 将图片压缩并写入到缓存目录
// image.createImagePacker()函数的返回值是ImagePacker对象
const packer = image.createImagePacker()
// 将图片压缩或重新编码,返回的结果为二进制数据流
const arrayBuffer = await packer.packToData(pixelMap, { format: 'image/jpeg', quality: 70 }) // 图片质量(1-100)
// 获取缓存路径
const cxt = getContext()
const imgPath = cxt.cacheDir + '/' + Date.now() + '.jpeg'
// 创建临时文件对象,给fileIo创建和写入权限,写入压缩后的图片数据
const imgFile =
fileIo.openSync(imgPath, fileIo.OpenMode.CREATE | fileIo.OpenMode.READ_WRITE)
// 将图片写入到缓存路径
fileIo.writeSync(imgFile.fd, arrayBuffer)
// 关闭后file对象不再具备实际意义 不可再用于进行读写等操作
fileIo.closeSync(imgFile)
//......
}
说明:
- 使用
ImagePacker
对pixelMap格式数据进行压缩并打包 - 使用
fileIo
模块将图片写入到缓存目录 - 操作完后注意关闭file对象
3. 将图片保存到本地相册
typescript
import { promptAction } from "@kit.ArkUI"
import { fileUri } from "@kit.CoreFileKit"
import { photoAccessHelper } from "@kit.MediaLibraryKit"
async saveImg() {
//......
// 3. 将图片保存到本地相册
// 获取图片的完整路径( getContext获取的是部分路径 )
const imgUri = fileUri.getUriFromPath(imgPath)
// 创建一个 向相册发送修改数据 的请求
const request = photoAccessHelper.MediaAssetChangeRequest.createImageAssetRequest(cxt, imgUri)
// 获取照片访问助手实例,用于接收请求
const helper = photoAccessHelper.getPhotoAccessHelper(cxt)
// 调用助手实例上的方法, 将图片保存到本地 ( 需要相册的相关权限 )
await helper.applyChanges(request)
promptAction.showToast({ message: '图片已保存到本地' })
}
说明:
- 使用
fileUri
获取图片的完整路径 - 通过
photoAccessHelper
模块得到修改请求和图片访问助手 - 将图片保存到本地 ( 需要相册的相关权限 )
四、相关模块说明
模块 | 功能 |
---|---|
componentSnapshot | 对已渲染的组件进行截图 |
promptAction | 创建并显示文本提示框 |
image | 提供图片的解码和编码能力 |
fileIo | 提供文件存储管理能力 |
fileUri | 通过PATH获取文件统一资源标志符 |
photoAccessHelper | 提供相册管理能力 |
五、补充
如果没有向用户申请相册的相关权限,我们也可以用华为内置的安全控件完成保存功能,此时用户通过点击该保存按钮,可以临时获取存储权限,而不需要权限弹框授权确认。
typescript
//
SaveButton({
text: SaveDescription.SAVE_IMAGE,
buttonType: ButtonType.Normal,
icon: SaveIconStyle.FULL_FILLED
})
.onClick((event, result) => {
if (result == SaveButtonOnClickResult.SUCCESS) {
this.saveImg()
// 自己关自己
this.controller.close()
}
})
为了保障用户的隐私不被恶意应用获取,华为针对安全控件作了很多的限制,比如其对象参数内属性的值都是枚举,开发者并不能对其样式做过多更改。
六、总结
本文提供了一个获取组件截图并保存到相册的主要流程,并提供了一个临时获取相册存储权限的方式,希望能帮助开发者快速掌握保存图片的核心代码实现。