构建基于 Node.js 的条形码识别程序

rk3007 9年前

来自: http://www.oschina.net/translate/how-to-build-node-js-barcode-reader-on-windows-lin

在这篇文章中,我们将展示一个非常简单的方法构建一个自定义的 Node 模块,该模块封装了Dynamsoft Barcode Reader SDK ,支持 Windows、Linux 和 OS X,同时我们将演示如何集成这块模块实现一个在线的条形码读取应用。

越来越多的 Web 开发者选择 Node 来构建网站,因为使用 JavaScript 来开发复杂的服务器端 Web 应用越来越便利。为了扩展在不同平台下的 Node 的功能,Node 允许开发者使用 C/C++ 来创建扩展。

演示项目代码下载:

介绍

Dynamsoft Barcode Reader 为 Windows、Linux 和 OS X 提供条形码解析的 C/C++ 共享库。其最大的优势是适用于多种高级编程语言,包括 JavaScript, Python, Java, Ruby, PHP 等,只要可以封装 C/C++ API 作为一个扩展就可以使用。不管是什么编程语言,最终只需要简单几行代码即可完成条形码的解析。

支持 1D/2D 条形码类型

  • Code 39, Code 93, Code 128, Codabar, Interleaved 2 of 5, EAN-8, EAN-13, UPC-A, UPC-E,Industrial 2 of 5

  • QRCode

  • DataMatrix

  • PDF417

支持图像类型、

  • BMP, JPEG, PNG, GIF, TIFF, PDF

运行环境

  • Windows, Linux & Mac

  • Node v5.5.0

Node.js 条形码扩展

Node.js 扩展使用 C/C++ 编写的动态链接的共享对象。如果你没有接触过这方面的技术,可以阅读 官方教程

创建扩展

创建名为 dbr.cc 的文件,并添加方法 DecodeFile:

#include <node.h>  #include <string.h>  #include "If_DBR.h"  #include "BarcodeFormat.h"  #include "BarcodeStructs.h"  #include "ErrorCode.h"     using namespace v8;     void DecodeFile(const FunctionCallbackInfo<Value>& args) {     }     void Init(Handle<Object> exports) {      NODE_SET_METHOD(exports, "decodeFile", DecodeFile);  }     NODE_MODULE(dbr, Init)

解析来自 JavaScript 传递过来的参数

Isolate* isolate = Isolate::GetCurrent();  HandleScope scope(isolate);  String::Utf8Value license(args[0]->ToString());  String::Utf8Value fileName(args[1]->ToString());  char *pFileName = *fileName;  char *pszLicense = *license;  __int64 llFormat = args[2]->IntegerValue();  Local<Function> cb = Local<Function>::Cast(args[3]);

解析条形码图像:

int iMaxCount = 0x7FFFFFFF;  ReaderOptions ro = {0};  pBarcodeResultArray pResults = NULL;  ro.llBarcodeFormat = llFormat;  ro.iMaxBarcodesNumPerPage = iMaxCount;     DBR_InitLicense(pszLicense);  // Decode barcode image  int ret = DBR_DecodeFile(pFileName, &ro, &pResults);

将条形码转成字符串:

const char * GetFormatStr(__int64 format)  {      if (format == CODE_39)          return "CODE_39";      if (format == CODE_128)          return "CODE_128";      if (format == CODE_93)          return "CODE_93";      if (format == CODABAR)          return "CODABAR";      if (format == ITF)          return "ITF";      if (format == UPC_A)          return "UPC_A";      if (format == UPC_E)          return "UPC_E";      if (format == EAN_13)          return "EAN_13";      if (format == EAN_8)          return "EAN_8";      if (format == INDUSTRIAL_25)          return "INDUSTRIAL_25";      if (format == QR_CODE)          return "QR_CODE";      if (format == PDF417)          return "PDF417";      if (format == DATAMATRIX)          return "DATAMATRIX";         return "UNKNOWN";  }

将结果转成 v8 对象:

Local<Array> barcodeResults = Array::New(isolate);     for (int i = 0; i < count; i++)  {      tmp = ppBarcodes[i];         Local<Object> result = Object::New(isolate);      result->Set(String::NewFromUtf8(isolate, "format"), String::NewFromUtf8(isolate, GetFormatStr(tmp->llFormat)));      result->Set(String::NewFromUtf8(isolate, "value"), String::NewFromUtf8(isolate, tmp->pBarcodeData));         barcodeResults->Set(Number::New(isolate, i), result);  }

构建扩展

要求:

安装 node-gyp:

npm install -g node-gyp

创建 binding.gyp 用于多平台编译:

{    "targets": [      {        'target_name': "dbr",        'sources': [ "dbr.cc" ],        'conditions': [            ['OS=="linux"', {              'defines': [                'LINUX_DBR',              ],              'include_dirs': [                  "/home/xiao/Dynamsoft/BarcodeReader4.0/Include"              ],              'libraries': [                  "-lDynamsoftBarcodeReaderx64", "-L/home/xiao/Dynamsoft/BarcodeReader4.0/Redist"              ],              'copies': [              {                'destination': 'build/Release/',                'files': [                  '/home/xiao/Dynamsoft/BarcodeReader4.0/Redist/libDynamsoftBarcodeReaderx64.so'                ]              }]            }],            ['OS=="win"', {              'defines': [                'WINDOWS_DBR',              ],              'include_dirs': [                  "F:\Program Files (x86)\Dynamsoft\Barcode Reader 4.1\Components\C_C++\Include"              ],              'libraries': [                  "-lF:\Program Files (x86)\Dynamsoft\Barcode Reader 4.1\Components\C_C++\Lib\DBRx64.lib"              ],              'copies': [              {                'destination': 'build/Release/',                'files': [                  'F:\Program Files (x86)\Dynamsoft\Barcode Reader 4.1\Components\C_C++\Redist\DynamsoftBarcodeReaderx64.dll'                ]              }]            }],            ['OS=="mac"', {              'defines': [                'MAC_DBR',              ],              'include_dirs' : [                  "/Applications/Dynamsoft/Barcode\ Reader\ 4.1/Include"              ],              'libraries': [                  "-lDynamsoftBarcodeReader"              ]            }]        ]      }    ]  }

将 DRB 安装目录替换成你机器上的实际目录。

配置构建环境:

node-gyp configure

可以在 Mac 上你会碰到下面的错误:

error: xcode-select: error: tool 'xcodebuild' requires Xcode, but active developer directory '/Library/Developer/CommandLineTools' is a command line tools instance

解决办法是:

sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer

构建项目:

node-gyp build

在线条形码解析

你已经成功的构建了 Node 的条形码解析模块,现在可以创建一个简单的条形码读取应用。

安装 ExpressFormidable :

npm install express  npm install formidable

使用 Express 创建一个简单应用:

var formidable = require('formidable');  var util = require('util');  var express = require('express');  var fs = require('fs');  var app = express();  var path = require('path');  var dbr = require('./build/Release/dbr');  var http = require('http');     fs.readFile('./license.txt', 'utf8', function(err, data) {       app.use(express.static(__dirname));    app.use(function(req, res, next) {      res.header("Access-Control-Allow-Origin", "*");      res.header("Access-Control-Allow-Methods", "PUT, POST, GET, DELETE, OPTIONS");      res.header("Access-Control-Allow-Headers", "X-Requested-With, content-type");      res.header("Access-Control-Allow-Credentials", true);      next();    });       var server = app.listen(2016, function() {      var host = server.address().address;      var port = server.address().port;      console.log('listening at http://%s:%s', host, port);    });  });

使用 Formidable 从表单中提取图像数据:

app.post('/upload', function(req, res) {      var form = new formidable.IncomingForm();      form.parse(req, function(err, fields, files) {        var dir = 'uploads';           fs.mkdir(dir, function(err) {          var flag = fields.uploadFlag;          var barcodeType = parseInt(fields.barcodetype);             console.log('flag: ' + flag);             if (flag === '1') { // read barcode image file            fs.readFile(files.fileToUpload.path, function(err, data) {              // save file from temp dir to new dir              var fileName = path.join(__dirname, dir, files.fileToUpload.name);              console.log(fileName);              fs.writeFile(fileName, data, function(err) {                if (err) throw err;                 });            });             } else { // read barcode image url            var tmpFileName = path.join(__dirname, dir, 'tmp.jpg');            var tmp = fs.createWriteStream(tmpFileName);            var url = fields.fileToDownload;            console.log('url: ' + url);            http.get(url, function(response) {              response.pipe(tmp);              tmp.on('finish', function() {                tmp.close(function() {                   });              });            });          }        });         });    });

导入条形码模块用来解析图像文件:

decodeBarcode(res, license, tmpFileName, barcodeType);

运行应用:

node server.js

访问 http://localhost:2016/index.htm :

如果你要在 Windows、Linux 和 Mac 下构建条形码读取应用,可以直接下载示例程序 Dynamsoft Barcode Reader , 也可以直接咨询 support@dynamsoft.com .

</div>