鸿蒙中如何生存图片

打印 上一主题 下一主题

主题 1788|帖子 1788|积分 5364

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
 注:实用版本(HarmonyOS NEXT/5.0/API13+)
  鸿蒙系统实现图片生存至相册全流程详解

一、技术实现流程概述

本业务需完成从组件截图到恒久化存储的完整链路,主要分为四大阶段:

  • 组件截图天生
  • 图片数据转换存储
  • 沙箱文件转公有文件
  • 媒体库写入与权限管理
二、核心实现步骤

步骤1:获取组件截图对象

步骤2:JPEG格式转换与缓存写入

选择JPEG格式的考量(代码有标注)


  • 接纳有损压缩均衡画质与体积
  • 官方推荐设置98%质量参数(0-100范围)
  • 克制PNG的无损压缩导致体积过大
  1. /**
  2.    * 保存图片到沙箱, 再从沙箱中读取写入相册
  3.    */
  4.   async saveImage(){
  5.     // 1. 根据组件的id生成截图对象
  6.     const pixelMap = await componentSnapshot.get('share')
  7.     // 2. 借助ImagePacker去把图片对象生成二级制数据流
  8.     const imagePacker = image.createImagePacker()
  9.     const arrayBuffer = await imagePacker.packToData(pixelMap,{ format: "image/jpeg", quality: 98 })
  10.     // 3. 借助fileIo读写文件
  11.     // 3.1 获取上下文
  12.     const  ctx = getContext(this)
  13.     // 3.2 获取沙箱中存图的路径
  14.     const imagePath = ctx.cacheDir + '/' + Date.now() + 'jpeg'
  15.     // 3.3 以 创建 或 读写 的模式打开文件(没有则创建并打开, 有则打开)
  16.     const file = fileIo.openSync(imagePath,fileIo.OpenMode.CREATE | fileIo.OpenMode.READ_WRITE)
  17.     // 3.4 同步写入二级制数据流到文件中
  18.     fileIo.writeSync(file.fd,arrayBuffer)
  19.     // 3.5 同步去关闭文件
  20.     fileIo.closeSync(file.fd)
  21.     promptAction.showToast({message: '写入成功'})
  22.   }
复制代码
步骤3:沙箱文件转存相册

这个时候是没用权限的 必要使用 SaveButton组件 来授权 组件时间一般有30分钟左右 授权一次三十分钟之内不用授权
  1. // 3.2 获取沙箱中存图的路径
  2.     const imagePath = ctx.cacheDir + '/' + Date.now() + 'jpeg'
  3.     // 3.3 以 创建 或 读写 的模式打开文件(没有则创建并打开, 有则打开)
  4.     const file = fileIo.openSync(imagePath,fileIo.OpenMode.CREATE | fileIo.OpenMode.READ_WRITE)
  5.     // 3.4 同步写入二级制数据流到文件中
  6.     fileIo.writeSync(file.fd,arrayBuffer)
  7.     // 3.5 同步去关闭文件
  8.     fileIo.closeSync(file.fd)
  9.     // 4. 把沙箱中的文件写入相册
  10.     // 4.1 获取资源文件的uri地址  3.2 获取存在沙箱的 路径
  11.     const imgUrl = fileUri.getUriFromPath(imagePath)
  12.     // 4.2 进行图片资产变更(私有->公有)  要私有变公有 要先获取 再变更,变更看文档 复制 后传参数 上下文和url的地址
  13.     const assetChangeRequest = photoAccessHelper.MediaAssetChangeRequest.createImageAssetRequest(ctx,imgUrl)
  14.     // 4.3 提交媒体变更请求
  15.     // 4.3.1 获取相册管理模块的实例
  16.     const phAccessHelper = photoAccessHelper.getPhotoAccessHelper(ctx)
  17.     // 4.3.2 调用变更方法
  18.     await phAccessHelper.applyChanges(assetChangeRequest)
  19.     promptAction.showToast({message: '图片写入成功'})
复制代码
步骤4:权限动态申请与安全组件

  1. SaveButton({
  2.           icon: SaveIconStyle.FULL_FILLED,//保存按钮展示填充样式图标。
  3.           text: SaveDescription.SAVE_IMAGE,//保存按钮的文字描述为“保存图片”。
  4.           buttonType: ButtonType.Normal //普通按钮(默认不带圆角)。
  5.         })
  6. ...
  7.           //参数可复制文档实例
  8.   .onClick((event:ClickEvent, result:SaveButtonOnClickResult)=>{
  9.                //恒等于0
  10.             if(result == SaveButtonOnClickResult.SUCCESS){
  11.               this.saveImage()
  12.             }
  13.           })
复制代码
三、关键注意事项


  • 路径有效性:沙箱路径必要使用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分钟内不用重复授权)
终极写入相册就完成了此业务

  1. import { UserStoreKey } from '../../commons/utils/Auth'
  2. import { QuestionDetail, User } from '../../models'
  3. import { componentSnapshot, promptAction } from '@kit.ArkUI'
  4. import image from '@ohos.multimedia.image'
  5. import { fileIo, fileUri } from '@kit.CoreFileKit'
  6. import { photoAccessHelper } from '@kit.MediaLibraryKit'
  7. @CustomDialog
  8. export struct QuestionShareDialog {
  9.   @Prop item: QuestionDetail
  10.   @StorageProp(UserStoreKey) user: User = {} as User
  11.   /**
  12.    * 保存图片到沙箱, 再从沙箱中读取写入相册
  13.    */
  14.   async saveImage(){
  15.     // 1. 根据组件的id生成截图对象
  16.     const pixelMap = await componentSnapshot.get('share')
  17.     // 2. 借助ImagePacker去把图片对象生成二级制数据流
  18.     const imagePacker = image.createImagePacker()
  19.     const arrayBuffer = await imagePacker.packToData(pixelMap,{ format: "image/jpeg", quality: 98 })
  20.     // 3. 借助fileIo读写文件
  21.     // 3.1 获取上下文
  22.     const  ctx = getContext(this)
  23.     // 3.2 获取沙箱中存图的路径
  24.     const imagePath = ctx.cacheDir + '/' + Date.now() + '.jpeg'
  25.     // 3.3 以 创建 或 读写 的模式打开文件(没有则创建并打开, 有则打开)
  26.     const file = fileIo.openSync(imagePath,fileIo.OpenMode.CREATE | fileIo.OpenMode.READ_WRITE)
  27.     // 3.4 同步写入二级制数据流到文件中
  28.     fileIo.writeSync(file.fd,arrayBuffer)
  29.     // 3.5 同步去关闭文件
  30.     fileIo.closeSync(file.fd)
  31.     // 4. 把沙箱中的文件写入相册
  32.     // 4.1 获取资源文件的uri地址  3.2 获取存在沙箱的 路径
  33.     const imgUrl = fileUri.getUriFromPath(imagePath)
  34.     // 4.2 进行图片资产变更(私有->公有)  要私有变公有 要先获取 再变更,变更看文档 复制 后传参数 上下文和url的地址
  35.     const assetChangeRequest = photoAccessHelper.MediaAssetChangeRequest.createImageAssetRequest(ctx, imgUrl);
  36.     // 4.3 提交媒体变更请求
  37.     // 4.3.1 获取相册管理模块的实例
  38.     const phAccessHelper = photoAccessHelper.getPhotoAccessHelper(ctx)
  39.     // 4.3.2 调用变更方法
  40.     // 需要配置权限: permission: ohos.permission.WRITE_IMAGEVIDEO
  41.     await phAccessHelper.applyChanges(assetChangeRequest);
  42.     // 5. 关闭弹窗
  43.     this.controller.close()
  44.     promptAction.showToast({message: '图片写入相册成功'})
  45.   }
  46.   controller: CustomDialogController
  47.   build() {
  48.     Stack({ alignContent: Alignment.BottomEnd }) {
  49.       Column({ space: 20 }) {
  50.         Image($r('app.media.ic_interview_logo'))
  51.           .width(40)
  52.           .height(40)
  53.         Text('面试通,搞定企业面试题')
  54.         Divider()
  55.           .strokeWidth(0.5)
  56.           .color($r('app.color.common_gray_border'))
  57.         Text('大厂面试题:' + this.item.stem)
  58.           .fontSize(12)
  59.           .maxLines(2)
  60.           .fontWeight(600)
  61.           .width('100%')
  62.           .lineHeight(24)
  63.           .textOverflow({ overflow: TextOverflow.Ellipsis })
  64.         QRCode(this.item.id)
  65.           .width(160)
  66.           .height(160)
  67.           .alignSelf(ItemAlign.Center)
  68.         Text('扫码查看答案')
  69.           .fontSize(12)
  70.           .alignSelf(ItemAlign.Center)
  71.         Blank()
  72.         Text('分享来自:' + this.user.nickName || this.user.username)
  73.           .fontSize(12)
  74.       }
  75.       .id('share')  // 用于后续截图使用
  76.       .padding(20)
  77.       .alignItems(HorizontalAlign.Start)
  78.       .width(300)
  79.       .height(500)
  80.       .backgroundColor($r('app.color.white'))
  81.       Row() {
  82.         SaveButton({
  83.           icon: SaveIconStyle.FULL_FILLED,//保存按钮展示填充样式图标。
  84.           text: SaveDescription.SAVE_IMAGE,//保存按钮的文字描述为“保存图片”。
  85.           buttonType: ButtonType.Normal //普通按钮(默认不带圆角)。
  86.         })
  87.           .fontColor($r('app.color.white'))
  88.           .fontSize(14)
  89.           .padding(12)
  90.           .backgroundColor($r('app.color.common_main_color'))
  91.           .onClick((event:ClickEvent, result:SaveButtonOnClickResult)=>{
  92.             if(result == SaveButtonOnClickResult.SUCCESS){
  93.               this.saveImage()
  94.             }
  95.           })
  96.       }
  97.       .borderRadius({ topLeft: 8 })
  98.       .clip(true)
  99.     }
  100.     .borderRadius(8)
  101.     .clip(true)
  102.   }
  103. }
复制代码
以上代码只是单个文件夹的流程图,如需总代码可留下关注私信我~

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

莫张周刘王

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表