IE不支持WebRTC,所以没有办法通过JS接口在浏览器中直接访问USB摄像头。解决的方法就是通过本地启动一个服务去获取摄像头数据,然后发送到IE的web页面上,通过img元素不断刷新来显示,这个在上一篇文章中已经说过。这篇文章是基于上一篇里Node.js的代码,增加条形码扫描功能。
C/C++的封装代码在https://github.com/Dynamsoft/nodejs-barcode。
用于解码的接口是decodeBufferAsync()
。以下是相关的C/C++代码:
void DecodeBufferAsync(const FunctionCallbackInfo<Value>& args) {
if (!createDBR()) {return;}
Isolate* isolate = Isolate::GetCurrent();
Local<Context> context = isolate->GetCurrentContext();
// get arguments
unsigned char* buffer = (unsigned char*) node::Buffer::Data(args[0]); // file stream
int width = args[1]->Int32Value(context).ToChecked(); // image width
int height = args[2]->Int32Value(context).ToChecked(); // image height
int stride = args[3]->Int32Value(context).ToChecked(); // stride
int iFormat = args[4]->Int32Value(context).ToChecked(); // barcode types
Local<Function> cb = Local<Function>::Cast(args[5]); // javascript callback function
String::Utf8Value templateName(isolate, args[6]); // template name
char *pTemplateName = *templateName;
// initialize BarcodeWorker
BarcodeWorker *worker = new BarcodeWorker;
worker->request.data = worker;
worker->callback.Reset(isolate, cb);
worker->iFormat = iFormat;
worker->pResults = NULL;
worker->buffer = buffer;
worker->width = width;
worker->height = height;
worker->bufferType = RGB_BUFFER;
worker->stride = stride;
if (hasTemplate(pTemplateName)) {
// Load the template.
char szErrorMsg[256];
DBR_InitRuntimeSettingsWithString(hBarcode, pTemplateName, CM_OVERWRITE, szErrorMsg, 256);
worker->useTemplate = true;
}
else {
worker->useTemplate = false;
}
uv_queue_work(uv_default_loop(), &worker->request, (uv_work_cb)DetectionWorking, (uv_after_work_cb)DetectionDone);
}
第一个参数是图像数据的指针,所以在JS层要通过getData()
获取buffer:
const vCap = new cv.VideoCapture(0);
var img = vCap.read();
dbr.decodeBufferAsync(img.getData(), img.cols, img.rows, img.step, barcodeTypes, function (err, msg) {
results = msg
}, "");
编译的时候针对不同的平台有一些差别。Linux上通过rpath设置相对路径;Windows上把DLL拷贝到输出目录;mac上把dylib文件拷贝到/usr/local/lib目录下。
binding.gyp
{
"targets": [
{
'target_name': "dbr",
'sources': ["src/dbr.cc"],
"cflags" : [
"-std=c++11"
],
'ldflags': [
"-Wl,-rpath,'$$ORIGIN'"
],
'include_dirs': [
"./"
],
'conditions': [
['OS=="linux"', {
'defines': [
'LINUX_DBR',
],
'libraries': [
"-lDynamsoftBarcodeReader", "-L../platforms/linux"
],
'copies': [
{
'destination': 'build/Release/',
'files': [
'./platforms/linux/libDynamsoftBarcodeReader.so'
]
}
]
}],
['OS=="win"', {
'defines': [
'WINDOWS_DBR',
],
'libraries': [
"-l../platforms/windows/DBRx64.lib"
],
'copies': [
{
'destination': 'build/Release/',
'files': [
'./platforms/windows/**.*'
]
}
]
}],
['OS=="mac"', {
'defines': [
'MAC_DBR',
],
'libraries': [
"-lDynamsoftBarcodeReader", "-L../platforms/macos"
],
'copies': [
{
'destination': '/usr/local/lib/',
'files': [
'./platforms/macos/libDynamsoftBarcodeReader.dylib'
]
}
]
}]
]
}
]
}
包已经发布到npm上。安装前先装好每个平台需要的C/C++编译环境。然后运行下面的命令下载,编译,安装:
npm install -g node-gyp
npm install barcode4nodejs
在服务端调用JS条形码接口,当返回结果的时候画到当前图像上,然后通过jpg编码发送给web客户端:
function capture() {
var frame = wCap.read()
if (frame.empty) {
wCap.reset();
frame = wCap.read();
}
dbr.decodeBufferAsync(frame.getData(), frame.cols, frame.rows, frame.step, barcodeTypes, function (err, msg) {
// console.log(results)
results = msg
}, "", 1);
if (results != null) {
for (index in results) {
let result = results[index];
let upperLeft = new cv.Point(result.x1, result.y1)
let bottomLeft = new cv.Point(result.x2, result.y2)
let upperRight = new cv.Point(result.x3, result.y3)
let bottomRight = new cv.Point(result.x4, result.y4)
frame.drawLine(
upperLeft,
bottomLeft,
drawParams
)
frame.drawLine(
bottomLeft,
upperRight,
drawParams
)
frame.drawLine(
upperRight,
bottomRight,
drawParams
)
frame.drawLine(
bottomRight,
upperLeft,
drawParams
)
frame.putText(result.value, new cv.Point(result.x1, result.y1 + 10), fontFace, fontScale, textColor, thickness);
}
}
img = cv.imencode('.jpg', frame);
setTimeout(capture, 30);
}
capture();
var server = http.createServer(function (req, res) { //create web server
if (req.url.startsWith("/image")) {
res.writeHead(200, { 'Content-Type': 'image/jpeg' });
res.write(img);
res.end();
}
else {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.write(html);
res.end();
}
});
结果是异步返回的,因为连续帧之间的差别很小,所以用于显示问题不大。
以下是IE中的运行效果:
如何在IE中打开USB摄像头扫描条形码
https://github.com/yushulx/nodejs-barcode-reader