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