图片数据作为SharedArrayBuffer对象通过线程间通信传输,使用图片处理服务下的writeBufferToPixels将图片数据写入PixelMap,通过图片编码器ImagePacker重新生成的图片文件显示纯黑,与原始图片不符。
原始图片如下:

异常图片如下:

问题代码示例参考如下:
let callback = async (eventData: emitter.EventData): Promise<void> => { if (eventData.data != null) { // eventData.data.result数据类型为SharedArrayBuffer let pixelByte: Uint8Array = new Uint8Array(eventData.data.result) let pixelMap = image.createPixelMapSync({ size: { width, height }, srcPixelFormat: image.PixelMapFormat.RGBA_8888, pixelFormat: image.PixelMapFormat.RGBA_8888, }) for (let index = 0; index < 100; index++) { hilog.debug(0x00, "getImagePixelByTexture", `${pixelByte[index]}`) } await pixelMap.writeBufferToPixels(pixelByte.buffer) resolve(pixelMap) } else { resolve(null) } }
报错日志参考如下:
C02B05/PixelMapNapi us.pinguo...era_ohos E colors mismatch C02B05/PixelMapNapi us.pinguo...era_ohos E fail to get buffer info
根据报错日志获取buffer信息失败(fail to get buffer info),而buffer数据来源于eventData.data.result,是线程间通信传输的数据,在业务逻辑中是一个SharedArrayBuffer对象,判断通过writeBufferToPixels读取缓冲区中数据写入PixelMap时,该buffer不符合想要的数据类型预期。
需要将SharedArrayBuffer建立Int32Array类型的视图读取,再将Int32Array转为Uint8Array类型,通过Uint8Array类型得到的buffer数据为正确的二进制图像像素数据格式。
let callback = async (eventData: emitter.EventData): Promise<void> => { if (eventData.data != null) { let sab: SharedArrayBuffer = eventData.data.result as SharedArrayBuffer; let int32: Int32Array = new Int32Array(sab); let length = int32.length; let uint8Array = new Uint8Array(length * 4); // 每 Int32占用4字节 for (let i = 0; i < length; i++) { let value = int32[i]; uint8Array[i * 4] = value & 0xff; // 最低位字节 uint8Array[i * 4 + 1] = (value >> 8) & 0xff; // 第二低位字节 uint8Array[i * 4 + 2] = (value >> 16) & 0xff; // 第三低位字节 uint8Array[i * 4 + 3] = (value >> 24) & 0xff; // 最高位字节 } let pixelMap = image.createPixelMapSync({ size: { width, height }, srcPixelFormat: image.PixelMapFormat.RGBA_8888, pixelFormat: image.PixelMapFormat.RGBA_8888, }); await pixelMap.writeBufferToPixels(uint8Array.buffer); resolve(pixelMap); } else { resolve(null); } };
完整示例参考如下:
import { BusinessError, emitter } from '@kit.BasicServicesKit'; import { image } from '@kit.ImageKit'; import { fileIo } from '@kit.CoreFileKit'; import { common } from '@kit.AbilityKit'; const getImagePixelByTextureEvent: number = 1; class GLInterface { static getImagePixelByTexture(tid: number, width: number, height: number): Promise<PixelMap | null> { return new Promise<PixelMap | null>((resolve) => { let event: emitter.InnerEvent = { eventId: getImagePixelByTextureEvent }; let callback = async (eventData: emitter.EventData): Promise<void> => { if (eventData.data != null) { let sab: SharedArrayBuffer = eventData.data.result as SharedArrayBuffer; let int32: Int32Array = new Int32Array(sab); let length = int32.length; let uint8Array = new Uint8Array(length * 4); // 每 Int32占用4字节 for (let i = 0; i < length; i++) { let value = int32[i]; uint8Array[i * 4] = value & 0xff; // 最低位字节 uint8Array[i * 4 + 1] = (value >> 8) & 0xff; // 第二低位字节 uint8Array[i * 4 + 2] = (value >> 16) & 0xff; // 第三低位字节 uint8Array[i * 4 + 3] = (value >> 24) & 0xff; // 最高位字节 } let pixelMap = image.createPixelMapSync({ size: { width, height }, srcPixelFormat: image.PixelMapFormat.RGBA_8888, pixelFormat: image.PixelMapFormat.RGBA_8888, }); await pixelMap.writeBufferToPixels(uint8Array.buffer); resolve(pixelMap); } else { resolve(null); } }; emitter.once(event, callback); }); } } @Entry @Component struct Index { pixMap: image.PixelMap | undefined = undefined; context = this.getUIContext().getHostContext() as common.UIAbilityContext; async mainFunc(): Promise<void> { let pixelMap: PixelMap | null = await GLInterface.getImagePixelByTexture(0, 1024, 1024); let packImageByte: ArrayBuffer = await image.createImagePacker().packToData(pixelMap!, { format: 'image/jpeg', quality: 100 }); let file = await fileIo.open(`${this.context.tempDir}/readImage1.jpg`, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE); try { fileIo.writeSync(file.fd, packImageByte); } finally { fileIo.closeSync(file); } } build() { Row() { Column() { Image(this.pixMap) .width(64) .height(64); Button('taskpoolEmitterTest') .onClick(async () => { this.context.resourceManager.getRawFileContent('background.png', (error: BusinessError, value: Uint8Array) => { let pixelBuffer = new Uint8Array(value).buffer as Object as ArrayBuffer; let imageResource = image.createImageSource(pixelBuffer); let imPix = imageResource.createPixelMapSync(); this.pixMap = imPix; let buffer1 = new ArrayBuffer(imPix.getPixelBytesNumber()); imPix.readPixelsToBufferSync(buffer1); let uint8 = new Uint8Array(buffer1); let buffer2 = new SharedArrayBuffer(uint8.length); let int32 = new Int32Array(buffer2); // 将uint8转为uint32 for (let i = 0; i < uint8.length; i += 4) { int32[i/4] = (uint8[i + 0] << 0) | (uint8[i + 1] << 8) | (uint8[i + 2] << 16) | (uint8[i + 3] << 24); } let eventData: emitter.EventData = { data: { 'result': buffer2, } }; let innerEvent: emitter.InnerEvent = { eventId: getImagePixelByTextureEvent, priority: emitter.EventPriority.HIGH }; emitter.emit(innerEvent, eventData); }); this.mainFunc(); }); } .width('100%') .height('100%'); }; } }