• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 使用ImageReceiver完成图片接收
2图片接收类ImageReceiver用于获取组件surface id,接收最新的图片和读取下一张图片,以及释放ImageReceiver实例。<br/>
3> **说明:**
4>- Receiver作为消费者,需要有对应的生产者提供数据才能实现完整功能。常见的生产者是相机的拍照流或预览流。<br/>
5
6ImageReceiver可以接收相机预览流中的图片,实现[双路预览](../camera/camera-dual-channel-preview.md)。<br/>
7
8ImageReceiver信息相关API的详细介绍请参见[API参考](../../reference/apis-image-kit/js-apis-image.md#imagereceiver9)。
9
10## 开发步骤
11
12创建ImageReceiver对象,获取SurfaceId创建预览流,注册图像监听,按需处理预览流每帧图像。
13
141. 创建ImageReceiver对象,通过ImageReceiver对象可获取预览流SurfaceId。
15
16    ```ts
17    import { image } from '@kit.ImageKit';
18    let imageWidth: number = 1920; // 请使用设备支持profile的size的宽。
19    let imageHeight: number = 1080; // 请使用设备支持profile的size的高。
20
21    async function initImageReceiver():Promise<void>{
22      // 创建ImageReceiver对象。
23      let size: image.Size = { width: imageWidth, height: imageHeight };
24      let imageReceiver = image.createImageReceiver(size, image.ImageFormat.JPEG, 8);
25      // 获取预览流SurfaceId。
26      let imageReceiverSurfaceId = await imageReceiver.getReceivingSurfaceId();
27      console.info(`initImageReceiver imageReceiverSurfaceId:${imageReceiverSurfaceId}`);
28    }
29    ```
30
312. 注册监听处理预览流每帧图像数据:通过ImageReceiver组件中imageArrival事件监听获取底层返回的图像数据,详细的API说明请参考[Image API参考](../../reference/apis-image-kit/js-apis-image.md)。
32
33    ```ts
34    import { BusinessError } from '@kit.BasicServicesKit';
35    import { image } from '@kit.ImageKit';
36
37    function onImageArrival(receiver: image.ImageReceiver): void {
38      // 注册imageArrival监听。
39      receiver.on('imageArrival', () => {
40        // 获取图像。
41        receiver.readNextImage((err: BusinessError, nextImage: image.Image) => {
42          if (err || nextImage === undefined) {
43            console.error('readNextImage failed');
44            return;
45          }
46          // 解析图像内容。
47          nextImage.getComponent(image.ComponentType.JPEG, async (err: BusinessError, imgComponent: image.Component) => {
48            if (err || imgComponent === undefined) {
49              console.error('getComponent failed');
50            }
51            if (imgComponent.byteBuffer) {
52              // 详情见下方解析图片buffer数据参考,本示例以方式一为例。
53              let width = nextImage.size.width; // 获取图片的宽。
54              let height = nextImage.size.height; // 获取图片的高。
55              let stride = imgComponent.rowStride; // 获取图片的stride。
56              console.debug(`getComponent with width:${width} height:${height} stride:${stride}`);
57              // stride与width一致。
58              if (stride == width) {
59                let pixelMap = await image.createPixelMap(imgComponent.byteBuffer, {
60                  size: { height: height, width: width },
61                  srcPixelFormat: 8,
62                })
63              } else {
64                // stride与width不一致。
65                const dstBufferSize = width * height * 1.5
66                const dstArr = new Uint8Array(dstBufferSize)
67                for (let j = 0; j < height * 1.5; j++) {
68                  const srcBuf = new Uint8Array(imgComponent.byteBuffer, j * stride, width)
69                  dstArr.set(srcBuf, j * width)
70                }
71                let pixelMap = await image.createPixelMap(dstArr.buffer, {
72                  size: { height: height, width: width },
73                  srcPixelFormat: 8,
74                })
75              }
76            } else {
77              console.error('byteBuffer is null');
78            }
79            // 确保当前buffer没有在使用的情况下,可进行资源释放。
80            // 如果对buffer进行异步操作,需要在异步操作结束后再释放该资源(nextImage.release())。
81            nextImage.release();
82          })
83        })
84      })
85    }
86    ```
87
88
89    通过 [image.Component](../../reference/apis-image-kit/js-apis-image.md#component9) 解析图片buffer数据参考:
90
91    > **注意:**
92    > 需要确认图像的宽width是否与行距rowStride一致,如果不一致可参考以下方式处理:
93
94    方式一:去除imgComponent.byteBuffer中stride数据,拷贝得到新的buffer,调用不支持stride的接口处理buffer。
95
96    ```ts
97    // 以NV21为例(YUV_420_SP格式的图片)YUV_420_SP内存计算公式:长x宽+(长x宽)/2。
98    const dstBufferSize = width * height * 1.5;
99    const dstArr = new Uint8Array(dstBufferSize);
100    // 逐行读取buffer数据。
101    for (let j = 0; j < height * 1.5; j++) {
102      // imgComponent.byteBuffer的每行数据拷贝前width个字节到dstArr中。
103      const srcBuf = new Uint8Array(imgComponent.byteBuffer, j * stride, width);
104      dstArr.set(srcBuf, j * width);
105    }
106    let pixelMap = await image.createPixelMap(dstArr.buffer, {
107      size: { height: height, width: width }, srcPixelFormat: 8
108    });
109    ```
110
111    方式二:根据stride*height创建pixelMap,然后调用pixelMap的cropSync方法裁剪掉多余的像素。
112
113    ```ts
114    // 创建pixelMap,width宽传行距stride的值。
115    let pixelMap = await image.createPixelMap(imgComponent.byteBuffer, {
116      size:{height: height, width: stride}, srcPixelFormat: 8});
117    // 裁剪多余的像素。
118    pixelMap.cropSync({size:{width:width, height:height}, x:0, y:0});
119    ```
120
121    方式三:将原始imgComponent.byteBuffer和stride信息一起传给支持stride的接口处理。