翻译于 2016/02/13 10:15
1 人 顶 此译文
In this post, let’s take a glimpse of how easy to build a custom Node module on Windows, Linux, and Mac by wrapping Dynamsoft Barcode Reader SDK, as well as how to integrate the module to quickly implement an online barcode reader.
This article is in the Product Showcase section for our sponsors at CodeProject. These reviews are intended to provide you with information on products and services that we consider useful and of value to developers.
More and more Web developers tend to choose Node.js to build their Website because it is convenient to build complex server-side Web applications using only JavaScript. To extend and empower the functionalities of Node.js applications on different platforms, Node.js allows developers to create addons in C/C++. In this post, let’s take a glimpse of how easy to build a custom Node module on Windows, Linux, and Mac by wrapping Dynamsoft Barcode Reader SDK, as well as how to integrate the module to quickly implement an online barcode reader.
Dynamsoft Barcode Reader provides C/C++ shared libraries for Windows, Linux, and Mac. The ultimate benefit is that any high-level programming languages, such as JavaScript, Python, Java, Ruby, PHP and so on, are capable of wrapping C/C++ APIs using an extension or an addon. No matter which programming language you are familiar with, the SDK will expedite the coding work of barcode reader app with a few lines of code.
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 Addons are dynamically-linked shared objects written in C/C++. If you have never touched this part before, you’d better follow the official tutorial to get started.
Dynamsoft Barcode Reader 为 Windows、Linux 和 OS X 提供条形码解析的 C/C++ 共享库。其最大的优势是适用于多种高级编程语言,包括 JavaScript, Python, Java, Ruby, PHP 等,只要可以封装 C/C++ API 作为一个扩展就可以使用。不管是什么编程语言,最终只需要简单几行代码即可完成条形码的解析。
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 扩展使用 C/C++ 编写的动态链接的共享对象。如果你没有接触过这方面的技术,可以阅读 官方教程 。
Create dbr.cc and add a method 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)
Parse parameters that passed from 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]);
Decode barcode image:
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);
Convert barcode formats to String:
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"; }
Convert results to v8 object:
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); }
Prerequisites:
Windows: Install DBR for Windows, Visual Studio, and Python v2.7.
Linux: Install DBR for Linux.
Mac: Install DBR for Mac and Xcode.
Install node-gyp:
npm install -g node-gyp
Create binding.gyp for multiplatform compilation:
{ "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" ] }] ] } ] }
Replace the DBR Installation Directory with yours.
Configure the building environment:
node-gyp configure
Probably you will see the following error when configuring the environment on Mac:
error: xcode-select: error: tool 'xcodebuild' requires Xcode, but active developer directory '/Library/Developer/CommandLineTools' is a command line tools instance
Here is the solution:
sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer
Build the project:
node-gyp build
创建名为 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); }
要求:
Windows: 需要安装 DBR for Windows, Visual Studio, and Python v2.7.
Linux: 安装 DBR for Linux.
Mac: 安装 DBR for Mac 和 Xcode.
安装 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
You have successfully built the Node barcode reader module. Now it is time to create a simple barcode reader app.
Install Express and Formidable:
npm install express npm install formidable
Create a simple Website using 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); }); });
Use Formidable to extract the image data from Form.
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() { }); }); }); } }); }); });
Import the barcode module to decode the image file.
decodeBarcode(res, license, tmpFileName, barcodeType);
Run the app:
node server.js
Visit http://localhost:2016/index.htm:
Do you want to build a barcode reader app on Windows, Linux or Mac? Download the sample code and get your hands dirty now. For more information about Dynamsoft Barcode Reader, please contact support@dynamsoft.com.
你已经成功的构建了 Node 的条形码解析模块,现在可以创建一个简单的条形码读取应用。
安装 Express 和 Formidable:
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.