//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;
|