目录

如何实现PixelMap图片颜色翻转

问题现象

通过截图获取的图片类型是PixelMap,图片背景是白色,绘制内容是黑色,需要将白色背景图转换成透明色,将原来黑色的内容转换成白色,如何实现。

效果预览

背景知识

PixelMap是图像解码后的一种无压缩位图格式,图片解码是指将所支持格式的图片文件解码成统一的PixelMap格式,目前支持的图片格式有JPEG、PNG、GIF、WebP、BMP、SVG、ICO、DNG、HEIF。PixelMap主要用于图像显示或进一步处理,这种格式可以有效地存储图像的原始数据,使其可以方便地进行图像变换,如裁剪、缩放、偏移、旋转、翻转、设置透明度等。

解决方案

  1. 使用getPixelBytesNumber方法获取图像像素的总字节数,通过readPixelsToBuffer读取图像像素数据,结果写入缓冲区ArrayBuffer里。
    const imageInfo: image.ImageInfo = await pixelMap.getImageInfo();
    const buffer: ArrayBuffer = new ArrayBuffer(pixelMap.getPixelBytesNumber());
    // 通过readPixelsToBuffer实现PixelMap的深拷贝,其中readPixelsToBuffer输出为BGRA_8888
    await pixelMap.readPixelsToBuffer(buffer);
    // readPixelsToBuffer输出为BGRA_8888,此处createPixelMap需转为RGBA_8888
    const opts: image.InitializationOptions = {
      editable: true,
      pixelFormat: image.PixelMapFormat.RGBA_8888,
      size: { height: imageInfo.size.height, width: imageInfo.size.width }
    };
    const pixelData = new Uint32Array(buffer);
  2. 遍历像素数组,改变颜色。再通过image.createPixelMap创建新的PixelMap对象,按照PixelMap的像素格式,读取缓冲区中的图像像素数据,并写入新PixelMap。
    // 遍历像素数组,将白色变为透明,深色主题下黑色变成白色
    const length = pixelData.length;
    for (let i = 0; i < length; i++) {
      if (pixelData[i] === 0xFFFFFFFF) { // 检查是否为白色
        pixelData[i] = 0xFF000000; // 为了方便展示,背景先改成深色
      } else {
        if (dark) { // 如果是深色
          pixelData[i] = 0xFFffffff; // 改为白色
        }
      }
    }
    // 重新将修改像素写入
    const newPixelMap = await image.createPixelMap(buffer, opts);
    await newPixelMap.writeBufferToPixels(buffer);
    this.changeImgPixelMap = newPixelMap;

完整代码示例参考:

import { image } from '@kit.ImageKit';
import { common } from '@kit.AbilityKit';

@Entry
@Component
struct TurnImageColorDemo {
  @State pixelMap: image.PixelMap | undefined = undefined;
  @State changeImgPixelMap: image.PixelMap | undefined = undefined;

  async handleLightAndDarkPixelMap(pixelMap: image.PixelMap, dark: boolean) {
    const imageInfo: image.ImageInfo = await pixelMap.getImageInfo();
    const buffer: ArrayBuffer = new ArrayBuffer(pixelMap.getPixelBytesNumber());
    // 通过readPixelsToBuffer实现PixelMap的深拷贝,其中readPixelsToBuffer输出为BGRA_8888
    await pixelMap.readPixelsToBuffer(buffer);
    // readPixelsToBuffer输出为BGRA_8888,此处createPixelMap需转为RGBA_8888
    const opts: image.InitializationOptions = {
      editable: true,
      pixelFormat: image.PixelMapFormat.RGBA_8888,
      size: { height: imageInfo.size.height, width: imageInfo.size.width }
    };
    const pixelData = new Uint32Array(buffer);

    // 遍历像素数组,将白色变为透明,深色主题下黑色变成白色
    const length = pixelData.length;
    for (let i = 0; i < length; i++) {
      if (pixelData[i] === 0xFFFFFFFF) { // 检查是否为白色
        pixelData[i] = 0xFF000000; // 为了方便展示,背景先改成深色
      } else {
        if (dark) { // 如果是深色
          pixelData[i] = 0xFFffffff; // 改为白色
        }
      }
    }
    // 重新将修改像素写入
    const newPixelMap = await image.createPixelMap(buffer, opts);
    await newPixelMap.writeBufferToPixels(buffer);
    this.changeImgPixelMap = newPixelMap;
  }

  async aboutToAppear() {
    let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
    // 获取resourceManager资源管理
    const resourceManager = context.resourceManager;
    // 获取图片数据,代码中图片仅作示例,实际请按开发环境图片为准
    const fileData = await resourceManager.getMediaContent($r('app.media.turn_color').id);
    // 创建imageSource
    const imageSource = image.createImageSource(fileData.buffer);
    let decodingOptions: image.DecodingOptions = {
      editable: true,
      desiredPixelFormat: 3,
    };
    // 创建PixelMap
    this.pixelMap = await imageSource.createPixelMap(decodingOptions);
  }

  build() {
    Column({ space: 10 }) {
      Text('原图')
        .fontSize(10)
      Image(this.pixelMap)
        .width(200)
        .height(200)
      Button('颜色翻转')
        .width(200)
        .height(30)
        .onClick(() => {
          if (this.pixelMap) {
            this.handleLightAndDarkPixelMap(this.pixelMap, true);
          }
        })
      Text('翻转后的图片')
        .fontSize(10)
      Image(this.changeImgPixelMap)
        .width(200)
        .height(200)
    }
    .height('100%')
    .width('100%')
  }
}

总结

实现图片颜色翻转可参考以下步骤:

  1. 获取需要转换的图片资源数据,并写入缓冲区。
  2. 遍历像素数组,通过条件判断将符合条件的像素值转变成指定的颜色值。
  3. 使用修改后的像素数据创建新的PixelMap并保存。

根据不同的业务场景,实现将符合条件的像素数据转变成指定颜色(如蓝色转变为红色等)。