鸿蒙采用Worker多线程实现图片滤镜处理 - 教程

1、实现流程

在这里插入图片描述
在这里插入图片描述

2、伪代码实现

Step 1:创建项目与配置 Worker
新建 Stage 模型项目(DevEco Studio 4.0+),确保 module.json5 中声明 Worker 脚本路径(子线程脚本存放位置):

// entry/src/main/module.json5
{
"module": {
"name": "entry",
"type": "entry",
"workers": [
"ets/workers/ImageFilterWorker.ts" // 声明Worker脚本路径
],
"abilities": [/* ... */]
}
}

Step 2:编写 Worker 子线程脚本(滤镜处理逻辑)
创建 entry/src/main/ets/workers/ImageFilterWorker.ts,实现图片像素处理(以 灰度化滤镜 为例,CPU 密集型任务):

// ImageFilterWorker.ts(Worker子线程脚本)
import worker, { ThreadWorkerGlobalScope, MessageEvents
} from '@ohos.worker';
// 获取Worker全局作用域
const workerPort: ThreadWorkerGlobalScope = worker.workerPort;
// 监听主线程发送的图片处理任务
workerPort.onmessage = (e: MessageEvents) =>
{
const { cmd, pixelData, width, height
} = e.data;
// 接收图片数据、宽高、命令
try {
let processedData: Uint8ClampedArray;
switch (cmd) {
case 'grayscale': // 灰度化滤镜
processedData = grayscaleFilter(pixelData, width, height);
break;
case 'blur': // 模拟模糊滤镜(简化版)
processedData = blurFilter(pixelData, width, height);
break;
default:
throw new Error(`不支持的滤镜类型: ${cmd
}`);
}
// 将处理后的像素数据发送回主线程(通过ArrayBuffer)
workerPort.postMessage({
status: 'success',
data: processedData.buffer, // 传递ArrayBuffer
width,
height
});
} catch (error) {
// 错误信息发送回主线程
workerPort.postMessage({ status: 'error', message: error.message
});
}
};
/**
* 灰度化滤镜算法:将RGB像素转为灰度值(Y = 0.299*R + 0.587*G + 0.114*B)
* @param pixelData 原始像素数据(Uint8ClampedArray,格式:[R, G, B, A, R, G, B, A, ...])
* @param width 图片宽度
* @param height 图片高度
*/
function grayscaleFilter(
pixelData: Uint8ClampedArray,
width: number,
height: number
): Uint8ClampedArray {
const processedData = new Uint8ClampedArray(pixelData.length);
// 新数组存储结果
for (let i = 0; i < pixelData.length; i += 4) {
const r = pixelData[i];
// 红色通道
const g = pixelData[i + 1];
// 绿色通道
const b = pixelData[i + 2];
// 蓝色通道
const a = pixelData[i + 3];
// 透明度通道(保持不变)
// 计算灰度值
const gray = Math.round(0.299 * r + 0.587 * g + 0.114 * b);
// 写入新像素数据(R=G=B=gray,透明度不变)
processedData[i] = gray;
processedData[i + 1] = gray;
processedData[i + 2] = gray;
processedData[i + 3] = a;
}
return processedData;
}
/** 简化版模糊滤镜(示例,实际可替换为高斯模糊等复杂算法) */
function blurFilter(
pixelData: Uint8ClampedArray,
width: number,
height: number
): Uint8ClampedArray {
// 此处省略复杂算法,实际项目可引入第三方滤镜库(如通过NDK调用C++实现的高性能模糊算法)
return pixelData;
// 仅作示例,返回原始数据
}

Step 3:主线程实现(UI + 图片选择 + Worker 通信)
创建页面 entry/src/main/ets/pages/ImageFilterPage.ts,实现用户交互和 Worker 管理:

// ImageFilterPage.ts(主线程页面)
import worker, { ThreadWorker, MessageEvents
} from '@ohos.worker';
import promptAction from '@ohos.promptAction';
import filePicker from '@ohos.file.picker';
import image from '@ohos.multimedia.image';
import fs from '@ohos.file.fs';
@Entry
@Component
struct ImageFilterPage {
@State originalImage: PixelMap | null = null;
// 原始图片PixelMap
@State filteredImage: PixelMap | null = null;
// 处理后图片PixelMap
@State isProcessing: boolean = false;
// 处理中状态(控制按钮禁用)
private worker: ThreadWorker | null = null;
// Worker实例
// 页面加载时创建Worker
aboutToAppear() {
this.createWorker();
}
// 页面销毁时终止Worker
aboutToDisappear() {
this.terminateWorker();
}
// 创建Worker实例
private createWorker() {
try {
this.worker = new worker.ThreadWorker('entry/ets/workers/ImageFilterWorker.ts');
// 监听Worker返回的结果
this.worker.onmessage = (e: MessageEvents) =>
this.handleWorkerResult(e);
// 监听Worker错误
this.worker.onerror = (e) =>
{
promptAction.showToast({ message: `Worker错误: ${e.message
}`
});
this.isProcessing = false;
};
} catch (error) {
console.error('创建Worker失败:', error);
promptAction.showToast({ message: 'Worker初始化失败'
});
}
}
// 终止Worker
private terminateWorker() {
if (this.worker) {
this.worker.terminate();
this.worker = null;
}
}
// 处理Worker返回的结果(处理后的图片数据)
private async handleWorkerResult(e: MessageEvents) {
this.isProcessing = false;
// 结束处理状态
if (e.data.status === 'success') {
const { data: buffer, width, height
} = e.data;
// 将Worker返回的ArrayBuffer转为PixelMap
this.filteredImage = await this.bufferToPixelMap(new Uint8ClampedArray(buffer), width, height);
promptAction.showToast({ message: '滤镜处理完成'
});
} else {
promptAction.showToast({ message: `处理失败: ${e.data.message
}`
});
}
}
// 选择本地图片(通过文件选择器)
private async selectImage() {
try {
// 调用系统文件选择器,选择图片文件
const result = await filePicker.selectFile({
type: filePicker.Types.IMAGE,
count: 1 // 仅选择1张图片
});
if (result.length === 0) return;
// 读取选中的图片文件,转为PixelMap(用于UI显示)
const uri = result[0].uri;
// 图片文件URI
const file = await fs.open(uri, fs.OpenMode.READ_ONLY);
const pixelMap = await image.createPixelMap(file.fd);
await fs.close(file.fd);
this.originalImage = pixelMap;
// 显示原始图片
this.filteredImage = null;
// 重置处理后图片
} catch (error) {
console.error('选择图片失败:', error);
promptAction.showToast({ message: '选择图片失败'
});
}
}
// 启动滤镜处理(通过Worker子线程)
private async startFilterProcessing(filterType: 'grayscale' | 'blur') {
if (!this.originalImage || !this.worker || this.isProcessing) return;
this.isProcessing = true;
// 标记处理中
promptAction.showToast({ message: `正在应用${filterType === 'grayscale' ? '灰度' : '模糊'
}滤镜...`
});
try {
// 1. 将原始图片PixelMap转为RGBA像素数据(Uint8ClampedArray)
const pixelData = await this.pixelMapToPixelData(this.originalImage);
const { width, height
} = await this.originalImage.getImageInfo();
// 2. 发送任务给Worker子线程(传递像素数据、宽高、滤镜类型)
this.worker.postMessage({
cmd: filterType, // 任务类型:'grayscale'或'blur'
pixelData: pixelData.buffer, // 像素数据ArrayBuffer
width,
height
});
} catch (error) {
console.error('处理图片失败:', error);
this.isProcessing = false;
promptAction.showToast({ message: '处理图片失败'
});
}
}
// PixelMap转为RGBA像素数据(Uint8ClampedArray:[R, G, B, A, R, G, B, A, ...])
private async pixelMapToPixelData(pixelMap: PixelMap): Promise<Uint8ClampedArray>
  {
  const imageInfo = await pixelMap.getImageInfo();
  const bufferSize = imageInfo.size;
  // 像素数据总字节数(width * height * 4,4通道RGBA)
  const pixelBuffer = new ArrayBuffer(bufferSize);
  await pixelMap.readPixelsToBuffer(pixelBuffer);
  // 将PixelMap像素读取到ArrayBuffer
  return new Uint8ClampedArray(pixelBuffer);
  // 转为可操作的类型化数组
  }
  // 接收Worker返回的处理结果,转为PixelMap并更新UI
  private async handleWorkerResult(e: MessageEvents) {
  if (e.data.status !== 'success') return;
  const { data: buffer, width, height
  } = e.data;
  const pixelData = new Uint8ClampedArray(buffer);
  // 从ArrayBuffer恢复像素数据
  // 将像素数据转为PixelMap(用于UI显示)
  const pixelMap = await image.createPixelMap(
  pixelData,
  { width, height, pixelFormat: image.PixelFormat.RGBA_8888
  }
  );
  this.filteredImage = pixelMap;
  // 更新处理后图片
  }
  build() {
  Column({ space: 16
  }) {
  Text('图片滤镜处理(Worker多线程示例)')
  .fontSize(20)
  .fontWeight(FontWeight.Bold);
  // 原始图片区域
  Column() {
  Text('原始图片')
  .fontSize(16)
  .margin(4);
  if (this.originalImage) {
  Image(this.originalImage)
  .width(300)
  .height(300)
  .objectFit(ImageFit.Contain);
  } else {
  Text('未选择图片')
  .width(300)
  .height(300)
  .backgroundColor('#f5f5f5')
  .textAlign(TextAlign.Center)
  .fontColor('#999');
  }
  }
  // 操作按钮区域
  Row({ space: 12
  }) {
  Button('选择图片')
  .onClick(() =>
  this.selectImage())
  .backgroundColor('#007DFF');
  Button('灰度滤镜')
  .onClick(() =>
  this.startFilterProcessing('grayscale'))
  .backgroundColor('#007DFF')
  .enabled(!this.isProcessing);
  // 处理中禁用按钮
  Button('模糊滤镜')
  .onClick(() =>
  this.startFilterProcessing('blur'))
  .backgroundColor('#007DFF')
  .enabled(!this.isProcessing);
  }
  // 处理后图片区域
  Column() {
  Text('处理后图片')
  .fontSize(16)
  .margin(4);
  if (this.filteredImage) {
  Image(this.filteredImage)
  .width(300)
  .height(300)
  .objectFit(ImageFit.Contain);
  } else if (this.originalImage &&
  !this.isProcessing) {
  Text('点击滤镜按钮开始处理')
  .width(300)
  .height(300)
  .backgroundColor('#f5f5f5')
  .textAlign(TextAlign.Center)
  .fontColor('#999');
  }
  }
  }
  .width('100%')
  .height('100%')
  .padding(16)
  .justifyContent(FlexAlign.Center);
  }
  }

3、核心优势与注意事项

在这里插入图片描述

4、多Worker线程交互

在这里插入图片描述
在这里插入图片描述

采用主线程作为中介,接收a的worker线程的数据,然后b的worker线程从主线程中去获取数据。

posted on 2025-10-23 10:24  ljbguanli  阅读(6)  评论(0)    收藏  举报