马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
注:实用版本(HarmonyOS NEXT/5.0/API13+)
鸿蒙系统实现图片生存至相册全流程详解
一、技术实现流程概述
本业务需完成从组件截图到恒久化存储的完整链路,主要分为四大阶段:
- 组件截图天生
- 图片数据转换存储
- 沙箱文件转公有文件
- 媒体库写入与权限管理
二、核心实现步骤
步骤1:获取组件截图对象
步骤2:JPEG格式转换与缓存写入
选择JPEG格式的考量(代码有标注):
- 接纳有损压缩均衡画质与体积
- 官方推荐设置98%质量参数(0-100范围)
- 克制PNG的无损压缩导致体积过大
- /**
- * 保存图片到沙箱, 再从沙箱中读取写入相册
- */
- async saveImage(){
- // 1. 根据组件的id生成截图对象
- const pixelMap = await componentSnapshot.get('share')
- // 2. 借助ImagePacker去把图片对象生成二级制数据流
- const imagePacker = image.createImagePacker()
- const arrayBuffer = await imagePacker.packToData(pixelMap,{ format: "image/jpeg", quality: 98 })
- // 3. 借助fileIo读写文件
- // 3.1 获取上下文
- const ctx = getContext(this)
- // 3.2 获取沙箱中存图的路径
- const imagePath = ctx.cacheDir + '/' + Date.now() + 'jpeg'
- // 3.3 以 创建 或 读写 的模式打开文件(没有则创建并打开, 有则打开)
- const file = fileIo.openSync(imagePath,fileIo.OpenMode.CREATE | fileIo.OpenMode.READ_WRITE)
- // 3.4 同步写入二级制数据流到文件中
- fileIo.writeSync(file.fd,arrayBuffer)
- // 3.5 同步去关闭文件
- fileIo.closeSync(file.fd)
- promptAction.showToast({message: '写入成功'})
- }
复制代码 步骤3:沙箱文件转存相册
这个时候是没用权限的 必要使用 SaveButton组件 来授权 组件时间一般有30分钟左右 授权一次三十分钟之内不用授权
- // 3.2 获取沙箱中存图的路径
- const imagePath = ctx.cacheDir + '/' + Date.now() + 'jpeg'
- // 3.3 以 创建 或 读写 的模式打开文件(没有则创建并打开, 有则打开)
- const file = fileIo.openSync(imagePath,fileIo.OpenMode.CREATE | fileIo.OpenMode.READ_WRITE)
- // 3.4 同步写入二级制数据流到文件中
- fileIo.writeSync(file.fd,arrayBuffer)
- // 3.5 同步去关闭文件
- fileIo.closeSync(file.fd)
- // 4. 把沙箱中的文件写入相册
- // 4.1 获取资源文件的uri地址 3.2 获取存在沙箱的 路径
- const imgUrl = fileUri.getUriFromPath(imagePath)
- // 4.2 进行图片资产变更(私有->公有) 要私有变公有 要先获取 再变更,变更看文档 复制 后传参数 上下文和url的地址
- const assetChangeRequest = photoAccessHelper.MediaAssetChangeRequest.createImageAssetRequest(ctx,imgUrl)
- // 4.3 提交媒体变更请求
- // 4.3.1 获取相册管理模块的实例
- const phAccessHelper = photoAccessHelper.getPhotoAccessHelper(ctx)
- // 4.3.2 调用变更方法
- await phAccessHelper.applyChanges(assetChangeRequest)
- promptAction.showToast({message: '图片写入成功'})
复制代码 步骤4:权限动态申请与安全组件
- SaveButton({
- icon: SaveIconStyle.FULL_FILLED,//保存按钮展示填充样式图标。
- text: SaveDescription.SAVE_IMAGE,//保存按钮的文字描述为“保存图片”。
- buttonType: ButtonType.Normal //普通按钮(默认不带圆角)。
- })
- ...
- //参数可复制文档实例
- .onClick((event:ClickEvent, result:SaveButtonOnClickResult)=>{
- //恒等于0
- if(result == SaveButtonOnClickResult.SUCCESS){
- this.saveImage()
- }
- })
复制代码 三、关键注意事项
- 路径有效性:沙箱路径必要使用context获取标准目录
- 内存管理:及时释放PixelMap资源克制内存走漏
- 异常处理:文件IO操作需包裹try-catch块
- 权限时效:WRITE_IMAGEVIDEO权限默认有效期30分钟
- 格式兼容性:确保设备支持JPEG编码格式
四、性能优化建议
- 大图处理建议分块写入
- 频仍操作建议使用Worker线程
- 可添加进度提示提拔用户体验
- 建议对重复生存操作做防抖处理
通过以上标准化实现流程,我们可高效完成鸿蒙系统的图片存储业务开发,同时包管应用的稳固性和用户体验。现实开发中需根据详细业务场景调整质量参数和异常处理策略。
总结:
要完成鸿蒙中生存图片业务可以分为以下步骤进行实现:
首先我们要用componentSnapshot组件的get方法获取id天生截图对象
然后借助ImagePacker把图片转化为JPEG二进制数据流(问为什么是JPEG格式1:均衡画质和体积2:官方文档设置98%质量参数克制过度压缩,包管图片清晰度)
这个时候图片数据已经写入编译器的缓存目录了,我们接着必要获取沙箱中存放图片的路径这时还必要借助fileIo文件管理组件 创建或读写的方式打开文件之后同步写入二进制数据中
将图片存储到沙箱之后 这个时候图片是私有的 我们必要把私有变为共有然后获取相册管理权限 终极就可以实现了
接下来把沙箱中的文件写入相册中(先获取上文中写好的url地点,用fileUri.getUriFromPath()获取),用photoAccessHelper.MediaAssetChangeRequest.createImageAssetRequest('上下文','url地点')变私为公
公有完毕之后就可以提交媒体变动请求 接纳applyChanges方法(必要再model.json5中配置权限:permission: ohos.permission.WRITE_IMAGEVIDEO)
这里共同使用SaveButton安全组件获取短时期权限,唤起系统的相册授权(一般是30分钟内不用重复授权)
终极写入相册就完成了此业务
- import { UserStoreKey } from '../../commons/utils/Auth'
- import { QuestionDetail, User } from '../../models'
- import { componentSnapshot, promptAction } from '@kit.ArkUI'
- import image from '@ohos.multimedia.image'
- import { fileIo, fileUri } from '@kit.CoreFileKit'
- import { photoAccessHelper } from '@kit.MediaLibraryKit'
- @CustomDialog
- export struct QuestionShareDialog {
- @Prop item: QuestionDetail
- @StorageProp(UserStoreKey) user: User = {} as User
- /**
- * 保存图片到沙箱, 再从沙箱中读取写入相册
- */
- async saveImage(){
- // 1. 根据组件的id生成截图对象
- const pixelMap = await componentSnapshot.get('share')
- // 2. 借助ImagePacker去把图片对象生成二级制数据流
- const imagePacker = image.createImagePacker()
- const arrayBuffer = await imagePacker.packToData(pixelMap,{ format: "image/jpeg", quality: 98 })
- // 3. 借助fileIo读写文件
- // 3.1 获取上下文
- const ctx = getContext(this)
- // 3.2 获取沙箱中存图的路径
- const imagePath = ctx.cacheDir + '/' + Date.now() + '.jpeg'
- // 3.3 以 创建 或 读写 的模式打开文件(没有则创建并打开, 有则打开)
- const file = fileIo.openSync(imagePath,fileIo.OpenMode.CREATE | fileIo.OpenMode.READ_WRITE)
- // 3.4 同步写入二级制数据流到文件中
- fileIo.writeSync(file.fd,arrayBuffer)
- // 3.5 同步去关闭文件
- fileIo.closeSync(file.fd)
- // 4. 把沙箱中的文件写入相册
- // 4.1 获取资源文件的uri地址 3.2 获取存在沙箱的 路径
- const imgUrl = fileUri.getUriFromPath(imagePath)
- // 4.2 进行图片资产变更(私有->公有) 要私有变公有 要先获取 再变更,变更看文档 复制 后传参数 上下文和url的地址
- const assetChangeRequest = photoAccessHelper.MediaAssetChangeRequest.createImageAssetRequest(ctx, imgUrl);
- // 4.3 提交媒体变更请求
- // 4.3.1 获取相册管理模块的实例
- const phAccessHelper = photoAccessHelper.getPhotoAccessHelper(ctx)
- // 4.3.2 调用变更方法
- // 需要配置权限: permission: ohos.permission.WRITE_IMAGEVIDEO
- await phAccessHelper.applyChanges(assetChangeRequest);
- // 5. 关闭弹窗
- this.controller.close()
- promptAction.showToast({message: '图片写入相册成功'})
- }
- controller: CustomDialogController
- build() {
- Stack({ alignContent: Alignment.BottomEnd }) {
- Column({ space: 20 }) {
- Image($r('app.media.ic_interview_logo'))
- .width(40)
- .height(40)
- Text('面试通,搞定企业面试题')
- Divider()
- .strokeWidth(0.5)
- .color($r('app.color.common_gray_border'))
- Text('大厂面试题:' + this.item.stem)
- .fontSize(12)
- .maxLines(2)
- .fontWeight(600)
- .width('100%')
- .lineHeight(24)
- .textOverflow({ overflow: TextOverflow.Ellipsis })
- QRCode(this.item.id)
- .width(160)
- .height(160)
- .alignSelf(ItemAlign.Center)
- Text('扫码查看答案')
- .fontSize(12)
- .alignSelf(ItemAlign.Center)
- Blank()
- Text('分享来自:' + this.user.nickName || this.user.username)
- .fontSize(12)
- }
- .id('share') // 用于后续截图使用
- .padding(20)
- .alignItems(HorizontalAlign.Start)
- .width(300)
- .height(500)
- .backgroundColor($r('app.color.white'))
- Row() {
- SaveButton({
- icon: SaveIconStyle.FULL_FILLED,//保存按钮展示填充样式图标。
- text: SaveDescription.SAVE_IMAGE,//保存按钮的文字描述为“保存图片”。
- buttonType: ButtonType.Normal //普通按钮(默认不带圆角)。
- })
- .fontColor($r('app.color.white'))
- .fontSize(14)
- .padding(12)
- .backgroundColor($r('app.color.common_main_color'))
- .onClick((event:ClickEvent, result:SaveButtonOnClickResult)=>{
- if(result == SaveButtonOnClickResult.SUCCESS){
- this.saveImage()
- }
- })
- }
- .borderRadius({ topLeft: 8 })
- .clip(true)
- }
- .borderRadius(8)
- .clip(true)
- }
- }
复制代码 以上代码只是单个文件夹的流程图,如需总代码可留下关注私信我~
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |