文档管理中心
我的
您当前正在浏览新版开发者文档中心,目录分类和层级有所调整。点击左侧当前文档分类名称前的“☰”图标,可切换文档分类。 了解新版目录
指南与API参考指南媒体Image Kit(图片处理服务)图片开发指导(ArkTS)图片编辑和处理使用PixelMap完成位图操作

使用PixelMap完成位图操作

当需要对目标图片中的部分区域进行处理时,可以使用位图操作功能。此功能常用于图片美化等操作。

如下图所示,一张图片中,将指定的矩形区域像素数据读取出来,进行修改后,再写回原图片对应区域。

图1 位图操作示意图

开发步骤

位图操作相关API的详细介绍请参见Interface (PixelMap)。

  1. 完成图片解码,获取PixelMap位图对象。

  2. 从PixelMap位图对象中获取信息。

    收起
    自动换行
    深色代码主题
    复制
    1. // 获取图像像素的总字节数。
    2. const totalPixelBytes: number = this.pixelMap.getPixelBytesNumber();
    3. Logger.info('Total bytes: ', totalPixelBytes.toString());
    4. // 获取图像像素的每行字节数。
    5. const rowBytes: number = this.pixelMap.getBytesNumberPerRow();
    6. Logger.info('Row bytes: ', rowBytes.toString());
    7. // 获取当前图像的像素密度。像素密度是指每英寸图片所拥有的像素数量,像素密度越大,图片越精细。
    8. const density: number = this.pixelMap.getDensity();
    9. Logger.info('Density: ', density.toString());
  3. 读取并修改目标区域像素数据,写回原图。

    说明

    建议readPixelsToBuffer和writeBufferToPixels成对使用,readPixels和writePixels成对使用,避免因图像像素格式不一致,造成PixelMap图像出现异常。

    收起
    自动换行
    深色代码主题
    复制
    1. // 场景一:读取并修改整张图像数据。
    2. // 读取整个PixelMap的像素数据,并按照PixelMap的像素格式写入缓冲区。
    3. const buffer = new ArrayBuffer(totalPixelBytes);
    4. await this.pixelMap.readPixelsToBuffer(buffer).then(() => {
    5. Logger.info('Succeeded in reading image pixel data.');
    6. }).catch((error: BusinessError) => {
    7. Logger.error('Failed to read image pixel data. The error is: ' + String(error));
    8. });
    9. // ...
    10. // 按照PixelMap的像素格式,读取缓冲区内的图像像素数据,并将其写入整个PixelMap。
    11. this.pixelMap!.writeBufferToPixels(buffer).then(() => {
    12. Logger.info('Succeeded in writing image pixel data.');
    13. this.updateImageInfo();
    14. }).catch((error: BusinessError) => {
    15. Logger.error('Failed to write image pixel data. The error is: ' + String(error));
    16. });
    收起
    自动换行
    深色代码主题
    复制
    1. // 场景二:读取并修改指定区域内的图像数据。
    2. // 读取PixelMap指定区域内的像素数据,并按照RGBA_8888像素格式写入PositionArea.pixels缓冲区,该区域由PositionArea.region指定。
    3. const regionWidth: number = 200;
    4. const regionHeight: number = 100;
    5. const area: image.PositionArea = {
    6. pixels: new ArrayBuffer(regionWidth * regionHeight * 4), // BGRA_8888格式的每个像素占4字节。
    7. offset: 0,
    8. stride: regionWidth * 4, // 指定区域的行跨距。
    9. region: {
    10. x: 0,
    11. y: 0,
    12. size: { width: regionWidth, height: regionHeight }
    13. }
    14. };
    15. await this.pixelMap.readPixels(area).then(() => {
    16. Logger.info('Succeeded in reading the image data in the area.');
    17. // ...
    18. }).catch((error: BusinessError) => {
    19. Logger.error('Failed to read the image data in the area. The error is: ' + String(error));
    20. });
    21. // 读取PositionArea.pixels缓冲区内的图像像素数据,并按照BGRA_8888像素格式将其写入PixelMap的指定区域,该区域由PositionArea.region指定。
    22. await this.pixelMap.writePixels(area).then(() => {
    23. this.updateImageInfo();
    24. Logger.info('Succeeded in writing pixelMap into the specified area.');
    25. }).catch((error: BusinessError) => {
    26. Logger.error('Failed to write pixelMap into the specified area. The error is: ' + String(error));
    27. });

开发示例

复制(深拷贝)位图并改变像素格式

说明
  • 该方法仅可实现PixelMap基本内容的复制,不支持复制色域和HDR元数据。如果不需要改变新PixelMap的像素格式,请使用clone或cloneSync。
  • 该方法不支持将新PixelMap转换为下列像素格式:RGBA_1010102、YCBCR_P010、YCRCB_P010、ASTC_4x4。
  1. 完成图片解码,获取PixelMap位图对象。

  2. 参考以下代码对PixelMap进行深拷贝。

    收起
    自动换行
    深色代码主题
    复制
    1. /**
    2. * 复制(深拷贝)PixelMap并改变像素格式。
    3. *
    4. * @param pixelMap - 被复制的原PixelMap。
    5. * @param desiredPixelFormat - 新PixelMap的像素格式。如果不指定,则仍使用原PixelMap的像素格式。
    6. * @returns 新PixelMap的Promise。
    7. */
    8. async function clonePixelMap(pixelMap: PixelMap, desiredPixelFormat?: image.PixelMapFormat): Promise<PixelMap> {
    9. // 获取原PixelMap的图片信息。
    10. const imageInfo = pixelMap.getImageInfoSync();
    11. // 读取原PixelMap的像素数据,并按照原PixelMap的像素格式写入缓冲区。
    12. const buffer = new ArrayBuffer(pixelMap.getPixelBytesNumber());
    13. await pixelMap.readPixelsToBuffer(buffer);
    14. // 根据原PixelMap的图片信息,生成初始化选项。
    15. const options: image.InitializationOptions = {
    16. // 数据源的像素格式:必须匹配原PixelMap的像素格式,否则新PixelMap的图像会出现异常。
    17. srcPixelFormat: imageInfo.pixelFormat,
    18. // 新PixelMap的像素格式。
    19. pixelFormat: desiredPixelFormat || imageInfo.pixelFormat,
    20. // 新PixelMap的透明度类型。
    21. alphaType: imageInfo.alphaType,
    22. // 新PixelMap的尺寸:必须匹配原PixelMap的尺寸,不支持传入其他尺寸以进行缩放。
    23. size: imageInfo.size
    24. };
    25. // 根据像素数据和初始化选项,创建新PixelMap。
    26. return await image.createPixelMap(buffer, options);
    27. }

将两张宽度相同的位图纵向拼接成一张长图

说明

该方法仅支持以下像素格式的PixelMap:RGBA_8888、BGRA_8888、RGBA_F16。

  1. 完成图片解码,获取两张宽度相同且像素格式相同的PixelMap位图对象。

  2. 参考以下代码对两张PixelMap进行拼接。

    收起
    自动换行
    深色代码主题
    复制
    1. /**
    2. * 将两张宽度相同的PixelMap纵向拼接成一张长图。
    3. *
    4. * @param pixelMap1 - 第一张PixelMap。
    5. * @param pixelMap2 - 第二张PixelMap。宽度必须与第一张相同,高度可以不同。
    6. * @returns 拼接后的新PixelMap的Promise。
    7. */
    8. async function concatPixelMap(pixelMap1: PixelMap, pixelMap2: PixelMap): Promise<PixelMap> {
    9. // 将pixelMap1的像素数据读取至area1.pixels中。
    10. const imageInfo1 = pixelMap1.getImageInfoSync();
    11. const area1: image.PositionArea = {
    12. pixels: new ArrayBuffer(pixelMap1.getPixelBytesNumber()),
    13. offset: 0,
    14. stride: pixelMap1.getBytesNumberPerRow(),
    15. region: {
    16. size: imageInfo1.size,
    17. x: 0,
    18. y: 0
    19. }
    20. };
    21. await pixelMap1.readPixels(area1);
    22. // 将pixelMap2的像素数据读取至area2.pixels中。
    23. const imageInfo2 = pixelMap2.getImageInfoSync();
    24. const area2: image.PositionArea = {
    25. pixels: new ArrayBuffer(pixelMap2.getPixelBytesNumber()),
    26. offset: 0,
    27. stride: pixelMap2.getBytesNumberPerRow(),
    28. region: {
    29. size: imageInfo2.size,
    30. x: 0,
    31. y: 0
    32. }
    33. };
    34. await pixelMap2.readPixels(area2);
    35. // 创建一个新的空白PixelMap,其宽度与pixelMap1和pixelMap2相等,高度为pixelMap1和pixelMap2相加。
    36. const options: image.InitializationOptions = {
    37. srcPixelFormat: imageInfo1.pixelFormat,
    38. pixelFormat: imageInfo1.pixelFormat,
    39. size: {
    40. width: imageInfo1.size.width,
    41. height: imageInfo1.size.height + imageInfo2.size.height
    42. }
    43. };
    44. const newPixelMap = image.createPixelMapSync(options);
    45. // 将之前获取的pixelMap1和pixelMap2的像素数据按顺序写入新PixelMap。
    46. await newPixelMap.writePixels(area1);
    47. area2.region.y = imageInfo1.size.height; // pixelMap2像素的写入位置应该从pixelMap1末行像素的下一行开始。
    48. await newPixelMap.writePixels(area2);
    49. return newPixelMap;
    50. }