鸿蒙采用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线程从主线程中去获取数据。
浙公网安备 33010602011771号