前言

在移动端领域,图片压缩基本是绕不过去的需求,尤其是微信分享对图片有大小限制。而高频使用图片压缩的原因无非以下几点原因:

1:性能优化,大尺寸图片导致内存占用飙升,易引发应用卡顿、闪退(尤其低端机型),压缩可降低渲染压力。

2:流量敏感,未压缩图片消耗用户超额流量,移动网络下加载缓慢,影响弱网用户体验。

3:存储限制,本地缓存大图快速占满手机存储空间,导致用户主动清理或卸载应用。

4:成本控制,服务器带宽和云存储费用与图片体积正相关,压缩可降低企业运营成本。

5:平台规则适配,社交媒体/文件上传接口普遍存在图片尺寸限制(如微信头像),压缩可规避上传失败。

6:响应速度提升,压缩后图片传输耗时减少50%以上,显著缩短用户等待时间。

7:视觉平衡需求,移动端屏幕物理尺寸有限,超高分辨率图片难以被肉眼感知,压缩可剔除冗余像素数据。

本质矛盾:移动端资源有限性(硬件/网络/存储)与高质量图片需求之间的冲突,压缩是技术妥协的最优解

而图片压缩又分2种

1:质量压缩(不改变图片分辨率的情况下压缩图片文件大小)
2:分辨率压缩(改变图片分辨率,分辨率压缩时也会改变文件大小)

简单使用示例(支持文件大小和图片分辨率大小压缩)

public compress(context:Context){
  // 此处换成实际的图片uri
  const imageData = 'file://com.example.xxx/xxx.jpg'
  // 支持fd、uri、沙箱路径、图片url、base64图片、ArrayBuffer数据
  HMImage.compress(context)
  .start([imageData])
  .then((result: CompressResult) => {
    // 本次压缩是否全部成功
    const isAllSuccess = result.isAllSuccess
    // 本次压缩成功的数据
    const successData = result.successData
    // 本次压缩失败的数据
    const failData = result.failData
  }).catch((error: BusinessError) => {
  
  })
}

图片压缩实现方法介绍

1:质量压缩

const imagePacker: image.ImagePacker = image.createImagePacker()
// format:图片压缩后的目标格式
// quality:输出图片质量的参数,该参数仅对JPEG图片和HEIF图片生效。取值范围为0-100。
// 0质量最低,100质量最高,质量越高生成图片所占空间越大。WebP、PNG等图片均为无损编码
const packOpts: image.PackingOption = { format: 'image/webp', quality: 70 }
const imagePath = 'xxxx' //实际的图片沙箱路径
const imageSource = image.createImageSource(imagePath)
const result:ArrayBuffer = await imagePacker.packToData(imageSource, packOpts)
// 最后将压缩得到的ArrayBuffer类型的数据保存至本地,然后就完成了图片质量压缩
// 是不是很简单?其实就是官网提供的api,只负责调用就实现了

2:分辨率压缩

// 分辨率压缩的目标大小,比如500x500的图片,压缩成100X100的图片
let options: image.DecodingOptions = {
  desiredSize: {
    width: 100,
    height: 100
  }
}
const imagePath = 'xxxx' //实际的图片沙箱路径
const imageSource = image.createImageSource(imagePath)
// 这里进行分辨率压缩返回一个图像像素类PixelMap,
// 后续在通过packToData无损压缩返回ArrayBuffer数据
const pixelMap = imageSource.createPixelMapSync(options)

const imagePacker: image.ImagePacker = image.createImagePacker()
const packOpts: image.PackingOption = { format: 'image/webp', quality: 100 }
const result:ArrayBuffer = await imagePacker.packToData(pixelMap, packOpts)
// 最后将压缩得到的ArrayBuffer类型的数据保存至本地,然后就完成了图片分辨率压缩
// 是不是很简单?其实就是官网提供的api,只负责调用就实现了

ArrayBuffer数据保存至沙箱方法

// 需要保存文件的路径
const filePath="xxxx"
let fileFd =fileIo.openSync(filePath, fileIo.OpenMode.CREATE 
                            | fileIo.OpenMode.WRITE_ONLY 
                            | fileIo.OpenMode.TRUNC).fd
fileIo.writeSync(fileFd, arrayBuffer)
fileIo.closeSync(fileFd)

图片压缩库介绍(源码在文末)

支持的数据类型:fd,uri,图片沙箱路径,图片网络地址,base64图片,ArrayBuffer。
支持批量压缩,提供压缩进度监听。

HMImageUtils额外提供

1:fd转ArrayBuffer、UintArray方法
2:uri转ArrayBuffer、UintArray方法
3:沙箱路径转ArrayBuffer、UintArray方法
4:ArrayBuffer转UintArray方法

下载安装

中心仓库地址

ohpm install @zhongrui/hm_image

导入模块

import { HMImage, CompressImageOption, CompressResult } from "@zhongrui/hm_image";

图片压缩

public compress(context:Context){
  // 此处换成实际的图片uri
  const imageData = 'file://com.example.xxx/xxx.jpg'
  // 支持fd、uri、沙箱路径、图片url、base64图片、ArrayBuffer数据
  HMImage.compress(context)
     // 打开调试模式,输出日志
    .setDebug(true)
    .setProgressListener((progress:number,total:number)=>{
        //压缩进度,progress:压缩成功的数量,total:总数量
    })
    .start([imageData]).then((result: CompressResult) => {
    // 本次压缩是否全部成功
    const isAllSuccess = result.isAllSuccess
    // 本次压缩成功的数据
    const successData = result.successData
    // 本次压缩失败的数据
    const failData = result.failData
    // 处理完业务操作之后,调用delete()方法可以删除本次压缩保存的沙箱图片
    result.delete()
    // 处理完业务操作之后,调用deleteAll()方法可以删除所有压缩保存在沙箱目录的图片,效果和HMImage.deleteAllCompressImage(context)一致
    result.deleteAll()
  }).catch((error: BusinessError) => {
    const code = error.code
    const message = error.message
    console.info("compress err code:" + code + ",message:" + message)
  })
}
compress

compress(context: Context, option?: CompressImageOption)
设置压缩参数

参数名 类型 是否必填 说明
context Context 应用上下文
option CompressImageOption 图片压缩选项

CompressImageOption

参数名 类型 是否必填 说明
maxWidth number 限制图片压缩后的最大宽度不超过maxWidth,单位:px
maxHeight number 限制图片压缩后的最大高度不超过maxHeight,单位:px
scale number 图片压缩时设置的分辨率缩放比例取值范围:(0,1]
maxFileSize number 设置图片压缩后的文件大小不超过maxFileSize,单位:byte
ignoreFileSize number 图片大小如果小于等于ignoreFileSize,则不压缩,单位:byte
targetDir string 设置图片保存的目录
quality number 图片压缩的质量,取值范围:(0,100],默认值:70
qualityStep number 如果图片压缩后的文件大小超过maxFileSize,quality会依次减少qualityStep再进行压缩
compressNum number 同时压缩图片的多线程数量,默认值:8
imageFormat CompressionImageFormat 取值:JPEG,WEBP,PNG,HEIC,HEIF,默认值:CompressionImageFormat.WEBP
start

start(image: ImageDataType[]): Promise< CompressResult >;
参数:

参数名 类型 是否必填 说明
image ImageDataType[] 图片数据,支持string或number或ArrayBuffer类型,可以是fd,uri,url,沙箱路径,base64

返回值:

参数名 类型 说明
isAllSuccess boolean 图片是否全部压缩成功
successData CompressImageData[] 压缩成功的图片数据
failData CompressImageData[] 压缩失败的图片数据
delete function 删除本次图片压缩文件的方法
deleteAll function 删除所有图片压缩文件的方法

CompressImageData

参数名 类型 说明
code number 错误码
message string 错误提示信息
origin ImageDataType 原始图片数据
originSize number 原始图片文件大小,单位:byte
fileName string 原始图片缓存到沙箱目录的文件名
filePath string 原始图片缓存到沙箱目录的文件路径
compressFileName string 压缩后的图片文件名
compressFilePath string 压缩后的图片文件路径
compressFileSize number 压缩后的图片文件大小,单位:byte

CompressImageData.code错误码

错误码 说明
1 成功
-1 内部错误
1001 参数错误
1002 原始图片复制到沙箱目录错误
1003 检查图片大小错误
1005 剩余空间不足
1006 创建imageSource失败
1007 分辨率压缩失败
1008 质量压缩失败
1009 保存和压缩过程错误
1010 网络图片地址为空
1011 获取网络图片大小错误
1012 下载网络地址错误

注意:start().then().catch((error: BusinessError) => {})中的BusinessError错误码需要另行处理,可参考官方文档

deleteAllCompressImage

删除所有图片压缩保存到本地的文件的方法

// 删除所有压缩保存在沙箱目录的图片
HMImage.deleteAllCompressImage(context)

let targetDir='/data/xxxx/haps/entry/files'
// 如果压缩图片时CompressImageOption参数有设置targetDir,这里可以传入otherDir一起删除
HMImage.deleteAllCompressImage(context,targetDir)
  
let otherDir=['/data/xxxx/haps/entry/files','/data/xxxx/haps/entry/cache']
// 除了删除默认缓存目录,还需要删除其他多个目录
HMImage.deleteAllCompressImage(context,...otherDir)

参数:

参数名 类型 是否必传 说明
context Context 应用上下文
dirPath …string[] 其他目录

HMImageUtils

// fd、uri、沙箱路径文件转ArrayBuffer
HMImageUtils.fileToArrayBuffer(file: number | string)

// base64数据转ArrayBuffer
HMImageUtils.base64ToArrayBuffer(base64Image: string)

// fd、uri、沙箱路径、base64、ArrayBuffer数据转Uint8Array
HMImageUtils.fileToUint8Array(file: ImageDataType)

中心仓库地址
源码地址

历史文章

HarmonyOS NEXT多环境+多渠道+自定义路径输出+自定义名称一键打app和hap包
HarmonyOS NEXT一行代码实现任意处弹窗
HarmonyOS NEXT数据列表加载更多(无需监听列表滑到最底部)
HarmonyOS NEXT下拉刷新+上拉加载(纵向横向都支持)(v1+v2装饰器)

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐