鸿蒙 图片位图操作:像素级读写
本文同步发表于微信公众号微信搜索程语新视界即可关注每个工作日都有文章更新一、位图操作位图操作指对PixelMap进行像素级的读写操作可以对目标图片中的部分区域进行处理。应用场景场景说明图片美化调整局部颜色、亮度添加水印在指定区域写入文字或Logo滤镜效果批量修改像素颜色图像拼接将多张图片合并成一张操作示意图原图完整图片 ↓ 读取指定矩形区域像素数据 ↓ 修改像素数据 ↓ 写回原图片对应区域 ↓ 得到修改后的图片二、导入模块import { image } from kit.ImageKit; import { BusinessError } from kit.BasicServicesKit;三、获取PixelMap信息在进行位图操作前需要先完成图片解码获取PixelMap对象。// 获取图像像素的总字节数 let pixelBytesNumber: number pixelMap.getPixelBytesNumber(); // 获取图像像素每行字节数 let rowBytes: number pixelMap.getBytesNumberPerRow(); // 获取当前图像像素密度每英寸像素数量密度越大图片越精细 let density: number pixelMap.getDensity();四、像素读写操作4.1 场景一整张图片读写Buffer方式使用readPixelsToBuffer读取整张图片像素数据到缓冲区使用writeBufferToPixels将缓冲区数据写回。// 按照PixelMap的像素格式读取PixelMap的图像像素数据并写入缓冲区中 const buffer new ArrayBuffer(pixelBytesNumber); pixelMap.readPixelsToBuffer(buffer).then(() { console.info(Succeeded in reading image pixel data.); }).catch((error: BusinessError) { console.error(Failed to read image pixel data. The error is: error); }); // 修改缓冲区数据如调整颜色、亮度等 // ... // 按照PixelMap的像素格式读取缓冲区中的图像像素数据并写入PixelMap pixelMap.writeBufferToPixels(buffer).then(() { console.info(Succeeded in writing image pixel data.); }).catch((error: BusinessError) { console.error(Failed to write image pixel data. The error is: error); });4.2 场景二指定区域图片读写Pixels方式使用readPixels读取指定区域的像素数据使用writePixels将数据写回指定区域。PositionArea参数说明参数类型说明pixelsArrayBuffer像素数据缓冲区offsetnumber缓冲区偏移量stridenumber行步长每行字节数regionRegion区域信息x, y, width, height// 固定按照BGRA_8888格式读取PixelMap指定区域内的图像像素数据 const area: image.PositionArea { pixels: new ArrayBuffer(8), offset: 0, stride: 8, region: { size: { height: 1, width: 2 }, x: 0, y: 0 } }; pixelMap.readPixels(area).then(() { console.info(Succeeded in reading the image data in the area.); }).catch((error: BusinessError) { console.error(Failed to read the image data in the area. The error is: error); }); // 修改区域像素数据 // ... // 固定按照BGRA_8888格式将缓冲区中的图像像素数据写入PixelMap指定区域 pixelMap.writePixels(area).then(() { console.info(Succeeded in writing the image data in the area.); }).catch((error: BusinessError) { console.error(Failed to write the image data in the area. The error is: error); });说明建议readPixelsToBuffer和writeBufferToPixels成对使用readPixels和writePixels成对使用避免因图像像素格式不一致造成PixelMap图像出现异常五、示例5.1 复制深拷贝位图并改变像素格式该方法仅可实现PixelMap基本内容的复制不支持复制色域和HDR元数据。提示如果不需要改变新PixelMap的像素格式请使用clone或cloneSync方法。/** * 复制深拷贝PixelMap并改变像素格式 * * param pixelMap - 被复制的原PixelMap * param desiredPixelFormat - 新PixelMap的像素格式可选不指定则沿用原格式 * returns 新PixelMap的Promise */ async function clonePixelMap(pixelMap: image.PixelMap, desiredPixelFormat?: image.PixelMapFormat): Promiseimage.PixelMap { // 获取原PixelMap的图片信息 const imageInfo pixelMap.getImageInfoSync(); // 读取原PixelMap的像素数据并按照原PixelMap的像素格式写入缓冲区 const buffer new ArrayBuffer(pixelMap.getPixelBytesNumber()); await pixelMap.readPixelsToBuffer(buffer); // 根据原PixelMap的图片信息生成初始化选项 const options: image.InitializationOptions { // 数据源的像素格式必须匹配原PixelMap的像素格式 srcPixelFormat: imageInfo.pixelFormat, // 新PixelMap的像素格式 pixelFormat: desiredPixelFormat || imageInfo.pixelFormat, // 新PixelMap的透明度类型 alphaType: imageInfo.alphaType, // 新PixelMap的尺寸必须匹配原PixelMap的尺寸 size: imageInfo.size }; // 根据像素数据和初始化选项创建新PixelMap return await image.createPixelMap(buffer, options); }限制说明限制项说明不支持复制色域、HDR元数据不支持转换为RGBA_1010102、YCBCR_P010、YCRCB_P010、ASTC_4x45.2 将两张宽度相同的位图纵向拼接成一张长图限制仅支持以下像素格式的PixelMapRGBA_8888、BGRA_8888、RGBA_F16async function concatPixelMap(pixelMap1: image.PixelMap, pixelMap2: image.PixelMap): Promiseimage.PixelMap { // 1. 将pixelMap1的像素数据读取至area1.pixels中 const imageInfo1 pixelMap1.getImageInfoSync(); const area1: image.PositionArea { pixels: new ArrayBuffer(pixelMap1.getPixelBytesNumber()), offset: 0, stride: pixelMap1.getBytesNumberPerRow(), region: { size: imageInfo1.size, x: 0, y: 0 } }; await pixelMap1.readPixels(area1); // 2. 将pixelMap2的像素数据读取至area2.pixels中 const imageInfo2 pixelMap2.getImageInfoSync(); const area2: image.PositionArea { pixels: new ArrayBuffer(pixelMap2.getPixelBytesNumber()), offset: 0, stride: pixelMap2.getBytesNumberPerRow(), region: { size: imageInfo2.size, x: 0, y: 0 } }; await pixelMap2.readPixels(area2); // 3. 创建一个新的空白PixelMap // 宽度与pixelMap1和pixelMap2相等高度为两者相加 const options: image.InitializationOptions { srcPixelFormat: imageInfo1.pixelFormat, pixelFormat: imageInfo1.pixelFormat, size: { width: imageInfo1.size.width, height: imageInfo1.size.height imageInfo2.size.height } }; const newPixelMap image.createPixelMapSync(options); // 4. 将像素数据按顺序写入新PixelMap await newPixelMap.writePixels(area1); // pixelMap2像素的写入位置应该从pixelMap1末行像素的下一行开始 area2.region.y imageInfo1.size.height; await newPixelMap.writePixels(area2); return newPixelMap; }总结操作类型方法说明获取像素字节数getPixelBytesNumber()图像像素总字节数获取每行字节数getBytesNumberPerRow()每行像素字节数获取像素密度getDensity()每英寸像素数整张图片读取readPixelsToBuffer()读取到ArrayBuffer整张图片写入writeBufferToPixels()从ArrayBuffer写入区域读取readPixels()读取指定区域到PositionArea区域写入writePixels()从PositionArea写入指定区域深拷贝clonePixelMap()复制并改变像素格式图像拼接concatPixelMap()两张图片纵向拼接开发流程完成图片解码获取PixelMap ↓ 获取PixelMap信息可选 ↓ 读取像素数据readPixelsToBuffer / readPixels ↓ 修改像素数据 ↓ 写回PixelMapwriteBufferToPixels / writePixels ↓ 使用修改后的PixelMap ↓ 释放资源鸿蒙PixelMap位图操作通过readPixelsToBuffer/writeBufferToPixels整图和readPixels/writePixels区域实现像素级读写支持深拷贝改变像素格式和图像拼接是图片美化、水印添加等功能的基础。