HarmonyOS 图片压缩实战:compressedImage、packing 与二分压缩算法详解
文章目录前言packing直接指定质量压缩compressedImage目标大小自动压缩packingImage二分压缩算法更精确savePixelMap把 PixelMap 保存到文件packToFileFromPixelMap直接写入已打开的文件saveImageSourceImageSource 保存到文件三种压缩方式怎么选写在最后前言近期发现一款很有意思的HarmonyOS 三方库, 地址 pura/harmony-utils(V1.4.0) , 作者是桃花镇童长老, 我这里也是直接通过该作者公布的源码进行案例编写进行,写了到目前写了一部分demo ,感觉确实很有帮助,这里呢也是开始写一个系列的演示demo 供大家参考。如有帮助可以在OpenHarmony中进行下载安装进行使用哦案例demo导航展示↓↓↓↓↓↓接下来言归正传 ↓↓↓↓上传图片时后台经常有限制单张不超过 2MB、头像不超过 500KB……怎么在上传前自动压缩到目标大小以内这篇讲三种压缩方式简单质量控制packing、目标大小限制compressedImage和二分压缩算法packingImage。packing直接指定质量压缩最简单的压缩方式直接指定 JPEG 质量值// quality50中等压缩constpmawaitthis.makeTestPixelMap(100,150,200,200,200);constbufawaitImageUtil.packing(pm,50,image/jpeg);this.addLog(packing(q50):${buf.byteLength}bytes);// quality10极度压缩constpmawaitthis.makeTestPixelMap(200,100,100,200,200);constbufawaitImageUtil.packing(pm,10,image/jpeg);this.addLog(packing(q10):${buf.byteLength}bytes);三个参数PixelMap质量值1-100越小文件越小格式通常用image/jpegPNG 质量值无效问题在于质量值和最终文件大小的关系不是线性的不同的图片内容同样的质量值产生的文件大小差异很大。所以如果你的需求是压缩到不超过 X KBpacking无法精确保证。compressedImage目标大小自动压缩compressedImage解决了这个问题你给一个目标大小KB它自动调整压缩参数直到文件不超过这个大小constpmawaitthis.makeTestPixelMap(80,120,200,300,300);// 压缩前的大小quality100不压缩constbeforeawaitImageUtil.packing(pm,100,image/jpeg);// 压缩到目标 5KB 以内constcompressedawaitImageUtil.compressedImage(pm,5,image/jpeg);this.compressInfo压缩前:${before.byteLength}B → 压缩后:${compressed.byteLength}B (目标≤5KB);this.addLog(compressedImage(5KB):${before.byteLength}B →${compressed.byteLength}B);三个参数PixelMap目标最大文件大小KB图片格式内部原理它会尝试不同的质量值找到一个让文件大小不超过目标值的参数。比直接猜质量值要可靠得多。注意目标大小是最大不超过不是精确等于。实际结果可能略小于目标值。packingImage二分压缩算法更精确packingImage用二分法搜索最优质量值是比compressedImage更精确的版本constpmawaitthis.makeTestPixelMap(180,100,200,200,200);// 先打包一次quality0 是为了演示实际传 0 表示最低质量constpngBufawaitImageUtil.packingFromPixelMap(pm,{format:image/jpeg,quality:0});// 二分压缩到 5KB 以内constresultawaitImageUtil.packingImage(pngBuf,pm,5*1024,0,image/jpeg);this.addLog(packingImage(5KB):${result.byteLength}bytes (≤5120));参数说明原始 buffer已打包的图片数据PixelMap目标大小字节注意是字节不是 KB5 * 1024 5KB初始质量值图片格式二分法的优势每次迭代都以 “中点质量值” 尝试收敛速度很快8 次以内就能找到满足要求的质量值比逐步递减质量值的方式效率高得多。savePixelMap把 PixelMap 保存到文件压缩后通常要保存到本地constpmawaitthis.makeTestPixelMap(255,200,0,100,100);constdirFileUtil.getFilesDirPath(images);constfilePathawaitImageUtil.savePixelMap(pm,dir,saved_test.png);this.addLog(savePixelMap →${filePath});三个参数PixelMap保存目录目录不存在会自动创建文件名含后缀返回完整的文件路径方便后续操作上传、分享等。packToFileFromPixelMap直接写入已打开的文件如果你已经打开了一个文件拿到了 fd可以直接写入constpmawaitthis.makeTestPixelMap(200,255,100,80,80);constfilePathFileUtil.getFilesDirPath(undefined,pack_to_file.jpg);constfileawaitFileUtil.open(filePath);awaitImageUtil.packToFileFromPixelMap(pm,file.fd,{format:image/jpeg,quality:90});awaitFileUtil.close(file.fd);conststatFileUtil.statSync(filePath);this.addLog(packToFileFromPixelMap:${stat.size}bytes);流程获取目标文件路径打开文件FileUtil.open把 PixelMap 以指定格式写入 fdImageUtil.packToFileFromPixelMap关闭文件用stat验证写入大小saveImageSourceImageSource 保存到文件constpmawaitthis.makeTestPixelMap(100,200,255,80,80);constbufawaitImageUtil.packingFromPixelMap(pm,{format:image/png,quality:100});constsrcImageUtil.createImageSource(buf);constdirFileUtil.getFilesDirPath(images);constpawaitImageUtil.saveImageSource(src,dir,saved_src.png);this.addLog(saveImageSource →${p});这个适合的场景你有一个ImageSource比如从网络下载的图片解析出来的要保存到本地。三种压缩方式怎么选方式特点适用场景packing(pm, quality)简单但不保证目标大小知道合适质量值或不在乎精确大小compressedImage(pm, maxKB)目标大小限制自动调整需要保证不超过某个大小packingImage(buf, pm, maxBytes)二分法最精确对大小有严格要求且需要高效率实际项目里的推荐头像上传用compressedImage简单可靠大批量图片处理用packingImage效率高。写在最后图片压缩的核心是在文件大小和画质之间找平衡packing最简单指定质量值compressedImage给定目标 KB自动压到不超标packingImage二分法精确高效savePixelMap压缩后保存到本地文件三篇 ImageUtil 文章到这里从创建 PixelMap、Base64 转换到图片压缩日常的图片处理需求基本都覆盖了。