HarmonyOS鸿蒙Next中如何给图片设置灰度效果?

HarmonyOS鸿蒙Next中如何给图片设置灰度效果? 如何给图片设置灰度效果?

3 回复

先来看真机效果:

cke_313244.gif

有以下两种方式使图片产生灰度效果:

1、直接使用组件的通用属性grayscale

Image($r('app.media.yd')).grayscale(1)  //1置灰,0无变化

2、通过读取图片的像素数据结合TaskGroup将其以rgba的格式分为四份在代码里面处理:

  • TaskGroup:表示任务组,一次执行一组任务,适用于执行一组有关联的任务。如果所有任务正常执行,异步执行完毕后返回所有任务结果的数组,数组中元素的顺序与addTask的顺序相同;如果任意任务失败,则会抛出对应异常。如果任务组中存在多个任务失败的情况,则会抛出第一个失败任务的异常。任务组可以多次执行,但执行后不能新增任务。

资源图片转为pixelMap

  // 通过media目录下的文件名称创建pixelMap。
  getPixmapFromMediaSync(resource: Resource): image.PixelMap {
    const context = this.getUIContext().getHostContext() as common.UIAbilityContext;
    const resourceMgr = context.resourceManager;

    const fileData = resourceMgr.getMediaContentSync(resource.id);
    const imageSource = image.createImageSource(fileData.buffer);
    const pixelMap = imageSource.createPixelMapSync();
    imageSource.release();
    return pixelMap;
  }

pixelMap分成四段并发调度

 // 读取pixelMap的像素数据
  let width = pixelMap.getImageInfoSync().size.width;
  let height = pixelMap.getImageInfoSync().size.height;
  let readBuffer: ArrayBuffer = new ArrayBuffer(width * height * 4);
  pixelMap.readPixelsToBufferSync(readBuffer);
  // 分成四段并发调度
  let number: number = 4 * Math.ceil(width * height / 4);
  let buffer1: ArrayBuffer = readBuffer.slice(0, number);
  let buffer2: ArrayBuffer = readBuffer.slice(number, number * 2);
  let buffer3: ArrayBuffer = readBuffer.slice(number * 2, number * 3);
  let buffer4: ArrayBuffer = readBuffer.slice(number * 3);

装填TaskGroup

let group: taskpool.TaskGroup = new taskpool.TaskGroup();
group.addTask(imageProcessing, buffer1);
group.addTask(imageProcessing, buffer2);
group.addTask(imageProcessing, buffer3);
group.addTask(imageProcessing, buffer4);

  function imageProcessing(dataSlice: ArrayBuffer): Uint8Array {
  // 图像灰度化处理操作
  let byteBuffer: Uint32Array = new Uint32Array(dataSlice);
  let byteBufferTemp: Uint8Array = new Uint8Array(new ArrayBuffer(byteBuffer.length * 4));
  for (let index = 0; index < byteBuffer.length; index++) {
    // 通过移位方式获取RGBA各通道的值。
    let rgb = byteBuffer[index];
    let red = (rgb >> 0) & 0x000000ff;
    let green = (rgb >> 8) & 0x000000ff;
    let blue = (rgb >> 16) & 0x000000ff;
    let alpha = (rgb >> 24) & 0x000000ff;
    // 加权平均算法,获取灰度值。
    let gray = (0.299 * red + 0.587 * green + 0.114 * blue);
    byteBufferTemp[index * 4] = gray;
    byteBufferTemp[index * 4 + 1] = gray;
    byteBufferTemp[index * 4 + 2] = gray;
    byteBufferTemp[index * 4 + 3] = alpha;
  }
  return byteBufferTemp;
}

开启图片处理线程,将像素做灰度化。

taskpool.execute(group, taskpool.Priority.HIGH).then((res: Array<Object>) => {
   //  结果数组汇总处理,重新编码为图片。
    console.info('execute res success', res.length);
    let byteBufferTemp: Uint8Array = new Uint8Array(new ArrayBuffer(width * height * 4));
    let offset: number = 0;
    for (let index = 0; index < res.length; index++) {
      const element = res[index] as Uint8Array;
      byteBufferTemp.set(element, offset);
      offset += element.length;
    }
    let color: ArrayBuffer = byteBufferTemp.buffer as ArrayBuffer;
    let opts: image.InitializationOptions =
      {
        editable: true,
        pixelFormat: pixelMap.getImageInfoSync().pixelFormat,
        size: { height: height, width: width }
      };
    this.pixelMapTemp = image.createPixelMapSync(color, opts);
    console.info('execute group success');
  });
})

完整代码:

组件引用

import { GrayView } from 'xx';

@Entry
@Component
struct Index {
  build() {
    Column() {
      GrayView2()
    }
    .height('100%')
    .width('100%')
  }
}

GrayView & GrayView2

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

@Component
export struct GrayView2 {
  @State isGray: boolean = false;

  build() {
    Column(){
      Button('grayscale:开启灰度效果').onClick(()=>{
        this.isGray = true
      }).margin({bottom:10})
      Image($r('app.media.yd')).backgroundColor(Color.Pink).width('50%').grayscale(this.isGray?1:0)
      GrayView()
    }.justifyContent(FlexAlign.Center)
    .height('100%')
    .width('100%')
  }
}

@Concurrent
function imageProcessing(dataSlice: ArrayBuffer): Uint8Array {
  // 图像灰度化处理操作
  let byteBuffer: Uint32Array = new Uint32Array(dataSlice);
  let byteBufferTemp: Uint8Array = new Uint8Array(new ArrayBuffer(byteBuffer.length * 4));
  for (let index = 0; index < byteBuffer.length; index++) {
    // 通过移位方式获取RGBA各通道的值。
    let rgb = byteBuffer[index];
    let red = (rgb >> 0) & 0x000000ff;
    let green = (rgb >> 8) & 0x000000ff;
    let blue = (rgb >> 16) & 0x000000ff;
    let alpha = (rgb >> 24) & 0x000000ff;
    // 加权平均算法,获取灰度值。
    let gray = (0.299 * red + 0.587 * green + 0.114 * blue);
    byteBufferTemp[index * 4] = gray;
    byteBufferTemp[index * 4 + 1] = gray;
    byteBufferTemp[index * 4 + 2] = gray;
    byteBufferTemp[index * 4 + 3] = alpha;
  }
  return byteBufferTemp;
}

@Component
export struct GrayView {
  @State pixelMap: image.PixelMap | undefined = undefined;
  @State pixelMapTemp: image.PixelMap | undefined = undefined;
  
  pixelMapGrayScale(pixelMap: PixelMap) {
    // 读取pixelMap的像素数据
    let width = pixelMap.getImageInfoSync().size.width;
    let height = pixelMap.getImageInfoSync().size.height;
    let readBuffer: ArrayBuffer = new ArrayBuffer(width * height * 4);
    pixelMap.readPixelsToBufferSync(readBuffer);
    // 分成四段并发调度
    let number: number = 4 * Math.ceil(width * height / 4);
    let buffer1: ArrayBuffer = readBuffer.slice(0, number);
    let buffer2: ArrayBuffer = readBuffer.slice(number, number * 2);
    let buffer3: ArrayBuffer = readBuffer.slice(number * 2, number * 3);
    let buffer4: ArrayBuffer = readBuffer.slice(number * 3);

    let group: taskpool.TaskGroup = new taskpool.TaskGroup();
    group.addTask(imageProcessing, buffer1);
    group.addTask(imageProcessing, buffer2);
    group.addTask(imageProcessing, buffer3);
    group.addTask(imageProcessing, buffer4);

    taskpool.execute(group, taskpool.Priority.HIGH).then((res: Array<Object>) => {
      //  结果数组汇总处理,重新编码为图片。
      console.info('execute res success', res.length);
      let byteBufferTemp: Uint8Array = new Uint8Array(new ArrayBuffer(width * height * 4));
      let offset: number = 0;
      for (let index = 0; index < res.length; index++) {
        const element = res[index] as Uint8Array;
        byteBufferTemp.set(element, offset);
        offset += element.length;
      }
      let color: ArrayBuffer = byteBufferTemp.buffer as ArrayBuffer;
      let opts: image.InitializationOptions =
        {
          editable: true,
          pixelFormat: pixelMap.getImageInfoSync().pixelFormat,
          size: { height: height, width: width }
        };
      this.pixelMapTemp = image.createPixelMapSync(color, opts);
      console.info('execute group success');
    });
  }

  aboutToAppear(): void {
    //测试:资源图片转为pixelMap
    this.pixelMap = this.getPixmapFromMediaSync($r('app.media.yd'));
  }

  // 通过media目录下的文件名称创建pixelMap。
  getPixmapFromMediaSync(resource: Resource): image.PixelMap {
    const context = this.getUIContext().getHostContext() as common.UIAbilityContext;
    const resourceMgr = context.resourceManager;
    const fileData = resourceMgr.getMediaContentSync(resource.id);
    const imageSource = image.createImageSource(fileData.buffer);
    const pixelMap = imageSource.createPixelMapSync();
    imageSource.release();
    return pixelMap;
  }

  build() {
    Row() {
      Column() {
        Text('原图')
        Image(this.pixelMap)
          .objectFit(ImageFit.Contain)
          .width('50%')
          .margin({
            bottom: 10,
            left: 5,
            right: 5
          })
        Text('灰度图')
        Image(this.pixelMapTemp)
          .objectFit(ImageFit.Contain)
          .width('50%')
          .margin({
            top: 10,
            left: 5,
            right: 5
          })
        Button('TaskGroup:像素数据开启灰度效果')
          .backgroundColor('#0D9FFB')
          .margin({
            top: 10,
            bottom: 10,
            left: 5,
            right: 5
          })
          .onClick(() => {
            this.pixelMapGrayScale(this.pixelMap as image.PixelMap);
          })
      }
      .width('100%')
    }
    .height('100%')
  }
}

相关文档:

更多关于HarmonyOS鸿蒙Next中如何给图片设置灰度效果?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS鸿蒙Next中,可通过PixelMapcreatePixelMapWithFilter方法,使用Filter类中的GRAYSCALE滤镜直接为图片设置灰度效果。具体步骤包括:先获取图片资源,转换为PixelMap对象,然后应用灰度滤镜处理。

在HarmonyOS Next中,可以通过ArkUI的图片处理能力,使用ImageFilter轻松实现图片灰度效果。

核心方法是使用ImageFilter.grayscale()滤镜。具体实现有两种常用方式:

1. 在Image组件中直接应用滤镜:

Image($r('app.media.myImage'))
  .width(200)
  .height(200)
  .imageFilter(ImageFilter.grayscale()) // 应用灰度滤镜

2. 使用自定义组件封装滤镜效果:

@Component
struct GrayImage {
  @Prop src: Resource
  @State filter: ImageFilter = ImageFilter.grayscale()

  build() {
    Image(this.src)
      .imageFilter(this.filter)
  }
}

关键说明:

  • ImageFilter.grayscale()会将彩色图像转换为灰度图像,转换系数遵循标准的亮度公式
  • 滤镜效果会实时渲染,支持动画过渡效果
  • 可与其他滤镜链式组合,如模糊、色彩调整等
  • 性能经过优化,适合列表等高频渲染场景

此方法适用于所有Image组件支持的图片资源类型,包括网络图片和本地资源。

回到顶部