
2.1 什么是 PixelMap在 HarmonyOS NEXT 中PixelMap 是所有图片处理的核心对象。很多开发者第一次接触图片开发时认为图片 jpg/png 文件实际上并不是。JPG、PNG、WebP 都只是磁盘上的文件格式。例如photo.jpg它在磁盘里面保存的是压缩数据而不是RGB RGB RGB RGB...图片真正能够被屏幕显示之前需要经过一次完整的解码流程。整个流程如下photo.jpg │ ▼ ImageSource │ ▼ JPEG 解码 │ ▼ RGBA 像素数据 │ ▼ PixelMap │ ▼ ArkUI Image │ ▼ GPU │ ▼ 屏幕显示因此PixelMap 就是一张图片解码后的像素数据。所有图片编辑都是围绕 PixelMap 完成。例如微信修改头像选择图片 ↓ PixelMap ↓ 裁剪 ↓ 旋转 ↓ 压缩 ↓ 上传小红书相册 ↓ PixelMap ↓ 滤镜 ↓ 贴纸 ↓ 文字 ↓ 保存美图秀秀图片 ↓ PixelMap ↓ 美颜 ↓ AI ↓ 导出所以可以说没有 PixelMap就没有图片编辑。2.2 PixelMap 为什么存在有人会问既然已经有 jpg 文件了。为什么还需要 PixelMap原因很简单。例如我们想修改图片左上角一个像素。JPGFFFFFFFFFFABCD239A... ......看到什么了吗什么也看不到。因为 JPG 是经过DCT 离散余弦变换量化霍夫曼编码以后得到的一串压缩数据。CPU 根本不知道第100万个字节 是不是 第100万个像素。所以必须JPG ↓ 解码 ↓ PixelMap ↓ 修改 ↓ 重新编码 ↓ JPG整个世界所有图片编辑器都是这样工作的。包括PhotoshopLightroom美图秀秀醒图Snapseed都是先解码再编辑。2.3 PixelMap 内存结构PixelMap 本质就是一块连续申请出来的内存。例如创建const pixelMap await imageSource.createPixelMap()实际上系统做了下面几件事情读取图片 ↓ 申请内存 ↓ JPEG 解码 ↓ 写入内存 ↓ PixelMap 返回假设图片1000 × 1000系统会申请1000000 个 Pixel每一个 Pixel 都紧挨着。例如Pixel0 Pixel1 Pixel2 Pixel3 Pixel4 ...... Pixel999999连续存放。这就是为什么PixelMap 可以高速访问。因为CPU 最喜欢连续内存而不是链表 树 Map图片处理之所以快就是因为PixelMap 的布局非常适合 CPU Cache。2.4 PixelMap 的内存布局PixelMap 默认使用RGBA8888什么意思一个 Pixel包含Red Green Blue Alpha每一个8 bit所以8 8 8 8 32bit即4 Byte一个 Pixel内存里面就是R G B A例如红色255 0 0 255绿色0 255 0 255蓝色0 0 255 255透明255 255 255 0因此PixelMap 真正的数据就是255 0 0 255 255 0 0 255 255 0 0 255 0 255 0 255 ...... ......连续排列。2.5 一个 Pixel 占多少内存RGBA8888R 8bitG 8bitB 8bitA 8bit因此4 Byte假设图片1920 ×1080像素1920 × 1080 2073600内存2073600 × 4 8294400 Byte约等于7.91MB很多人觉得图片只有2MB为什么内存8MB原因就在这里。图片2MB是压缩以后。PixelMap8MB是解码以后。完全不是一个概念。2.6 为什么一张照片会占几十 MB现在手机1200 万像素例如4032 ×3024像素12192768内存12192768 × 4 48771072约46MB如果5000 万像素8192 ×6144内存8192 × 6144 × 4 201MB所以为什么很多 App打开照片瞬间内存上涨200MB。就是因为PixelMap 已经解码了。2.7 PixelMap 生命周期PixelMap 生命周期可以分成六个阶段。第一阶段 创建例如const imageSource image.createImageSource(path)然后const pixelMap await imageSource.createPixelMap()系统申请内存 ↓ JPEG 解码 ↓ PixelMap第二阶段 编辑例如旋转 裁剪 缩放 滤镜 文字 水印全部发生在PixelMap上。第三阶段 显示例如Image(pixelMap)ArkUI直接GPU渲染。第四阶段 保存例如PixelMap ↓ ImagePacker ↓ JPEG ↓ File保存的时候重新编码。第五阶段 上传企业项目一般保存 ↓ OSS ↓ CDN上传的不再是PixelMap。而是JPEG。第六阶段 释放例如this.pixelMap undefined没有引用以后。GC回收。内存释放。2.8 PixelMap 创建过程源码解析很多人觉得createPixelMap()只是new 一个对象。实际上里面流程远比想象复杂。createPixelMap() │ ▼ 读取文件 │ ▼ 判断图片格式 │ ▼ JPEG Decoder │ ▼ 申请 RGBA 内存 │ ▼ 颜色空间转换 │ ▼ Alpha 通道处理 │ ▼ 生成 PixelMap真正耗时的是JPEG 解码而不是new PixelMap因此第一次打开一般几十毫秒。大图几百毫秒。都是正常现象。2.9 PixelMap 创建与复制很多新人喜欢let newMap oldMap以为复制了一份。其实只是引用。真正复制需要重新创建。例如原图 48MB复制48MB 48MB 96MB再复制144MB再复制192MB所以企业项目几乎不会无限复制PixelMap。一般只有原图 ↓ 结果图两份。2.10 为什么图片编辑都围绕 PixelMap因为PixelMap拥有原始 RGBA 数据Alpha 通道宽高色彩空间可直接绘制可重新编码所有图片编辑 API最终操作的都是PixelMap例如旋转PixelMap ↓ Canvas.rotate() ↓ 新的 PixelMap裁剪PixelMap ↓ Canvas.drawImageRect() ↓ 新的 PixelMap水印PixelMap ↓ Canvas.drawText() ↓ 新的 PixelMap压缩PixelMap ↓ ImagePacker ↓ JPEG所以整个图片编辑流程实际上就是ImageSource ↓ PixelMap ↓ Canvas ↓ PixelMap ↓ ImagePacker ↓ JPEG