1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
//build: 20240524
//摄像头取图组件,主要用于获取二维码图像然后利用dxDecoder组件来解析二维码图像
//依赖组件:dxDriver,dxCommon,dxStd,dxMap
import { capturerClass } from './libvbar-m-dxcapturer.so'
import * as os from "os"
import std from './dxStd.js'
import dxMap from './dxMap.js'
import dxCommon from './dxCommon.js';
import bus from './dxEventBus.js'
const capturerObj = new capturerClass();
const map = dxMap.get('default')
const capturer = {}
 
/**
 * 取图模块初始化
 * @param {object} options 配置参数,大部分可以用默认值
 * @param {string} options.path                 必填,图像采集设备路径,每种设备有差异,比如DW200对应的值是'/dev/video11', M500对应的'/dev/video0'
 * @param {number} options.width                非必填,图像宽,缺省是0
 * @param {number} options.height               非必填,图像高,缺省是0
 * @param {number} options.widthbytes           非必填,每个像素所占字节数 GREY : 1, YUV : 2,DW200缺省是1 VF203缺省是2
 * @param {number} options.pixel_format          非必填,像素格式, 缺省是1497715271表示V4L2_PIX_FMT_GREY
 * @param {number} options.max_channels          非必填,最大支持的同步输出channel数量,缺省是3
 * @param {number} options.rotation             非必填,旋转角度,缺省是90
 * @param {number} options.frame_num             非必填,帧编号,缺省是3
 * @param {number} options.preview_enable        非必填,预览是否启用,缺省是3
 * @param {number} options.preview_left          非必填,预览框左边框坐标,缺省是0
 * @param {number} options.preview_top           非必填,预览框上边框坐标,缺省是0
 * @param {number} options.preview_width         非必填,预览框宽度,VF203缺省是1024
 * @param {number} options.preview_height        非必填,预览框高度,VF203缺省是600
 * @param {number} options.preview_rotation      非必填,预览框旋转角度,缺省是0
 * @param {number} options.preview_mode          非必填,预览框模式,缺省是2
 * @param {number} options.preview_screen_index   非必填,预览框索引,缺省是0
 * @param {string} id 句柄id,非必填(若初始化多个实例需要传入唯一id)
 */
capturer.init = function (options, id) {
    if (options.path === undefined || options.path === null || options.path.length < 1) {
        throw new Error("dxCapturer.init: 'path' parameter should not be null or empty")
    }
    let pointer = capturerObj.init(options);
    if (!pointer) {
        throw new Error("dxCapturer.init: init failed")
    }
    dxCommon.handleId("capturer", id, pointer)
}
 
/**
 * 回调注册
 * @param {string} id 句柄id,非必填(需保持和init中的id一致)
 * @param {string} capturerDogId 摄像头看门狗句柄id,非必填
 * @returns true/false
 */
capturer.registerCallback = function (id, capturerDogId) {
    let pointer = dxCommon.handleId("capturer", id)
    let capturerDogPointer = null;
    print("capturerDogPointer:", capturerDogPointer)
    if(capturerDogId){
        capturerDogPointer = dxCommon.handleId("watchdog", capturerDogId)
        print("capturerDogPointer:", capturerDogPointer)
    }
    return capturerObj.registerCallback(pointer, "decoderCapturerImage", capturerDogPointer)
}
/**
 * 获取基本信息
 * @param {string} id 句柄id,非必填(需保持和init中的id一致)
 * @returns 格式类似: {"width":800,"widthbytes":1,"height":600,"name":{},"type":6}
 */
capturer.getInfo = function (id) {
    let pointer = dxCommon.handleId("capturer", id)
    return capturerObj.getInfo(pointer)
}
/**
 * 关闭取图模块
 * @param {string} id 句柄id,非必填(需保持和init中的id一致)
 * @returns true/false
 */
capturer.close = function (id) {
    let pointer = dxCommon.handleId("capturer", id)
    return capturerObj.close(pointer)
}
 
/**
 * 获取图像数据,轮询可调用此接口,类似capturer.msgReceive方法的获取,若使用这个方法,必须手动销毁获取的image指针
 * @param {string} id 句柄id,非必填(需保持和init中的id一致)
 * @returns image指针
 */
capturer.readImage = function (id) {
    let pointer = dxCommon.handleId("capturer", id)
    return capturerObj.readImage(pointer)
}
 
/**
 * 销毁获取的image指针,与capturer.readImage方法共同使用
 * @param {number} image image指针,必填
 * @returns true/false
 */
capturer.destroyImage = function (image) {
    return capturerObj.destroyImage(image)
}
 
/**
 * 使能/关闭capture预览
 * @param {number}  摄像头启用/禁用,必填
 * @param {string} id 句柄id,非必填(需保持和init中的id一致)
 * @returns true/false
 */
capturer.capturerEnable = function (enable, id) {
    if (enable == null) {
        throw new Error("nirEnable should not be null or empty")
    }
    let pointer = dxCommon.handleId("capturer", id)
    return capturerObj.capturerPreviewEnable(pointer, enable)
}
 
/**
 * @brief 图片文件转image
 * @param {string} fileName 文件路径
 * @param {number} type 图像类型 IMAGE_YUV420P = 0, 1IMAGE_YUV420SP = 1,
 * @return imageId image句柄id
 */
capturer.pictureFileToImage = function (fileName, type) {
    if (fileName == null) {
        throw new Error("fileName should not be null or empty")
    }
    if (type == null) {
        throw new Error("type should not be null or empty")
    }
    return capturerObj.pictureFileToImage(fileName, type)
}
 
/**
 * @brief 图片裁剪
 * @param {string} src_pic 源文件路径
 * @param {number} width 图像宽度
 * @param {number} height 图像高度
 * @param {string} out_pic 裁剪后的图片路径
 * @return ture/false
 */
capturer.pictureCropping = function (src_pic, width, height, out_pic) {
    if (src_pic == null) {
        throw new Error("src_pic should not be null or empty")
    }
    if (width == null) {
        throw new Error("width should not be null or empty")
    }
    if (height == null) {
        throw new Error("height should not be null or empty")
    }
    if (out_pic == null) {
        throw new Error("out_pic should not be null or empty")
    }
    return capturerObj.pictureCropping(src_pic, width, height, out_pic)
}
 
/**
 * 图片数据转image
 * @param {string}  base64Data 图片base64数据
 * @param {number}  dataLen 数据长度dataLen
 * @param {number}  type 图像类型 IMAGE_YUV420P = 0, 1IMAGE_YUV420SP = 1,
 * @returns imageId image句柄id
 */
capturer.pictureDataToImage = function (base64Data, dataLen, type) {
    if (base64Data == null) {
        throw new Error("base64Data should not be null or empty")
    }
    if (dataLen == null) {
        throw new Error("dataLen should not be null or empty")
    }
    if (type == null) {
        throw new Error("type should not be null or empty")
    }
    return capturerObj.pictureDataToImage(base64Data, dataLen, type)
}
 
// image, (enum image_type)type, (enum vbar_drv_picture_type)save_type, quality, pic_data, data_len
/**
 * image 转图片数据
 * @param {number}  imageId image图片句柄id
 * @param {number}  type 图像类型 IMAGE_YUV420P = 0, 1IMAGE_YUV420SP = 1,
 * @param {number}  saveType 转换后的图片类型 TYPE_JPEG = 0, TYPE_BMP = 1, TYPE_PNG = 2, TYPE_UNKNOE = 3;
 * @param {number}  quality 压缩比,jpeg 0-100, png 无损压缩无需此参数, bmp位图无需此参数
 * @returns 图片base64数据
 */
capturer.imageToPictureData = function (imageId, type, saveType, quality) {
    if (imageId == null) {
        throw new Error("imageId should not be null or empty")
    }
    if (type == null) {
        throw new Error("type should not be null or empty")
    }
    if (saveType == null) {
        throw new Error("saveType should not be null or empty")
    }
    if (quality == null) {
        throw new Error("quality should not be null or empty")
    }
    return capturerObj.imageToPictureData(imageId, type, saveType, quality)
}
 
/**
 * 转图片文件
 * @param {number}  imageId image图像句柄id
 * @param {string}  type 图像类型 IMAGE_YUV420P = 0, 1IMAGE_YUV420SP = 1,
 * @param {number}  saveType 转换后的图片类型 YPE_JPEG = 0, TYPE_BMP = 1, TYPE_PNG = 2, TYPE_UNKNOE = 3;
 * @param {number}  quality 压缩比,jpeg 0-100, png 无损压缩无需此参数, bmp位图无需此参数
 * @param {number}  savePath 图片保存路径
 * @returns true/false
 */
capturer.imageToPictureFile = function (imageId, type, saveType, quality, savePath) {
    if (imageId == null) {
        throw new Error("imageId should not be null or empty")
    }
    if (type == null) {
        throw new Error("type should not be null or empty")
    }
    if (saveType == null) {
        throw new Error("saveType should not be null or empty")
    }
    if (quality == null) {
        throw new Error("quality should not be null or empty")
    }
    if (savePath == null) {
        throw new Error("savePath should not be null or empty")
    }
    return capturerObj.imageToPictureFile(imageId, type, saveType, quality, savePath)
}
 
/**
* 图片缩放
* @param {number}   imageId image图像句柄id
* @param {number}   width  目标图像宽度
* @param {number}   height 目标图像高度
* @param {number}   mode       滤波器模式
*                   FILTER_MODE_NONE     不进行滤波,直接采样;速度最快。
*                   FILTER_MODE_LINEAR   只沿水平方向滤波。
*                   FILTER_MODE_BILINEAR 双线性滤波;比盒滤波更快,但在缩小图像时质量较低。
*                   FILTER_MODE_BOX      盒滤波;提供最高的缩放质量
*/
capturer.imageResizeResolution = function (imageId, width, height, mode) {
    if (imageId == null) {
        throw new Error("imageId should not be null or empty")
    }
    if (width == null) {
        throw new Error("width should not be null or empty")
    }
    if (height == null) {
        throw new Error("height should not be null or empty")
    }
    if (mode == null) {
        throw new Error("mode should not be null or empty")
    }
    return capturerObj.imageResizeResolution(imageId, width, height, mode)
}
 
/**
 * 判断capturer消息队列是否为空
 * @param {string} id 句柄id,非必填(需保持和init中的id一致)
 * @returns true/false
 */
capturer.msgIsEmpty = function (id) {
    let pointer = dxCommon.handleId("capturer", id)
    return capturerObj.msgIsEmpty(pointer)
}
 
/**
 * 从capturer消息队列中读取数据
 * @param {string} id 句柄id,非必填(需保持和init中的id一致)
 * @returns image指针
 */
capturer.msgReceive = function (id) {
    let pointer = dxCommon.handleId("capturer", id)
    return capturerObj.msgReceive(pointer)
}
 
/**
 * 查询capturer消息队列大小
 * @param {string} id 句柄id,非必填(需保持和init中的id一致)
 * @returns size
 */
capturer.msgQueueSize = function (id) {
    let pointer = dxCommon.handleId("capturer", id)
    return capturerObj.msgQueueSize(pointer)
}
 
capturer.RECEIVE_MSG = '__capturer__MsgReceive'
 
/**
 * 用于简化capturer组件的使用,把capturer封装在这个worker里,使用者只需要订阅eventbus的事件就可以监听capturer
 * @param {object} options capturer组件参数,参考capturer.init,必填
 * @param {string} options.id  句柄id,非必填(若初始化多个实例需要传入唯一id)
 */
capturer.run = function (options) {
    if (options === undefined || options.length === 0) {
        throw new Error("dxcapturer.run:'options' parameter should not be null or empty")
    }
    if (options.id === undefined || options.id === null || typeof options.id !== 'string') {
        // 句柄id
        options.id = ""
    }
    if (options.path === undefined || options.path === null || options.path.length <= 0) {
        throw new Error("dxcapturer.run:'path' should not be null or empty")
    }
    let oldfilepre = '/app/code/dxmodules/capturerWorker'
    let content = std.loadFile(oldfilepre + '.js').replace("{{id}}", options.id)
    let newfile = oldfilepre + options.id + '.js'
    std.saveFile(newfile, content)
    let init = map.get("__capturer__run_init" + options.id)
    if (!init) {//确保只初始化一次
        map.put("__capturer__run_init" + options.id, options)
        bus.newWorker(options.id || '__capturer', newfile)
    }
}
 
/**
 * 如果capturer单独一个线程,可以直接使用run函数,会自动启动一个线程,
 * 如果想加入到其他已有的线程,可以使用以下封装的函数
 */
capturer.worker = {
    //在while循环前
    beforeLoop: function (options) {
        capturer.init(options, options.id)
        capturer.registerCallback(options.id)
    },
    //在while循环里
    loop: function (options) {
        if (!capturer.msgIsEmpty(options.id)) {
            let res = capturer.msgReceive(options.id);
            if (options.id === undefined || options.id === null || typeof options.id !== 'string') {
                // 句柄id
                options.id = ""
            }
            bus.fire(capturer.RECEIVE_MSG + options.id, res)
        }
    }
}
 
export default capturer;