鸿蒙 图片位图操作:像素级读写
摘要:本文介绍了鸿蒙系统中PixelMap位图操作方法,主要包括整图和指定区域的像素读写操作。通过readPixelsToBuffer/writeBufferToPixels和readPixels/writePixels方法可实现像素级处理,支持图片美化、水印添加等功能。同时提供了深拷贝改变像素格式和图像拼接的代码示例,强调操作前需获取PixelMap对象并注意格式匹配。这些方法为图像处理提供了基
本文同步发表于微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新
一、位图操作
位图操作指对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参数说明:
| 参数 | 类型 | 说明 |
|---|---|---|
pixels |
ArrayBuffer | 像素数据缓冲区 |
offset |
number | 缓冲区偏移量 |
stride |
number | 行步长(每行字节数) |
region |
Region | 区域信息(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): Promise<image.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_4x4 |
5.2 将两张宽度相同的位图纵向拼接成一张长图
限制:仅支持以下像素格式的PixelMap:RGBA_8888、BGRA_8888、RGBA_F16
async function concatPixelMap(pixelMap1: image.PixelMap, pixelMap2: image.PixelMap): Promise<image.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)
↓
修改像素数据
↓
写回PixelMap(writeBufferToPixels / writePixels)
↓
使用修改后的PixelMap
↓
释放资源
鸿蒙PixelMap位图操作通过readPixelsToBuffer/writeBufferToPixels(整图)和readPixels/writePixels(区域)实现像素级读写,支持深拷贝改变像素格式和图像拼接,是图片美化、水印添加等功能的基础。
更多推荐


所有评论(0)