Quantcast
Channel: Barcode – Dynamsoft Developers
Viewing all 145 articles
Browse latest View live

Running Linux Console App on Chrome OS in Virtual Machine

$
0
0

Chrome OS, developed by Google, is a light-weighted operating system based on the Linux kernel. It uses Chrome web browser as the user interface that primarily supports web applications released as Chrome extensions. However, Chrome extension is not fresh to me. When running Chrome OS in a virtual machine, I wondered whether it is possible to run native apps. In this article, I want to share how to run a console application built with Dynamsoft C/C++ Barcode SDK on Chrome OS.

Virtual Machine Download

To experience Chrome OS in a virtual machine, we can use the CloudReady operating system that built on Google’s open-source Chromium. Here are the links:

Running Native Apps on Chrome OS

Check the information of the operating system:

uname -a

Chrome OS info

The operating system is 64-bit. By default, there is no GCC compiler installed:

No GCC installed

Luckily, SSH is available:

SSH on Chrome OS

Build Console App on Ubuntu and Copy It to Chrome OS

Download Dynamsoft C/C++ Barcode SDK for Linux and build the sample ~/BarcodeReader4.0/Samples/C.

Linux Barcode Reader

Use SCP to send ~/BarcodeReader4.0/Redist/libDynamsoftBarcodeReaderx64.so and ~/BarcodeReader4.0/Samples/C/BarcodeReaderDemo to Chrome OS:

scp ~/BarcodeReader4.0/Redist/libDynamsoftBarcodeReaderx64.so chronos@192.168.23.130:~/
scp ~/BarcodeReader4.0/Samples/C/BarcodeReaderDemo chronos@192.168.23.130:~/

Get connection timed out?

SSH connection timed out

Use iptables to check IP filter rules:

sudo iptables -S INPUT

iptables

By default, the port 22 is disabled. We need to enable it:

sudo iptables -A INPUT -p tcp –dport 22 -j ACCEPT

You have to do one more thing –  launch SSH daemon:

sudo /usr/sbin/sshd

SSH daemon

Try SCP again. It should work now.

SSH success
The next step is to run BarcodeReaderDemo. If you run it directly, you will get the permission error. To make it work, copy it to /usr/bin:

sudo cp ./BarcodeReaderDemo /usr/bin

operation not permitted

Do not forget to move libDynamsoftBarcodeReaderx64.so to /usr/local/lib64:

Barcode Reader on Chrome OS

In this way, we can successfully run Linux console applications on Chrome OS, but the better way is to use GCC building applications.

Install GCC with Crouton

Get Crouton from https://github.com/dnschneid/crouton.

Install CLI:

sh crouton -t cli-extra

Enter chroot environment and install GCC:

sudo startcli
sudo apt-get install gcc

crouton chroot

Now build C/C++ source code using GCC:

Chrome OS GCC Build

The post Running Linux Console App on Chrome OS in Virtual Machine appeared first on Code Pool.


Using OpenCV to Build Python Barcode Reader for macOS

$
0
0

This article is about how to use OpenCV and Dynamsoft Barcode Reader SDK to create a Python barcode reader on macOS.

How to Install OpenCV on macOS

Use ‘sw_vers’ to check macOS system version information:

check mac version

Install Homebrew.

If you have already installed Homebrew, just update it. When running ‘brew update’, you may see following errors.

Error: /usr/local/Library/brew.sh: line 32: /usr/local/Library/ENV/scm/git: No such file or directory.

To fix the error, run:

cd "$(brew --repository)" && git fetch && git reset --hard origin/master

Error: Fetching /usr/local/Library/Taps/flutter/homebrew-flutter failed!

To repair the error, run:

brew untap flutter/flutter

The next step is to install Python and NumPy. Python is pre-installed on macOS. The default version is not compatible with the latest OpenCV. Therefore, you need to install the latest Python using Homebrew.

brew install python python3 numpy
echo 'import site; site.addsitedir("/usr/local/lib/python2.7/site-packages")' >> /Users/xiao/Library/Python/2.7/lib/python/site-packages/homebrew.pth

Use command ‘python –version’ to check the current version. If it is not the latest version, you can edit .bash_profile and export the path:

vim ~/.bash_profile
export PATH=/usr/local/Cellar/python/2.7.13/bin:$PATH
source ~/.bash_profile

Install OpenCV:

brew tap homebrew/science
brew install opencv3

Python Barcode Reader for macOS

Get libDynamsoftBarcodeReader.dylib and relevant header files from DBR-Libs.zip.

To link the dynamic library and use barcode reading APIs, we need to write code in C/C++. Include the header files:

#include <Python.h>
#include "If_DBR.h"
#include "BarcodeFormat.h"
#include "BarcodeStructs.h"
#include "ErrorCode.h"
#include <ndarraytypes.h>

Where is ndarraytypes.h?
Use command ‘find / -name ndarraytypes.h’ to find it:

/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/numpy/core/include/numpy/ndarraytypes.h
/usr/local/Cellar/numpy/1.13.0/lib/python2.7/site-packages/numpy/core/include/numpy/ ndarraytypes.h
/usr/local/lib/python2.7/site-packages/numpy/core/include/numpy/ndarraytypes.h

Get native image data that decoded by OpenCV Python API:

    PyObject *o;
    if (!PyArg_ParseTuple(args, "O", &o))
        return NULL;

    PyObject *ao = PyObject_GetAttrString(o, "__array_struct__");
    PyObject *retval;

    if ((ao == NULL) || !PyCObject_Check(ao)) {
        PyErr_SetString(PyExc_TypeError, "object does not have array interface");
        return NULL;
    }

    PyArrayInterface *pai = (PyArrayInterface*)PyCObject_AsVoidPtr(ao);
    if (pai->two != 2) {
        PyErr_SetString(PyExc_TypeError, "object does not have array interface");
        Py_DECREF(ao);
        return NULL;
    }

    char *buffer = (char*)pai->data; // The address of image data
    int width = pai->shape[1];       // image width
    int height = pai->shape[0];      // image height
    int size = pai->strides[0] * pai->shape[0]; // image size = stride * height

Define BITMAPINFOHEADER structure. The DWORD defined by Microsoft is unsigned long, but here it is unsigned int. The size of the type should be 4 bytes.

typedef unsigned int DWORD;
typedef int LONG;
typedef unsigned short WORD;

#pragma pack(push)
#pragma pack(1)

typedef struct tagBITMAPINFOHEADER {
  DWORD biSize;
  LONG biWidth;
  LONG biHeight;
  WORD biPlanes;
  WORD biBitCount;
  DWORD biCompression;
  DWORD biSizeImage;
  LONG biXPelsPerMeter;
  LONG biYPelsPerMeter;
  DWORD biClrUsed;
  DWORD biClrImportant;
} BITMAPINFOHEADER;

#pragma pack(pop)

Construct a buffer with bitmap header info for barcode detection.

int dib_header_size = sizeof(BITMAPINFOHEADER);

char *total = (char *)malloc(size + dib_header_size); // buffer size = image size + header size
memset(total, 0, size + dib_header_size);
BITMAPINFOHEADER bitmap_info = {dib_header_size, width, height, 0, 24, 0, size, 0, 0, 0, 0};
memcpy(total, &bitmap_info, dib_header_size);

// Copy image data to buffer from bottom to top
char *data = total + dib_header_size;
int stride = pai->strides[0];
int i = 1;
for (; i <= height; i++) {
    memcpy(data, buffer + stride * (height - i), stride);
    data += stride;
}
int iRet = DBR_DecodeBuffer((unsigned char *)total, size + dib_header_size, &ro, &pResults);

Get and return barcode results:

    int count = pResults->iBarcodeCount;
    pBarcodeResult* ppBarcodes = pResults->ppBarcodes;
    pBarcodeResult tmp = NULL;
    retval = PyList_New(count); // The returned Python object
    PyObject* result = NULL;
    i = 0;
    for (; i < count; i++)
    {
        tmp = ppBarcodes[i];
        result = PyString_FromString(tmp->pBarcodeData);
        printf("result: %s\n", tmp->pBarcodeData);
        PyList_SetItem(retval, i, Py_BuildValue("iN", (int)tmp->llFormat, result)); // Add results to list
    }
    // release memory
    DBR_FreeBarcodeResults(&pResults);

Configure setup.py for building Python extension:

from distutils.core import setup, Extension
 
module_dbr = Extension('dbr', 
                        sources = ['dbr.c'], 
                        include_dirs=['/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/numpy/core/include/numpy', './include'],
                        library_dirs=['./lib'],
                        libraries=['DynamsoftBarcodeReader'])
 
setup (name = 'DynamsoftBarcodeReader',
        version = '1.0',
        description = 'Python barcode extension',
        ext_modules = [module_dbr])

Build and install dbr.so:

python setup.py build install

Write a simple Python barcode detection app:

import cv2
from dbr import *
import sys
import os.path

initLicense("D426ABF246933C82A16D537FC46C064F")
frame = cv2.imread(fileName, cv2.CV_LOAD_IMAGE_COLOR)
results = decodeBuffer(frame)

Note: when using imread, you have to set second parameter CV_LOAD_IMAGE_COLOR. The native API only works for a color image.

OpenCV Python barcode reader for macOS

Source Code

https://github.com/dynamsoft-dbr/mac-opencv

The post Using OpenCV to Build Python Barcode Reader for macOS appeared first on Code Pool.

How to Wrap Dynamsoft Linux Barcode SDK for Node.js

$
0
0

From version 4.x to 5.x, Dynamsoft improved Barcode SDK performance with a big leap. Unfortunately, only Windows edition is available for download so far. In this post, I will share how to create a Node.js extension with the preview version of Dynamsoft Linux Barcode SDK 5.2. If you are interested in Windows edition, please read – Building Node.js Barcode Addon with DBR v5.0.

Linux Environment: Ubuntu on Windows

If you are using Windows 10, Virtual Machine is not necessary for Linux development. I’d like to use the Linux subsystem installed from Windows Store:

Ubuntu on Windows

 

Environment Configuration

Open cmd.exe > bash. Install essential development tools ‘make‘ and ‘g++‘:

sudo apt-get install make g++

Download Node.js Linux binary (x64) and extract the package:

tar -xvf node-v8.4.0-linux-x64.tar.xz

Export Node.js bin path in ~/.bashrc:

export PATH=/mnt/f/zip/node-v8.4.0-linux-x64/bin:$PATH

Make the change work:

source ~/.bashrc

Extract dbr_linux_5.2.tar.gz:

tar -xvf dbr_linux_5.2.tar.gz

Create a symlink for libDynamsoftBarcodeReaderx64.so:

sudo ln -s <Your PATH>/libDynamsoftBarcodeReaderx64.so /usr/lib/libDynamsoftBarcodeReader.so

Install node-gyp:

npm install -g node-gyp

Node.js Extension

Let’s get started with binding.gyp:

{
    "targets": [
      {
        'target_name': "dbr",
        'sources': [ "dbr.cc" ],
        'conditions': [
            ['OS=="linux"', {
                'defines': [
                  'LINUX_DBR',
                ],
                'libraries': [
                    "-lDynamsoftBarcodeReader"
                ]
              }]
        ]
      }
    ]
  }

In this file, we define the module name, source code files, and libraries. To make -lDynamsoftBarcodeReader work, please ensure that you have generated the symlink (/usr/lib/libDynamsoftBarcodeReader.so) for libDynamsoftBarcodeReaderx64.so beforehand.

Create dbr.cc. The code is same to Windows edition.

Configure building environment:

node-gyp configure

Build the project:

node-gyp build

Import the module to Node.js app:

var dbr = require('./build/Release/dbr');
var fs = require('fs');
var barcodeTypes = 0x3FF | 0x2000000 | 0x8000000 |
                   0x4000000;  // 1D, QRCODE, PDF417, DataMatrix


function decodeFileStreamAsync(fileName) {
  let stats = fs.statSync(fileName);
  let fileSize = stats["size"];

  fs.open(fileName, 'r', function(status, fd) {
    if (status) {
      console.log(status.message);
      return;
    }
    let buffer = new Buffer(fileSize);
    fs.read(fd, buffer, 0, fileSize, 0, function(err, bytesRead, data) {
      dbr.decodeFileStreamAsync(buffer, fileSize, barcodeTypes, function(msg) {
        console.log(fileName);
        let result = null;
        for (index in msg) {
          result = msg[index];
          console.log("Format: " + result['format']);
          console.log("Value : " + result['value']);
        }
        console.log("Done............................................................\n");
      });
    });
  });
}

dbr.initLicense(
    "t0068MgAAAGvV3VqfqOzkuVGi7x/PFfZUQoUyJOakuduaSEoI2Pc8+kMwjrojxQgE5aJphmhagRmq/S9lppTkM4w3qCQezxk=");

Run a test:

node test.js -f test.tif

linux barcode sdk

How to Get the Linux Barcode SDK

Contact support@dynamsoft.com to get the download link.

Source Code

https://github.com/dynamsoft-dbr/linux-barcode-sdk-node-wrapper

The post How to Wrap Dynamsoft Linux Barcode SDK for Node.js appeared first on Code Pool.

Building Python Barcode Extension with DBR 5.2 for Linux

$
0
0

According to the statistics of Stack Overflow traffic, Python is the fastest-growing major programming language in high-income countries. Python seems to be promising in the future. I have noticed that many of the developers who would like to use Dynamsoft Barcode Reader SDK for Linux are more interested in Python rather than C/C++ or Java. In this post, I will illustrate how to build the Python barcode extension with DBR 5.2.

Writing Python Barcode Extension in C/C++

Dynamsoft Barcode Reader 5.2 provides C/C++ APIs, which means you need to create a Python wrapper yourself. Please contact support@dynamsoft.com to get the beta version and trial license.

Setting Up Environment

The Ubuntu subsystem is my first choice for developing Linux app on Windows 10.

Download Numpy 1.11.2.

Extract and install Numpy

cd numpy-1.11.2
sudo python setup.py build install

Find the path of ndarraytypes.h:

sudo find /usr -name ndarraytypes.h

Create setup.py and add the header file directory:

from distutils.core import setup, Extension

module_dbr = Extension('dbr',
                        sources = ['dbr.c'], 
                        include_dirs=["/usr/local/lib/python2.7/dist-packages/numpy-1.11.2-py2.7-linux-x86_64.egg/numpy/core/include/numpy/"],
                        libraries=['DynamsoftBarcodeReader'])

setup (name = 'DynamsoftBarcodeReader',
        version = '1.0',
        description = 'Python barcode extension',
        ext_modules = [module_dbr])

Extract dbr_linux_5.2.tar.gz:

tar -xvf dbr_linux_5.2.tar.gz

Create a symlink for libDynamsoftBarcodeReaderx64.so:

sudo ln -s <Your PATH>/libDynamsoftBarcodeReaderx64.so /usr/lib/libDynamsoftBarcodeReader.so

The bridging C/C++ code

Include header files:

#include <Python.h>
#include "DynamsoftBarcodeReader.h"
#include <ndarraytypes.h>

Define methods and initialize Python module:

static PyMethodDef Methods[] =
{
    {"create", create, METH_VARARGS, NULL},
    {"destroy", destroy, METH_VARARGS, NULL},
    {"initLicense", initLicense, METH_VARARGS, NULL},
    {"decodeFile", decodeFile, METH_VARARGS, NULL},
    {"decodeBuffer", decodeBuffer, METH_VARARGS, NULL},
    {NULL, NULL, 0, NULL}
};

PyMODINIT_FUNC
initdbr(void)
{
     (void) Py_InitModule("dbr", Methods);
}

Initialize DBR license:

static PyObject *
initLicense(PyObject *self, PyObject *args)
{
    if (!createDBR()) 
    {
        return NULL;
    }

    char *pszLicense;
    if (!PyArg_ParseTuple(args, "s", &pszLicense)) {
        return NULL;
    }

    int ret = DBR_InitLicenseEx(hBarcode, pszLicense);
    return Py_BuildValue("i", ret);
}

Pass a file name and read barcodes:

/**
 * Decode barcode from a file 
 */
static PyObject *
decodeFile(PyObject *self, PyObject *args)
{
    if (!createDBR()) 
    {
        return NULL;
    }

    char *pFileName;
    int iFormat;
    if (!PyArg_ParseTuple(args, "si", &pFileName, &iFormat)) {
        return NULL;
    }

    // Initialize Dynamsoft Barcode Reader
    int iMaxCount = 0x7FFFFFFF;
    SBarcodeResultArray *pResults = NULL;
    DBR_SetBarcodeFormats(hBarcode, iFormat);
    DBR_SetMaxBarcodesNumPerPage(hBarcode, iMaxCount);

    // Barcode detection
    int ret = DBR_DecodeFileEx(hBarcode, pFileName, &pResults);

    // Wrap results
    PyObject *list = createPyResults(pResults);
    return list;
}

Give an image buffer and read barcodes:

/**
 * Decode barcode from an image buffer. 
 */
static PyObject *
decodeBuffer(PyObject *self, PyObject *args)
{
    if (!createDBR()) 
    {
        return NULL;
    }

    PyObject *o;
    int iFormat;
    if (!PyArg_ParseTuple(args, "Oi", &o, &iFormat))
        return NULL;

    PyObject *ao = PyObject_GetAttrString(o, "__array_struct__");

    if ((ao == NULL) || !PyCObject_Check(ao)) {
        PyErr_SetString(PyExc_TypeError, "object does not have array interface");
        return NULL;
    }

    PyArrayInterface *pai = (PyArrayInterface*)PyCObject_AsVoidPtr(ao);
    if (pai->two != 2) {
        PyErr_SetString(PyExc_TypeError, "object does not have array interface");
        Py_DECREF(ao);
        return NULL;
    }

    // Get image information
    char *buffer = (char*)pai->data; // The address of image data
    int width = pai->shape[1];       // image width
    int height = pai->shape[0];      // image height
    int size = pai->strides[0] * pai->shape[0]; // image size = stride * height

    // Initialize Dynamsoft Barcode Reader
    int iMaxCount = 0x7FFFFFFF;
	SBarcodeResultArray *pResults = NULL;
	DBR_SetBarcodeFormats(hBarcode, iFormat);
	DBR_SetMaxBarcodesNumPerPage(hBarcode, iMaxCount);

    // Detect barcodes
    int iRet = DBR_DecodeBufferEx(hBarcode, buffer, width, height, width * 3, IPF_RGB_888, &pResults);
    
    // Wrap results
    PyObject *list = createPyResults(pResults);
    
    Py_DECREF(ao);
    return list;
}

Convert results to Python Object:

static PyObject *createPyResults(SBarcodeResultArray *pResults)
{
    // Get barcode results
    int count = pResults->iBarcodeCount;
    SBarcodeResult** ppBarcodes = pResults->ppBarcodes;
    SBarcodeResult* tmp = NULL;

    // Create a Python object to store results
    PyObject* list = PyList_New(count); 
    PyObject* result = NULL;
    for (int i = 0; i < count; i++)
    {
        tmp = ppBarcodes[i];
        result = PyString_FromString(tmp->pBarcodeData);
        PyList_SetItem(list, i, Py_BuildValue("sN", GetFormatStr(tmp->emBarcodeFormat), result)); // Add results to list
    }

    // Release memory
    DBR_FreeBarcodeResults(&pResults);

    return list;
}

Build and install the Python barcode extension:

sudo python setup.py build install

A command line barcode app

Read barcodes from a picture file:

import os.path
import dbr

def initLicense(license):
    dbr.initLicense(license)

def decodeFile(fileName):
    dbr.initLicense("t0068MgAAAGvV3VqfqOzkuVGi7x/PFfZUQoUyJOakuduaSEoI2Pc8+kMwjrojxQgE5aJphmhagRmq/S9lppTkM4w3qCQezxk=")
    formats = 0x3FF | 0x2000000 | 0x8000000 | 0x4000000; # 1D, QRCODE, PDF417, DataMatrix
    results = dbr.decodeFile(fileName, formats)
    
    for result in results:
        print("barcode format: " + result[0])
        print("barcode value: " + result[1])

if __name__ == "__main__":
    barcode_image = input("Enter the barcode file: ");
    if not os.path.isfile(barcode_image):
        print "It is not a valid file."
    else:
        decodeFile(barcode_image);

Run the app:

python test.py

Linux Python Barcode Reader

Reference

Source Code

https://github.com/dynamsoft-dbr/linux-barcode-sdk-python-wrapper

The post Building Python Barcode Extension with DBR 5.2 for Linux appeared first on Code Pool.

Building Swift Barcode Reader with DBR 5.2 for Linux

$
0
0

A few weeks ago, Apple released Swift 4.0 which is available for macOS and Ubuntu 14/16. In this post, I will share how to implement a simple Swift barcode reader (command line tool) with Dynamsoft Barcode Reader SDK for Linux.

Environment

Operating system and SDK

  • Windows 10.
  • VMware 11.1.2.
  • Ubuntu 14.04.
  • Swift 4.0.
  • Dynamsoft Barcode Reader 5.2 for Linux. Please contact support@dynamsoft.com to get the beta version and trial license.

How to enable a shared folder in VMware

When using a virtual machine, a shared folder is handy if you want to use a Windows tool to write code for Linux.

It is easy to add a shared folder via virtual machine settings:

vmware share folder

However, there may be no shared folder listed under /mnt/ in guest OS, such as Ubuntu 14.04. Run the following command to check Ubuntu version:

lsb_release -a

To solve the issue, download and install a patch:

git clone https://github.com/rasa/vmware-tools-patches.git
cd vmware-tools-patches
sudo ./patched-open-vm-tools.sh
sudo vmware-config-tools.pl
sudo reboot

Now you can see the shared folder and files. This way is fine for running swift code as follows:

swift xxx.swift

vmware swift demo

Nevertheless, it will cause errors if you compiling the code with swiftc:

swiftc test.swift
/usr/bin/ld.gold: fatal error: test: Input/output error
clang: error: linker command failed with exit code 1 (use -v to see invocation)
<unknown>:0: error: link command failed with exit code 1 (use -v to see invocation)

How to solve swiftc issue: “<unknown>:0: error: link command failed with exit code 127 (use -v to see invocation)”

To use Swift, you have to install following dependencies beforehand:

sudo apt-get install clang libicu-dev

If you fail to run swiftc, please refer to Vincent Saluzzo’s solution:

sudo apt-get install -y libicu-dev
sudo apt-get install -y clang-3.6
sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-3.6 100
sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-3.6 100

Creating Swift Barcode Reader with C library

Inspired by StackOverflow question – Compile C Code and Expose it to Swift under Linux, I have successfully created a command line barcode reader by linking libDynamsoftBarcodeReader.so.

Create dbr.h with some exposed methods:

#include "DynamsoftBarcodeReader.h"

int initLicense(const char* pszLicense);
char* decodeFile(const char* pFileName, int iFormat);
int createDBR();
void destroyDBR();

Create dbr.c to invoke Dynamsoft Barcode Reader SDK:

#include <stdio.h>
#include "dbr.h"

#define DBR_NO_MEMORY 0
#define DBR_SUCCESS   1

// Barcode reader handler
void* hBarcode = NULL; 

/**
 * Create DBR instance
 */
int createDBR() 
{
    if (!hBarcode) {
        hBarcode = DBR_CreateInstance();
        if (!hBarcode)
        {
            printf("Cannot allocate memory!\n");
            return DBR_NO_MEMORY;
        }
    }

    return DBR_SUCCESS;
}

/**
 * Destroy DBR instance
 */
void destroyDBR()
{
    if (hBarcode) {
        DBR_DestroyInstance(hBarcode);
    }
}

/**
 * Set Dynamsoft Barcode Reader license.  
 * To get valid license, please contact support@dynamsoft.com
 * Invalid license is acceptable. With an invalid license, SDK will return an imcomplete result.
 */
int initLicense(const char* pszLicense)
{
    if (!createDBR()) 
    {
        return -1;
    }

	return DBR_InitLicenseEx(hBarcode, pszLicense);
}

char* createPyResults(SBarcodeResultArray *pResults)
{
    // Get barcode results
    int count = pResults->iBarcodeCount;
	SBarcodeResult** ppBarcodes = pResults->ppBarcodes;
    SBarcodeResult* tmp = NULL;
    int i = 0;
    for (; i < count; i++)
    {
        tmp = ppBarcodes[i];
        printf("Result: %s, Format: %s\n", tmp->pBarcodeData, tmp->pBarcodeFormatString);
    }

    // Release memory
    DBR_FreeBarcodeResults(&pResults);

    return NULL;
}

/**
 * Decode barcode from a file 
 */
char* decodeFile(const char* pFileName, int iFormat)
{
    if (!createDBR()) 
    {
        return NULL;
    }

    // Initialize Dynamsoft Barcode Reader
	int iMaxCount = 0x7FFFFFFF;
	SBarcodeResultArray *pResults = NULL;
	DBR_SetBarcodeFormats(hBarcode, iFormat);
	DBR_SetMaxBarcodesNumPerPage(hBarcode, iMaxCount);

    // Barcode detection
    int ret = DBR_DecodeFileEx(hBarcode, pFileName, &pResults);

    // Wrap results
    return createPyResults(pResults);
}

Create barcode.swift to call C APIs:

let count = CommandLine.arguments.count
if count < 2 {
    print("Please add a file name. E.g. ./barcode test.tif")
}
else {
    let fileName = CommandLine.arguments[1]

    createDBR()
    let ret = initLicense("t0068MgAAAGvV3VqfqOzkuVGi7x/PFfZUQoUyJOakuduaSEoI2Pc8+kMwjrojxQgE5aJphmhagRmq/S9lppTkM4w3qCQezxk=")
    if ret == 0 {
        // Read barcode
        let barcodeTypes : Int32 = 0x3FF | 0x2000000 | 0x8000000 |
                    0x4000000;  // 1D, QRCODE, PDF417, DataMatrix
        decodeFile(fileName, barcodeTypes);
    }
    destroyDBR()
}

Compile dbr.c with gcc:

gcc -c dbr.c

Compile barcode.swift with swiftc:

swiftc -import-objc-header dbr.h barcode.swift dbr.o -o barcode -lDynamsoftBarcodeReader

Run the swift barcode reader:

 ./barcode test.tif

Linux Swift Barcode Reader

Source Code

https://github.com/dynamsoft-dbr/linux-swift-4.0-barcode-reader

The post Building Swift Barcode Reader with DBR 5.2 for Linux appeared first on Code Pool.

How to Port C/C++ Barcode Extension to Python 3

$
0
0

When porting code from Python 2 to Python 3, it is not as easy as you imagined no matter whether the primary programming language is Python or C/C++. Re-compiling the Dynamsoft Barcode extension for Python 3 is a challenge because I only found a few of documentation and resources online. Luckily, I succeeded in using Python 3 compatible APIs after reading the source code of Numpy.

Barcode Reader SDK for Python 3

The following content is to illustrate how to make C code compatible with both Python 2 and Python 3.

Prerequisites

  • Dynamsoft Barcode Reader 5.2 for Windows.

    Copy Dynamsoft\Barcode Reader 5.2\Components\C_C++\Redist\DynamsoftBarcodeReaderx86.dll to Python35\Lib\site-packages.
  • Python 3.5.0

  • OpenCV 3.3.0

    pip install opencv-python
  • Numpy 1.11.2

    pip install numpy
  • Visual Studio 2015

    SET VS90COMNTOOLS=%VS140COMNTOOLS%

Initialize the extension for Python 2 and Python 3

Create dbr.c. According to the tutorial – Porting Extension Modules to Python 3, we can initialize the module as follows:

#if PY_MAJOR_VERSION >= 3
#ifndef IS_PY3K
#define IS_PY3K 1
#endif
#endif

struct module_state {
    PyObject *error;
};

#if defined(IS_PY3K)
#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
#else
#define GETSTATE(m) (&_state)
static struct module_state _state;
#endif

static PyMethodDef dbr_methods[] =
{
    {"create", create, METH_VARARGS, NULL},
    {"destroy", destroy, METH_VARARGS, NULL},
    {"initLicense", initLicense, METH_VARARGS, NULL},
    {"decodeFile", decodeFile, METH_VARARGS, NULL},
    {"decodeBuffer", decodeBuffer, METH_VARARGS, NULL},
    {NULL, NULL, 0, NULL}
};

#if defined(IS_PY3K)

static int dbr_traverse(PyObject *m, visitproc visit, void *arg) {
    Py_VISIT(GETSTATE(m)->error);
    return 0;
}

static int dbr_clear(PyObject *m) {
    Py_CLEAR(GETSTATE(m)->error);
    return 0;
}

static struct PyModuleDef moduledef = {
    PyModuleDef_HEAD_INIT,
    "dbr",
    NULL,
    sizeof(struct module_state),
    dbr_methods,
    NULL,
    dbr_traverse,
    dbr_clear,
    NULL
};

#define INITERROR return NULL

PyMODINIT_FUNC
PyInit_dbr(void)

#else
#define INITERROR return
void
initdbr(void)
#endif
{
#if defined(IS_PY3K)
    PyObject *module = PyModule_Create(&moduledef);
#else
    PyObject *module = Py_InitModule("dbr", dbr_methods);
#endif

    if (module == NULL)
        INITERROR;
    struct module_state *st = GETSTATE(module);

    st->error = PyErr_NewException("dbr.Error", NULL, NULL);
    if (st->error == NULL) {
        Py_DECREF(module);
        INITERROR;
    }

#if defined(IS_PY3K)
    return module;
#endif
}

Replace PyString_FromString with PyUnicode_FromFormat

The barcode results have to be converted from C string to PyObject:

#if defined(IS_PY3K)
result = PyUnicode_FromFormat("%s", tmp->pBarcodeData);
#else
result = PyString_FromString(tmp->pBarcodeData);
#endif

Get image width, height, and buffer in C/C++

This part is totally different. You can download the source code of NumPy and read numpy/core/src/multiarray/ctors.c.

Here is the C/C++ code:

#if defined(IS_PY3K)
Py_buffer *view;
int nd;
PyObject *memoryview = PyMemoryView_FromObject(o);
if (memoryview == NULL) {
    PyErr_Clear();
    return -1;
}

view = PyMemoryView_GET_BUFFER(memoryview);
char *buffer = (char*)view->buf;
nd = view->ndim;
int len = view->len;
int stride = view->strides[0];
int width = view->strides[0] / view->strides[1];
int height = len / stride;
#else

Add include and lib paths to setup.py

You have to replace the paths with yours before building the extension:

from distutils.core import setup, Extension
import sys

dbr_include_dir = 'e:\\Program Files (x86)\\Dynamsoft\\Barcode Reader 5.2\\Components\\C_C++\\Include'
dbr_lib_dir = 'e:\\Program Files (x86)\\Dynamsoft\Barcode Reader 5.2\\Components\\C_C++\\Lib'


numpy_include_dir = None
if sys.version_info[0] == 2 and sys.version_info[1] == 7:
    numpy_include_dir = "F:\\Python27\\Lib\\site-packages\\numpy-1.11.2-py2.7-win32.egg\\numpy\\core\\include\\numpy"
else:
    numpy_include_dir = "F:\\Python35\\Lib\\site-packages\\numpy-1.11.2-py3.5-win32.egg\\numpy\\core\\include\\numpy"

module_dbr = Extension('dbr', sources=['dbr.c'], include_dirs=[
                       numpy_include_dir, dbr_include_dir], library_dirs=[dbr_lib_dir], libraries=['DBRx86'])

setup(name='DynamsoftBarcodeReader',
      version='1.0',
      description='Python barcode extension',
      ext_modules=[module_dbr])

Build the barcode extension module for Python 3

python3 setup.py build install

Command line app

Create test.py:

import os.path
import dbr
import cv2

def initLicense(license):
    dbr.initLicense(license)

def decodeFile(fileName):
    formats = 0x3FF | 0x2000000 | 0x8000000 | 0x4000000 # 1D, QRCODE, PDF417, DataMatrix
    results = dbr.decodeFile(fileName, formats)
    
    for result in results:
        print("barcode format: " + result[0])
        print("barcode value: " + result[1])

def decodeBuffer(image):
    formats = 0x3FF | 0x2000000 | 0x8000000 | 0x4000000 # 1D, QRCODE, PDF417, DataMatrix
    results = dbr.decodeBuffer(image, formats)
    
    for result in results:
        print("barcode format: " + result[0])
        print("barcode value: " + result[1])

if __name__ == "__main__":
    barcode_image = input("Enter the barcode file: ")
    if not os.path.isfile(barcode_image):
        print("It is not a valid file.")
    else:
        initLicense("Contact support@dynamsoft.com to get a valid license.")
        decodeFile(barcode_image)

Run the app:

python3 test.py

python3 barcode

Source code

https://github.com/dynamsoft-dbr/python-barcode-windows

The post How to Port C/C++ Barcode Extension to Python 3 appeared first on Code Pool.

Raspberry Pi Barcode Reader with DBR 5.2

$
0
0

Dynamsoft finally released Barcode Reader SDK v5.2 for Raspberry Pi. It is time to make an update. In this post, I will show you how to install the SDK, as well as how to write a simple Raspberry Pi barcode app using C/C++ and Python.

Installation

Tarball

Download dbr-rpi-5.2.0.tar.gz.

Extract the package:

tar -xvf dbr-rpi-5.2.0.tar.gz

Create a symlink for libDynamsoftBarcodeReader.so:

sudo ln –s <Your PATH>/libDynamsoftBarcodeReader.so /usr/lib/libDynamsoftBarcodeReader.so

Command line tool

Add public key:

wget -O - http://labs.dynamsoft.com/debian/conf/dbr.gpg.key | sudo apt-key add -

Add source to /etc/apt/sources.list:

deb http://labs.dynamsoft.com/debian/ dbr main non-free

Install Dynamsoft Barcode Reader:

sudo apt-get update && install dbr

Walkthrough of Raspberry Pi Barcode SDK

Getting started with C/C++ sample

Compile the built-in sample code:

cd <Package-root>/samples/c/
make
./BarcodeReaderDemo ../../images/Codabar.jpg

Barcode extension for Python 2 and Python 3

Create setup.py:

from distutils.core import setup, Extension
import os, numpy

numpy_include = os.path.join(os.path.dirname(numpy.__file__), "core", "include", "numpy")
print(numpy_include)
module_dbr = Extension('dbr',
                        sources = ['dbr.c'], 
                        include_dirs=[numpy_include, '<Path- DynamsoftBarcodeReader.h>'],
                        libraries=['DynamsoftBarcodeReader'])

setup (name = 'DynamsoftBarcodeReader',
        version = '5.2',
        description = 'Python barcode extension',
        ext_modules = [module_dbr])

Here I don’t explain dbr.c. If you are interested in the source code, please read How to Port C/C++ Barcode Extension to Python 3.

Build and install Python extension:

sudo python setup.py build install

Now we can quickly create a Raspberry Pi barcode app:

import os.path
import dbr

def initLicense(license):
    dbr.initLicense(license)

def decodeFile(fileName):
    formats = 0x3FF | 0x2000000 | 0x8000000 | 0x4000000 # 1D, QRCODE, PDF417, DataMatrix
    results = dbr.decodeFile(fileName, formats)
    
    for result in results:
        print("barcode format: " + result[0])
        print("barcode value: " + result[1])

def decodeBuffer(image):
    formats = 0x3FF | 0x2000000 | 0x8000000 | 0x4000000 # 1D, QRCODE, PDF417, DataMatrix
    results = dbr.decodeBuffer(image, formats)
    
    for result in results:
        print("barcode format: " + result[0])
        print("barcode value: " + result[1])

if __name__ == "__main__":
    barcode_image = input("Enter the barcode file: ")
    if not os.path.isfile(barcode_image):
        print("It is not a valid file.")
    else:
        initLicense("t0068MgAAAHtCgAPxEdCJN1bsu9n6YfnWDoaW7YZomIZZke2m9KynRnKSqsuQyd7Cdgo6razlb7VU3IFaKeBgg9Rq069Uihc=")
        decodeFile(barcode_image)

Create Shell scripts for SDK distribution

If you are a Python developer, you have to build the barcode module yourselves. We can use Shell scripts to automate the process.

Check CPU architectures for ARMv6 and ARMv7:

#!/bin/bash
CPU=$(lscpu)

ARMV6=$(echo $CPU | grep "armv6")
ARMV7=$(echo $CPU | grep "armv7")

if [ -n "${ARMV6}" ]
then
    echo "this is armv6"
    sudo ln -s $PWD/lib/armv6l/libDynamsoftBarcodeReader.so /usr/lib/libDynamsoftBarcodeReader.so
fi

if [ -n "${ARMV7}" ]
then
    echo "this is armv7"
    sudo ln -s $PWD/lib/armv7l/libDynamsoftBarcodeReader.so /usr/lib/libDynamsoftBarcodeReader.so
fi

Install essential packages for new environment:

sudo apt-get install python-dev python-pip
sudo pip install numpy

Build and install the Python module:

sudo python ./lib/python/setup.py build install

Remove the Python module:

#!/bin/bash
DBR_LIBRARY=$(python -c "import dbr; print(dbr.__file__)")
sudo rm "$DBR_LIBRARY"
sudo rm /usr/lib/libDynamsoftBarcodeReader.so

Raspberry Pi barcode SDK

Source Code

https://github.com/dynamsoft-dbr/raspberrypi-python-barcode

The post Raspberry Pi Barcode Reader with DBR 5.2 appeared first on Code Pool.

Building HTML5 Barcode Reader with Pure JavaScript SDK

$
0
0

Last week, I had successfully built JavaScript and WebAssembly ZXing barcode SDK. In this post, I will use the pure JavaScript barcode SDK to create a simple client-side HTML5 barcode reader app, which works in any WebRTC supported web browsers.

Supported Barcode Formats

Check ZXing source code to see what barcode formats are supported:

const DecodeHints DecodeHints::PRODUCT_HINT(
  UPC_A_HINT |
  UPC_E_HINT |
  EAN_13_HINT |
  EAN_8_HINT |
  RSS_14_HINT
  );

const DecodeHints DecodeHints::ONED_HINT(
  CODE_39_HINT |
  CODE_93_HINT |
  CODE_128_HINT |
  ITF_HINT |
  CODABAR_HINT |
  DecodeHints::PRODUCT_HINT
  );

const DecodeHints DecodeHints::DEFAULT_HINT(
  ONED_HINT |
  QR_CODE_HINT |
  DATA_MATRIX_HINT |
  AZTEC_HINT |
  PDF_417_HINT
  );

We can use DEFAULT_HINT to read all formats:

DecodeHints hints(DecodeHints::DEFAULT_HINT);
binarizer = new HybridBinarizer(source);
binary = new BinaryBitmap(binarizer);
results = decode_any_(binary, hints);

How to Open and Select Camera using HTML5

If you have no idea about how to use HTML5 to control cameras in WebRTC supported web browsers, visit https://simpl.info/getusermedia/sources/ to learn the source code:

var videoSelect = document.querySelector('select#videoSource');

navigator.mediaDevices.enumerateDevices()
  .then(gotDevices).then(getStream).catch(handleError);

videoSelect.onchange = getStream;

function gotDevices(deviceInfos) {
  for (var i = deviceInfos.length - 1; i >= 0; --i) {
    var deviceInfo = deviceInfos[i];
    var option = document.createElement('option');
    option.value = deviceInfo.deviceId;
    if (deviceInfo.kind === 'videoinput') {
      option.text = deviceInfo.label || 'camera ' +
        (videoSelect.length + 1);
      videoSelect.appendChild(option);
    } else {455
      console.log('Found one other kind of source/device: ', deviceInfo);
    }
  }
}

function getStream() {
  buttonGo.disabled = false;
  if (window.stream) {
    window.stream.getTracks().forEach(function(track) {
      track.stop();
    });
  }

  var constraints = {
    video: {
      deviceId: {exact: videoSelect.value}
    }
  };

  navigator.mediaDevices.getUserMedia(constraints).
    then(gotStream).catch(handleError);
}

function gotStream(stream) {
  window.stream = stream; // make stream available to console
  videoElement.srcObject = stream;
}

function handleError(error) {
  console.log('Error: ', error);
}

Note: when deploying the source code to your web server, you have to bind an SSL certificate. Otherwise, the camera cannot be opened, and you will see following warnings in Chrome console:

[Deprecation] getUserMedia() no longer works on insecure origins. To use this feature, you should consider switching your application to a secure origin, such as HTTPS. See https://goo.gl/rStTGz for more details.

Assume the web server is IIS, you can easily configure SSL certificate as follows:

SSL binding

HTML5 Barcode Reader

Basic steps

Draw video image to a temporary canvas:

  var barcodeCanvas = document.createElement("canvas");
  barcodeCanvas.width = vid.videoWidth;
  barcodeCanvas.height = vid.videoHeight;
  var barcodeContext = barcodeCanvas.getContext('2d');
  var imageWidth = vid.videoWidth, imageHeight = vid.videoHeight;
  barcodeContext.drawImage(videoElement, 0, 0, imageWidth, imageHeight);

Get image data from the canvas:

var imageData = barcodeContext.getImageData(0, 0, imageWidth, imageHeight);
var idd = imageData.data;

Copy pixels to a ZXing buffer:

var image = ZXing._resize(imageWidth, imageHeight);
  for (var i = 0, j = 0; i < idd.length; i += 4, j++) {
    ZXing.HEAPU8[image + j] = idd[i];
  }

Call ZXing._decode_any() to read barcode:

var err = ZXing._decode_any(decodePtr);

Testing Environment

Desktop Chrome 62.0.3202.94

Works for both JavaScript and WebAssembly ZXing.

Android Chrome 63.0.3239.111

Work for both JavaScript and WebAssembly ZXing.

iOS (11.2.1) Safari

iPhone does not support WebRTC well. I can successfully invoke cameras on iPad. However, WebAssembly is not supported.

Remotely Debugging HTML5 Barcode Reader

Enable USB debugging in Android developer settings.

Open Chrome on Android devices.

Connect Android devices to PC.

Open chrome://inspect in desktop Chrome:

Chrome inspect

Debug the app:

debug HTML5 barcode reader

Running HTML5 Barcode Reader in Android Chrome

Android HTML5 barcode reader

Source Code

https://github.com/yushulx/zxing-cpp-emscripten/tree/master/examples/js

https://github.com/yushulx/zxing-cpp-emscripten/tree/master/examples/wasm

The post Building HTML5 Barcode Reader with Pure JavaScript SDK appeared first on Code Pool.


Building .NET Barcode Reader with OpenCV and DBR 5.2

$
0
0

OpenCV is written in C++.  If you install OpenCV library on Windows, you will see OpenCV officially provides wrappers for Python and Java but not for C#. Fortunately, there are many .NET open source projects for wrapping OpenCV C++ APIs, and thus we don’t need to write a wrapper from scratch. In this post, I will share how to use OpenCV library and Dynamsoft Barcode Reader SDK to create a .NET barcode reader app on Windows.

Prerequisites

.NET Barcode Reader with OpenCV

I tried difference open source projects and finally decided to use OpenCvSharp which is continuously maintained by open source community.

Install OpenCvSharp and Dynamsoft Barcode Reader via Package Manager in Visual Studio. Tools >  NuGet Package Manager > Package Manager Console:

PM > Install-Package OpenCvSharp3-AnyCPU
PM> Install-Package Dynamsoft.DotNet.Barcode

Create a video capture object:

VideoCapture capture = new VideoCapture(0);

Get a video frame:

Mat image = capture.RetrieveMat();

Render the frame in a Window:

Cv2.ImShow("video", image);

Break the infinite loop when pressing ‘ESC’ key:

int key = Cv2.WaitKey(20);
// 'ESC'
if (key == 27)
{
    break;
}

Create a barcode reader object:

BarcodeReader reader = new BarcodeReader("t0068MgAAALLyUZ5pborJ8XVc3efbf4XdSvDAVUonA4Z3/FiYqz1MOHaUJD3d/uBmEtXVCn9fw9WIlNw6sRT/DepkdvVW4fs=");

To recognize barcodes, you can use DecodeBuffer() function. However, the type of the first parameter is byte[]. Now the biggest problem is how we can make the function work with Mat type.

Get the data pointer, width, height and element size as follows:

IntPtr data = image.Data;
int width = image.Width;
int height = image.Height;
int elemSize = image.ElemSize();
int buffer_size = width * height * elemSize;

Copy the data to a byte array:

using System.Runtime.InteropServices;
byte[] buffer = new byte[buffer_size];
Marshal.Copy(data, buffer, 0, buffer_size);

Decode the buffer and return barcode results:

BarcodeResult[] results = reader.DecodeBuffer(buffer, width, height, width * elemSize, ImagePixelFormat.IPF_RGB_888);
if (results != null)
{
    Console.WriteLine("Total result count: " + results.Length);
    foreach (BarcodeResult result in results)
    {
        Console.WriteLine(result.BarcodeText);
    }
}

Build and run the program:

.NET barcode reader with OpenCV

API References

Source Code

https://github.com/dynamsoft-dbr/opencv-dotnet

The post Building .NET Barcode Reader with OpenCV and DBR 5.2 appeared first on Code Pool.

The Preview of Dynamsoft Barcode Reader v6.0 for Windows

$
0
0

Dynamsoft Barcode Reader 6.0 is on the way. The major upgrade version improves the performance of barcode detection and recognition dramatically. It is over two times faster than version 5.2. In this post, I will disclose some new features and demonstrate the corresponding APIs.

Dynamsoft Barcode Reader SDK v6.0 Preview

Parameter templates

The new barcode SDK version aims to simplify API usage by dynamically loading customized parameter templates. A template is just a JSON file:

{
    "Version": "1.0",
    "ImageParameters": {
        "Name": "CUSTOM",
        "Timeout": 2147483647,
        "MaxImageDimension": 4000000,
        "PDFRasterDPI": 300,
        "ImageType": "AutoDetection",
        "TextFilterMode": "Enable",
        "MinImageDimensionToFilterText": 1000000,
        "RegionPredetectionMode": "Enable",
        "MinImageDimensionToPredetectRegion": 1000000,
        "LocalizationMode": "Lines",
        "BarcodeFormatIds": "ALL",
        "MaxBarcodesCount": 2147483647,
        "MaxThreadCount": 4,
        "DeblurLevel": 9,
        "Pages": "",
        "BarcodeInvertMode": "DarkOnLight"
    }
}

The key “Name” is necessary. Once you set a pair of key and value, it will overwrite the default one.

You can create as many as templates you like, and then add them to a global setting file default.settings.json:

{
    "Version": "1.0",
    "GlobalParameters": {
        "Name": "GLOBAL_DEFAULT",
        "MaxThreadCount": 4
    },
    "ParameterTemplateArray": [
        "custom.json",
	  "custom1.json",
	  "custom2.json",
    ]
}

Use function LoadSettingsFromFile() to load the global setting file.

int iRet = reader.LoadSettingsFromFile(templatePath, szErrorMsg, 256);

The templatePath has to be an absolute path. Usually, we put executable files and templates together. Use following C++ code to get the base path and compose the absolute path:

    char szErrorMsg[256];
    char basePath[255] = "";
    _fullpath(basePath, argv[0], sizeof(basePath));
    // Get the directory
    int iLast = 0;
    for (int i = 0; ; i++) {
        char tmp = basePath[i];
        if (tmp == '\\')
        {
            iLast = i;
        }
        else if (tmp == '\0')
        {
            break;
        }
    }

    char templatePath[1024];
    strncpy_s(templatePath, basePath, iLast);

    // Get the full path
    const char* pszSettingFile = "\\templates\\default.settings.json";
    strcat_s (templatePath, pszSettingFile);

API changes

The template feature is pretty convenient and flexible in my view. According to different scenes and cases, I don’t need always to modify my code. The only thing I need to do is to adjust the parameters in JSON file. To make the customized template work, set the template name when calling barcode detection API.

iRet = reader.DecodeFile(pszImageFile, "CUSTOM");

If you just provide a file name, the method will load default settings internally.

There is also some code difference between 5.2 and 6.0 when getting the barcode results.

dbr 5.2 vs. dbr 6.0

CMake: how to copy template directory to the output folder

After building the project, you have to copy the templates folder to the target directory if you use a path relative to the executable file. The command is copy_directory:

add_custom_command(TARGET BarcodeReader POST_BUILD 
        COMMAND ${CMAKE_COMMAND} -E copy_directory
        "${PROJECT_SOURCE_DIR}/templates"       
        $<TARGET_FILE_DIR:BarcodeReader>/"templates" )

Performance comparison: 5.2 vs. 6.0

Let’s take a glimpse of the performance comparison.

DBR v5.2

PS G:\cmake> .\build\Debug\BarcodeReader.exe G:\cmake\images\AllSupportedBarcodeTypes.tif
Barcode Reader Version 5.2
Total barcode(s) found: 13. Total time spent: 0.219 seconds

Dynamsoft Barcode Reader 5.2

DBR v6.0

PS F:\cmake\build> .\Debug\BarcodeReader.exe F:\cmake\images\AllSupportedBarcodeTypes.tif
Barcode Reader Version 6.0
Total barcode(s) found: 13. Total time spent: 0.094 seconds

Dynamsoft Barcode Reader 6.0 Preview

Dynamsoft Barcode Reader 6.0 is apparently the winner that has better performance and flexibility.

Source Code

https://github.com/dynamsoft-dbr/cmake/tree/6.0-preview

 

The post The Preview of Dynamsoft Barcode Reader v6.0 for Windows appeared first on Code Pool.

Things to Do with DBR 6.0 and Python Barcode Extension

$
0
0

Dynamsoft Barcode Reader 6.0 SDK is the best version ever. It dramatically improved barcode detecting speed and accuracy, especially for multiple barcodes per frame. Since there are some new APIs and parameters, I have to update both C++ and Python code for the Python barcode extension that was built with DBR 5.2 correspondingly.

Download

Setup.py for Building and Installing Python Barcode Extension

Import relevant modules.

from distutils.core import setup, Extension
import sys, os, numpy

from distutils.command.install import install

Dynamically get the header file directory of NumPy.

numpy_include = os.path.join(os.path.dirname(numpy.__file__), "core", "include", "numpy")

Set the library (.lib and .dll) paths of Dynamsoft Barcode Reader. To build the extension yourself, you have to replace following code with yours.

dbr_lib_dir = r'e:\Program Files (x86)\Dynamsoft\Barcode Reader 6.0\Components\C_C++\Lib'
dbr_dll = r'e:\Program Files (x86)\Dynamsoft\Barcode Reader 6.0\Components\C_C++\Redist\x86\DynamsoftBarcodeReaderx86.dll'

Specify parameters for Python extension.

module_dbr = Extension('dbr', sources=['dbr.c'], include_dirs=[
                       numpy_include], library_dirs=[dbr_lib_dir], libraries=['DBRx86'])

Create a customized class to extending installation command.

class CustomInstall(install):
      def run(self):
          install.run(self)
          import shutil
          from distutils.sysconfig import get_python_lib
          src = dbr_dll
          dst = get_python_lib()
          shutil.copy2(src, dst)

setup(name='dbr',
      version='6.0',
      description='Python barcode extension',
      author='Xiao Ling',
      author_email='xiao@dynamsoft.com',
      url='https://www.dynamsoft.com/Products/Dynamic-Barcode-Reader.aspx',
      license = 'https://www.dynamsoft.com/Products/barcode-reader-license-agreement.aspx',
      ext_modules=[module_dbr],
      long_description='Dynamsoft Barcode Reader is a software development toolkit which enables barcode recognition of Code 39, Code 129, QR Code, DataMatrix, PDF417.',
      platforms=['Windows'],
      cmdclass={'install': CustomInstall}
)

What does the customized class do? Distutils will build and install dbr.pyd to Python library directory but not include dependent DynamsoftBarcodeReaderx86.dll. I used to manually copy the file to the Python library directory, though, a smarter way is to trigger a post-install event and copy the file automatically.

Parameter Templates for Reading Barcode

Parameter template is a new feature of DBR 6.0. Instead of hardcoding parameters, we can now just modify a JSON file to make the application run differently without re-compile the source code.

barcode param template

Writing less code is cool.

python barcode dbr 6.0

Create a function to load the template.

static PyObject *
loadSettings(PyObject *self, PyObject *args)
{
    if (!createDBR()) 
    {
        return NULL;
    }

    char *pszSettingFile;
    if (!PyArg_ParseTuple(args, "s", &pszSettingFile)) {
        return NULL;
    }

    char szErrorMsg[256];
    int ret = DBR_LoadSettingsFromFile(hBarcode, pszSettingFile, szErrorMsg, 256);
    return Py_BuildValue("i", ret);
}

Create test.py. Put templates folder, which contains default.settings.json and custom.json, in the same directory. The default.settings.json file is for global settings. Usually, we do not need to edit it.

import os
import dbr
import cv2

def loadSettings(setting_file):
    dbr.loadSettings(setting_file)

def initLicense(license):
    dbr.initLicense(license)

def decodeFile(fileName):
    formats = 0x3FF | 0x2000000 | 0x8000000 | 0x4000000 # 1D, QRCODE, PDF417, DataMatrix
    results = dbr.decodeFile(fileName, formats, 'CUSTOM')
    
    for result in results:
        print("barcode format: " + result[0])
        print("barcode value: " + result[1])

def decodeBuffer(image):
    formats = 0x3FF | 0x2000000 | 0x8000000 | 0x4000000 # 1D, QRCODE, PDF417, DataMatrix
    results = dbr.decodeBuffer(image, formats, 'CUSTOM')
    
    for result in results:
        print("barcode format: " + result[0])
        print("barcode value: " + result[1])

if __name__ == "__main__":
    import sys
    if sys.version_info < (3, 0):
        barcode_image = raw_input("Enter the barcode file: ")
    else:
        barcode_image = input("Enter the barcode file: ")
        
    if not os.path.isfile(barcode_image):
        print("It is not a valid file.")
    else:
        initLicense("t0068MgAAABt/IBmbdOLQj2EIDtPBkg8tPVp6wuFflHU0+y14UaUt5KpXdhAxlERuDYvJy7AOB514QK4H50mznL6NZtBjITQ=")
        setting_file = os.path.join(os.getcwd(), 'templates', 'default.settings.json')
        loadSettings(setting_file)
        decodeFile(barcode_image)
        image = cv2.imread(barcode_image, 1)
        decodeBuffer(image)

Source Code

https://github.com/dynamsoft-dbr/python-barcode-windows

The post Things to Do with DBR 6.0 and Python Barcode Extension appeared first on Code Pool.

Updating PHP Barcode Extension for PHP7

$
0
0

Two years ago, I created a sample for demonstrating how to wrap Dynamsoft Barcode Reader 4.2, a C++ barcode library, as an extension for PHP5. How time flies, the latest barcode library is up to version 5.2. Meanwhile, many developers start to write web program in PHP7. This post will help PHP developers figure out how to build a PHP barcode reader on Ubuntu 16.04 with DBR 5.2 and PHP7.

Environment

Ubuntu 16.04

lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 16.04.3 LTS
Release:	16.04
Codename:	xenial

Installation

php7.0-cli, php7.0-dev and libxml2-dev

sudo apt-get install php7.0-cli php7.0-dev libxml2-dev

php-7.0.29 source code

DBR 5.2

  1. Add public key:
    wget -O - http://labs.dynamsoft.com/debian/conf/dbr.gpg.key | sudo apt-key add -
  2. Add source to /etc/apt/sources.list:
    deb http://labs.dynamsoft.com/debian/ dbr main non-free
  3. Install Dynamsoft Barcode Reader:
    sudo apt-get update && install dbr

Creating PHP Barcode Extension Step by Step

Unzip PHP source code and then change directory to ext.

tar -xzf php-7.0.29.tar.gz
cd ~/php-7.0.29/ext/

Create an extension directory.

./ext_skel --extname=dbr

PHP barcode extension

If you follow above guide, it will take time to build the whole project. We can use phpize to just build the extension that we created. Change directory to dbr folder and edit config.m4. What you need to do is to add the paths of the shared library (libDynamsoftBarcodeReader.so) and the header file(DynamsoftBarcodeReader.h).

PHP_ARG_ENABLE(dbr, whether to enable dbr support,
[  --enable-dbr           Enable dbr support])

if test "$PHP_DBR" != "no"; then

  LIBNAME=DynamsoftBarcodeReader
  LIBSYMBOL=DBR_CreateInstance

  PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL,
  [
  PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, /usr/lib, DBR_SHARED_LIBADD)
  AC_DEFINE(HAVE_DBRLIB,1,[ ])
  ],[
  AC_MSG_ERROR([wrong dbr lib version or lib not found])
  ],[
  -L$DBR_DIR/$PHP_LIBDIR -lm
  ])
  
  PHP_SUBST(DBR_SHARED_LIBADD)
  PHP_ADD_INCLUDE(/opt/dynamsoft/dbr/include)
  PHP_NEW_EXTENSION(dbr, dbr.c, $ext_shared)
fi

Configure and build the extension.

phpize
./configure
make

A shared library dbr.so will be generated under modules folder.

xiao@ubuntu:~/php-7.0.29/ext/dbr$ ls modules
dbr.so

Install extension to /usr/lib/php/20151012/dbr.so.

sudo make install

Add the following line to /etc/php/7.0/cli/php.ini.

extension=dbr.so

Open dbr.c. Create a function DecodeBarcodeFile().

PHP_FUNCTION(DecodeBarcodeFile)
{
    array_init(return_value);
	
    // Get Barcode image path
    char *pFileName;
    long barcodeType = 0;
    size_t iLen;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &pFileName, &iLen, &barcodeType) == FAILURE) {
        RETURN_STRING("Invalid parameters");
    } 

    void* hBarcode = DBR_CreateInstance();
    if (hBarcode)
    {
	DBR_InitLicenseEx(hBarcode, "t0068MgAAAL0RPbQ2oYpnm7QMnz7rxs8rigQLePZ2NF33syCm5HOcdW17XO3YlMzEwfB9J5HrbUfMWIB97szrsUsCtDW1X78=");
	
	int iMaxCount = 0x7FFFFFFF;
	SBarcodeResultArray *pResults = NULL;
	DBR_SetBarcodeFormats(hBarcode, barcodeType);
	DBR_SetMaxBarcodesNumPerPage(hBarcode, iMaxCount);	
	
	// Barcode detection
    	int ret = DBR_DecodeFileEx(hBarcode, pFileName, &pResults);
	
	if (pResults)
	{
	    int count = pResults->iBarcodeCount;
	    SBarcodeResult** ppBarcodes = pResults->ppBarcodes;
	    SBarcodeResult* tmp = NULL;
	    int i = 0;

	    for (; i < count; i++)
	    {
		tmp = ppBarcodes[i];
		zval tmp_array;
		array_init(&tmp_array);
		add_next_index_string(&tmp_array, tmp->pBarcodeFormatString);
		add_next_index_string(&tmp_array, tmp->pBarcodeData);
		add_next_index_zval(return_value, &tmp_array);
	    }
	    DBR_FreeBarcodeResults(&pResults);
	}


	if (hBarcode) {
            DBR_DestroyInstance(hBarcode);
    	}
    }
}

const zend_function_entry dbr_functions[] = {
	PHP_FE(DecodeBarcodeFile,   NULL) 
	PHP_FE_END	/* Must be the last line in dbr_functions[] */
};

Note: when parsing the parameters, the type of string length has to be size_t not int. I remember int is fine in PHP5, but it will fail to get the string value in PHP7. In addition, the way of creating an array is changed as well.

zval tmp_array;
array_init(&tmp_array);

Re-build and re-install the extension.

make
sudo make install

Create a simple PHP barcode reader.

<?php

$filename = "/opt/dynamsoft/dbr/images/AllSupportedBarcodeTypes.tif";
if (file_exists($filename)) {
  echo "Barcode file: $filename \n";
  /*
   * Description:
   * array DecodeBarcodeFile( string $filename , long $type )
   *
   * Returned value:
   * If succeed, it is an array.
   */
  $resultArray = DecodeBarcodeFile($filename, 0x3FF | 0x2000000 | 0x8000000 | 0x4000000);
  if (is_array($resultArray)) {
	$resultCount = count($resultArray);
	echo "Total count: $resultCount\n";
	for($i = 0; $i < $resultCount ; $i++) {
		$result = $resultArray[$i];
        	echo "Barcode format: $result[0], value: $result[1]\n";
	}
  }
  else {
    echo "$resultArray[0]";
  }
} else {
    echo "The file $filename does not exist";
}
?>

Run the script.

php -c /etc/php/7.0/cli/php.ini reader.php

PHP barcode reader

Source Code

https://github.com/dynamsoft-dbr/linux-php-barcode-reader-

The post Updating PHP Barcode Extension for PHP7 appeared first on Code Pool.

JSON Schema for Dynamsoft Barcode Reader Template Files

$
0
0

If you have tried out Dynamsoft Barcode Reader 6.0, you may have noticed the new template feature. The new SDK version supports importing parameters from JSON-format template files. How to create the template files? One way is to visit the barcode online demo, select some arguments and then download the template file. The other way is to write a JSON file by yourself. When writing a JSON file line by line, there is a problem that how to write valid data. The workaround is JSON Schema. JSON Schema is a vocabulary that allows you to annotate and validate JSON documents. To facilitate developers, I created a basic JSON Schema for Dynamsoft Barcode Reader template files.

JSON Schema for IntelliSense in Visual Studio Code

Visual Studio Code features IntelliSense which helps developers quickly write code. To use IntelliSense for JSON files, you need to configure JSON schema in user settings. Press F1 to open user settings and search for ‘json schema’. By default, there is an empty array. You can read vscode-docs to learn how to add custom JSON schemas for corresponding JSON files.

JSON schema in VS Code

Get started with examples

Here is a basic example of a JSON schema from JSON Schema example page.

{
    "title": "Person",
    "type": "object",
    "properties": {
        "firstName": {
            "type": "string"
        },
        "lastName": {
            "type": "string"
        },
        "age": {
            "description": "Age in years",
            "type": "integer",
            "minimum": 0
        }
    },
    "required": ["firstName", "lastName"]
}

We can visit understanding-json-schema to figure out how these keywords work for JSON.

  • The title must be a string, which is a short description of the purpose of the data. For long words description, you can add a description keyword.
  • The type specifies the data type for a schema. The basic types include string, number, object, array, Boolean and null. For example, assume you set name with the string type, if you create a JSON instance and set name with number type, you will get an error hint.
  • The properties is an object, where each key is the name of a property and each value is a JSON schema used to validate that property.
  • The required keyword takes an array of one or more strings. Each of these strings must be unique. Missing the required property makes the JSON document invalid.

Quickly Creating Dynamsoft Barcode Reader templates in VS Code

Create dbr.json:

{
    "title": "JSON schema for DBR configuration files",
    "$schema": "http://json-schema.org/draft-04/schema#",
    "description": "A representation of Dynamsoft Barcode Reader template.",
    "type": "object",
    "required": ["Version", "ImageParameters"],
    "properties": {
        "Version": {
            "description": "The template version number.",
            "type": "string",
            "enum": [
                "1.0"
            ]
        },
        "ImageParameters": {
            "description": "Parameters for barcode detection",
            "type": "object",
            "required": [
                "Name"
            ],
            "properties": {
                "Name": {
                    "description": "The name of the ImageParameters object",
                    "type": "string",
                    "maxLength": 50,
                    "minLength": 1
                },
                "Description": {
                    "description": "The description of the ImageParameters object",
                    "type": "string"
                },
                "BarcodeFormatIds": {
                    "description": "Sets which types of barcode to be read. Barcode types can be combined",
                    "type": "array",
                    "items": {
                        "type": "string",
                        "enum": [
                            "All", "OneD", "CODE_39", "CODE_128", "CODE_93", "CODABAR", "ITF", "EAN_13", "EAN_8", "UPC_A", "UPC_E", "INDUSTRIAL_25", "PDF417", "QR_CODE", "DATAMATRIX"
                        ]
                    }
                },
                "MaxBarcodesCount": {
                    "description": "Sets the maximum number of barcodes to read",
                    "type": "number",
                    "maximum": 2147483647,
                    "minimum": 1,
                    "default": 2147483647
                },
                "Timeout": {
                    "description": "Sets the maximum amount of time (in milliseconds) it should spend searching for a barcode per page",
                    "type": "number",
                    "maximum": 2147483647,
                    "minimum": 0,
                    "default": 2147483647
                },
                "ScaleDownThreshold": {
                    "description": "Sets the threshold value of the image shrinking",
                    "type": "number",
                    "maximum": 2147483647,
                    "minimum": 512,
                    "default": 2048
                },
                "DeblurLevel": {
                    "description": "The blurriness of the barcode",
                    "type": "number",
                    "maximum": 9,
                    "minimum": 0,
                    "default": 5
                }
            }
        }
    }
}

Copy the file to barcode project root directory.

Add the configuration to user settings.

"json.schemas": [
{
    "fileMatch": [
        "/tpl_*.json"
    ],
    "url": "./dbr.json"
}]

Create a template file started with ‘tpl_’.

Customize your parameter template for Dynamsoft Barcode Reader SDK.

Creating dbr template in Visual Studio Code

Source Code

https://github.com/dynamsoft-dbr/template-json-schema

The post JSON Schema for Dynamsoft Barcode Reader Template Files appeared first on Code Pool.

Node.js Barcode Extension with DBR 6.0

$
0
0

When searching for barcode SDK online, you can find lots of free and commercial SDKs. However, there are only a few of SDKs cross-platform, which is why Dynamsoft Barcode Reader is outstanding. Dynamsoft Barcode Reader SDK supports Windows, Linux, macOS, Android, iOS, and Raspberry Pi. Currently, the latest DBR 6.0 is better and faster than the previous version. The imperfection is it only supports Windows so far. If you need an SDK available for all platforms, please choose DBR 5.2. The post will help developers create a Node.js barcode reader with DBR 6.0 on Windows.

Prerequisites

Creating Node.js Barcode Extension Using C/C++

Node-gyp

To build C/C++ code, install node-gyp:

npm install -g node-gyp

Create binding.gyp file:

{
  "targets": [
    {
      'target_name': "dbr",
      'sources': [ "dbr.cc" ],
      'conditions': [
          ['OS=="win"', {
            'defines': [
              'WINDOWS_DBR',
            ],
            'include_dirs': [
                "E:\\Program Files (x86)\\Dynamsoft\\Barcode Reader 6.0\\Components\\C_C++\\Include"
            ],
            'libraries': [
                "-lE:\\Program Files (x86)\\Dynamsoft\\Barcode Reader 6.0\\Components\\C_C++\\Lib\\DBRx64.lib"
            ],
            'copies': [
            {
              'destination': 'build/Release/',
              'files': [
                'E:\\Program Files (x86)\\Dynamsoft\\Barcode Reader 6.0\\Components\\C_C++\\Redist\\x64\\DynamsoftBarcodeReaderx64.dll'
              ]
            }]
          }]
      ]
    }
  ]
}
  • ‘dbr.cc’: the C/C++ source file.
  • ‘include_dir’: DynamsoftBarcodeReader.h header file directory.
  • ‘libraries’: linking DBRx64.lib.
  • ‘copies’: copy DynamsoftBarcodeReaderx64.dll to the output folder.

Build Node.js extension:

node-gyp configure
node-gyp build

C/C++ APIs

Create native methods:

#include <node.h>
#include <node_buffer.h>
#include <string.h>
#include <uv.h>
#include "DynamsoftBarcodeReader.h"

using namespace v8;

void Init(Handle<Object> exports) {
    NODE_SET_METHOD(exports, "create", Create);
    NODE_SET_METHOD(exports, "destroy", Destroy);
    NODE_SET_METHOD(exports, "decodeYUYVAsync", DecodeYUYVAsync);
    NODE_SET_METHOD(exports, "decodeFileStreamAsync", DecodeFileStreamAsync);
    NODE_SET_METHOD(exports, "initLicense", InitLicense);
    NODE_SET_METHOD(exports, "decodeFileAsync", DecodeFileAsync);
    NODE_SET_METHOD(exports, "loadTemplates", LoadTemplates);
}

NODE_MODULE(dbr, Init)

DBR 6.0 allows developers to create and load parameter templates using JSON files.

void LoadTemplates(const FunctionCallbackInfo<Value>& args) 
{
    if (!createDBR()) {return;}

    Isolate* isolate = Isolate::GetCurrent();
    HandleScope scope(isolate);

    // Get arguments.
    String::Utf8Value fileName(args[0]->ToString()); // file name
    char *pszFileName = *fileName;

    // Load the template file.
    char szErrorMsg[256];
    DBR_LoadSettingsFromFile(hBarcode, pszFileName, szErrorMsg, 256);
}

Decode a file stream:

DBR_DecodeFileInMemory(hBarcode, worker->buffer, worker->size, worker->templateName);

Decode a file:

DBR_DecodeFile(hBarcode, worker->filename, worker->templateName);

How to detect barcodes

Here are the necessary steps of reading barcodes:

  1. Create an instance of the barcode reader.
  2. Set a valid license.
  3. Load a template.
  4. Invoke barcode reading APIs with a template name.
  5. Destroy the barcode reader.

Node.js Barcode Reader

Create a test.js file.

Get current directory to construct the template file path.

var templateFile = path.join(process.cwd(), 'templates', 'default.settings.json');

Initialize license and parameter template.

dbr.initLicense(
    "t0068MgAAACItg+NVEOPRujuNx/KXoEsTqRKBAkSCJjwJZZJt/fb7dYfsd/S86yrjQL0KvqHQ6wfh9/Xgu7MwiTqbEnAFFyA=");
dbr.loadTemplates(templateFile);

Read barcodes from an image file:

function decodeFileAsync(fileName) {
  dbr.decodeFileAsync(fileName, barcodeTypes, function(err, msg) {
    let result = null;
    for (index in msg) {
      result = msg[index];
      console.log("Format: " + result['format']);
      console.log("Value : " + result['value']);
      console.log("##################");
    }
  }, "CUSTOM");
}

Node.js barcode reader

Source Code

https://github.com/yushulx/nodejs-barcode-for-win-linux-mac/tree/DBR6.0

The post Node.js Barcode Extension with DBR 6.0 appeared first on Code Pool.

Why You Should Use A Commercial Barcode SDK for Business

$
0
0

ZXing is probably the most popular open source barcode SDK in the world. The library is written in Java and now has been ported to C++, .NET, Python, Objective-C, PHP and some other programming languages. Because ZXing is free, many developers would like to build barcode scanning apps with it. However, it is not competent for complicated business cases especially for images with multiple barcodes. In this article, I will show how to create a .NET barcode reader step by step and compare the performance difference between ZXing.Net and Dynamsoft Barcode Reader.

ZXing vs. Dynamsoft Barcode SDK

Supported Barcode Types

ZXing

UPC-A, UPC-E, EAN-8, EAN-13, Code 39, Code 93, Code 128, ITF, Codabar, MSI, RSS-14 (all variants), QR Code, Data Matrix, Aztec and PDF-417.

Dynamsoft Barcode Reader

Code 39, Code 93, Code 128, Codabar, EAN-8, EAN-13, UPC-A, UPC-E, Interleaved 2 of 5 (ITF), Industrial 2 of 5 (Code 2 of 5 Industry, Standard 2 of 5, Code 2 of 5), ITF-14, QRCode, DataMatrix and PDF417.

.NET Command Line Barcode Reader

Create a new Console Application in Visual Studio.

console barcode project

On the menu, Select Tools > NuGet Package Manager > Package Manager Console to install Dynamsoft Barcode Reader and ZXing.Net.

Install-Package Dynamsoft.DotNet.Barcode
Install-Package ZXing.Net

Alternatively, you can install DynamsoftBarcodeReader6.1.exe and then right-click references to import the library to the project.

dynamsoft barcode reader

Besides, you have to add System.Drawing framework.

dotnet drawing

List all files in an image folder:

string[] files = Directory.GetFiles(directory);

Load an image file to bitmap:

Bitmap barcodeBitmap = (Bitmap)Image.FromFile(file);

Note: The Image class does not support PDF format. If the input file is PDF, it will throw an exception.

Read multiple barcodes with ZXing:

ZXing.MultiFormatReader multiFormatReader = new ZXing.MultiFormatReader();
ZXing.Multi.GenericMultipleBarcodeReader multiBarcodeReader = new ZXing.Multi.GenericMultipleBarcodeReader(multiFormatReader);
LuminanceSource source = new BitmapLuminanceSource(bitmap);
ZXing.BinaryBitmap bBitmap = new ZXing.BinaryBitmap(new HybridBinarizer(source));
ZXing.Result[] zResults = multiBarcodeReader.decodeMultiple(bBitmap);

Read barcodes with Dynamsoft Barcode Reader:

Dynamsoft.Barcode.BarcodeReader reader = new Dynamsoft.Barcode.BarcodeReader();
reader.LicenseKeys = "t0068NQAAAJx5X8TaH/zQIy0Mm3HHIypzFTL+DQTIQah1eCiNcZygsi6sFa0cZiJVv+rRTyU29TpFsLA6hWiz+GAlQlGrRRg=";
TextResult[] results = reader.DecodeBitmap(barcodeBitmap, "");

Use Stopwatch to monitor the time cost:

Stopwatch swDBR = Stopwatch.StartNew();
swDBR.Stop();
Console.WriteLine(swDBR.Elapsed.TotalMilliseconds + "ms");

Beautify the output by string format:

Console.WriteLine("{0, -10}{1, -20}{2, -20}", "DBR", "time: " + swDBR.Elapsed.TotalMilliseconds + "ms", " result count: " + results.Length);
Console.WriteLine("{0, -10}{1, -20}{2, -20}", "ZXing", "time: " + swZXing.Elapsed.TotalMilliseconds + "ms", " result count: " + zResults.Length);

We can also color the output to differ the results:

Console.BackgroundColor = ConsoleColor.Blue;
Console.WriteLine("{0, -10}{1, -20}{2, -20}", "ZXing", "time: " + swZXing.Elapsed.TotalMilliseconds + "ms", " result count: " + zResults.Length);
Console.ResetColor();
Console.BackgroundColor = ConsoleColor.Red;
Console.WriteLine("{0, -10}{1, -20}{2, -20}", "DBR", "time: " + swDBR.Elapsed.TotalMilliseconds + "ms", " result count: " + results.Length);
Console.ResetColor();

Build and run the application with testing images.

dbr-zxing.exe [image folder]

barcode sdk performance

According to the result, we can see when detecting multiple barcodes, ZXing performs terribly. Dynamsoft Barcode Reader as a commercial barcode SDK is much faster and more accurate. If you want to create a business solution, such as document scanning and management based on barcodes, you’d better choose a commercial barcode SDK rather than ZXing.

Source Code

https://github.com/yushulx/dynamsoft-barcode-reader-vs-zxing

The post Why You Should Use A Commercial Barcode SDK for Business appeared first on Code Pool.


The Preview of Dynamsoft WebAssembly Barcode SDK

$
0
0

WebAssembly (Wasm) is a revolutionary technology for Web development. It aims to execute at native speed in web browsers. With WebAssembly, it is convenient to port C/C++ code for web client and server applications. Dynamsoft Barcode Reader 6.2 is the most potent barcode SDK ever, and its WebAssembly edition is on the way. Let’s see what we can do with the preview edition of Dynamsoft WebAssembly barcode SDK.

Browser Compatibility

Visit MDN to check the browser compatibility.

wasm browser

Testing Environment

  • Chrome Version 67.0.3396.99
  • IIS
  • Windows 10

License

To use the SDK, apply for a valid license beforehand.

WebAssembly Barcode SDK

Parameter Initialization

Configure parameters. Replace the license key with yours.

var dynamsoft = self.dynamsoft || {};
var reader;
dynamsoft.dbrEnv = dynamsoft.dbrEnv || {};
dynamsoft.dbrEnv.resourcesPath = "https://tst.dynamsoft.com/demo/DBR_WASM";
dynamsoft.dbrEnv.licenseKey = "t0068NQAAAFEiYhAfkotGqCdX6THMV7KARQKp5h14F7LrM4LoGND9F5AdXykh+TOYHnBnMw80FMeKjMJbieYYos5dYLSn/Do=";
dynamsoft.dbrEnv.onAutoLoadWasmSuccess = function () {
  reader = new dynamsoft.BarcodeReader();
};
dynamsoft.dbrEnv.onAutoLoadWasmError = function (status) {
  
};

After setting parameters, include dynamsoft.barcodereader.min.js at the bottom of your HTML page.

<script src="https://tst.dynamsoft.com/demo/DBR_WASM/dynamsoft.barcodereader.min.js"></script>

Loading .wasm file

It takes a while to download the dynamsoft.barcodereader.wasm file.

dynamsoft barcode wasm

Caching with IndexedDB

The .wasm file will be cached in IndexedDB. When you refresh or open the page next time, the loading speed is faster.

wasm IndexedDB

Reading barcodes

With Dynamsoft WebAssembly barcode SDK, you can detect barcodes from different input sources. Here are the available methods:

function decodeFileInMemery(FileName)
function decodeVideo(HTMLVideoElement)
function decodeBase64String(String)
function decodeBuffer(Blob | ArrayBuffer | Uint8Array)

Read an image file loaded via HTML <input> tag.

let image = document.getElementById('uploadImage').files[0];
if (image) {
    reader.decodeFileInMemery(image).then(results => {
        let txts = [];
        for (let i = 0; i < results.length; ++i) {
            txts.push(results[i].BarcodeText);
        }
        barcode_result.textContent = txts.join(", ");
    });
}

Render video frames on canvas and use the corresponding ArrayBuffer for barcode detection.

var imageData = barcodeContext.getImageData(0, 0, imageWidth, imageHeight);
var idd = imageData.data;
reader.decodeBuffer(idd.buffer, imageWidth, imageHeight, imageWidth * 4, dynamsoft.BarcodeReader.EnumImagePixelFormat.IPF_ARGB_8888).then(
    results => {
        let txts = [];
        for (var i = 0; i < results.length; ++i) {
            if (results[i].LocalizationResult.ExtendedResultArray[0].Confidence >= 30) {
                txts.push(results[i].BarcodeText);
            }
        }
    }
);

Read one or multiple barcodes in Desktop Chrome:

webassembly barcode detection

The web app is also compatible with mobile browsers.

webassembly barcode dynamsoft

For more information about the WebAssembly barcode SDK, please contact support@dynamsoft.com.

Source Code

https://github.com/yushulx/webassembly-barcode-reader

The post The Preview of Dynamsoft WebAssembly Barcode SDK appeared first on Code Pool.

JavaScript Barcode SDK: Native vs. WebAssembly

$
0
0

A JavaScript barcode SDK can be built in C/C++ for high performance. We can compile C/C++ code to a Node.js addon or WebAssembly. Which one is superior? Let’s try Dynamsoft Barcode Reader SDK to find the answer.

Node.js C++ Addon vs. WebAssembly

Speed

Performance is vital for SDK. According to our common sense, C++ addon should be the winner. However, it is interesting to see the performance gap when running C++ addon and WebAssembly in Node.js app.

Build C++ addon for Node.js

Download Dynamsoft Barcode Reader 6.2. You can choose one edition of Windows, Linux, and macOS. Here I use the Linux edition.

Get the sample code.

Copy libDynamsoftBarcodeReaderx64.so to /usr/lib:

sudo cp <Your PATH>/libDynamsoftBarcodeReaderx64.so /usr/lib/libDynamsoftBarcodeReader.so

Install node-gyp:

npm install -g node-gyp

Configure the building environment:

node-gyp configure

Build the extension:

node-gyp build

Install WebAssembly barcode SDK

npm install dbrjs

Create a simple Node.js barcode reader

var dbr = require('./build/Release/dbr');
var Module = require('dbrjs');

function decodeFileStreamAsync(fileName) {
  let stats = fs.statSync(fileName);
  let fileSize = stats["size"];

  fs.open(fileName, 'r', function(status, fd) {
    if (status) {
      console.log(status.message);
      return;
    }

    var source = fs.readFileSync(fileName);
      var typedArray = new Uint8Array(source);
      
      Module.onRuntimeInitialized = function() {
          let dbr = new Module.BarcodeReaderWasm("t0068NQAAAKTSQDbEid8CTEeNluhTXi+h35G8R03xIHsyYNzZoa2GiU2a8y7s5Z1lfHsMW5dNyZmH6jQL51HUcoB5EhpDeDk=");
          console.time('wasm');
          let results = dbr.DecodeFileInMemory(typedArray, "");
          console.timeEnd('wasm');
          let json = JSON.parse(results);
          let barcodeResults = json['textResult'];
          let txts = [];
          for (let i = 0; i < barcodeResults.length; ++i) {
              console.log("Value : " + Buffer.from(barcodeResults[i].BarcodeText, 'base64').toString('ascii'));
            }
            console.log("Done............................................................\n");
      };
      
    let buffer = new Buffer(fileSize);
    fs.read(fd, buffer, 0, fileSize, 0, function(err, bytesRead, data) {
      console.time('native');
      dbr.decodeFileStreamAsync(buffer, fileSize, barcodeTypes, function(err, msg) {
        console.timeEnd('native');
        let result = null;
        for (index in msg) {
          result = msg[index];
          // console.log("Format: " + result['format']);
          console.log("Value : " + result['value']);
        }
        console.log("Done............................................................\n");
      }, "");
    });
  });
}

Run the app to check the results.

Node.js Native vs WebAssembly

It turns out Node.js C++ addon is much faster than WebAssembly.

Portability

Although C++ addon has excellent performance, you have to use different compilers to rebuild it on different platforms. In contrast with C++ addon, WebAssembly is portable. If you have a Linux subsystem installed in Windows, you can quickly test the Node.js barcode reader by switching Linux and Windows.

WebAssembly for Linux and Windows

Web app development

Node.js C++ addon can only work on server-side, whereas WebAssembly can work on both server-side and client-side. To create an HTML5 barcode reader for web browsers, you can either implement a RESTful web service with C++ addon or build it with WebAssembly SDK.

Example: How to Use Dynamsoft WebAssembly Barcode SDK

Node.js

Create index.js:

const fs = require('fs');
var source = fs.readFileSync('test.jpg');
var typedArray = new Uint8Array(source);
const Module = require('dbrjs');
Module.onRuntimeInitialized = function() {
    let dbr = new Module.BarcodeReaderWasm("t0068NQAAAKTSQDbEid8CTEeNluhTXi+h35G8R03xIHsyYNzZoa2GiU2a8y7s5Z1lfHsMW5dNyZmH6jQL51HUcoB5EhpDeDk=");
    console.time('wasm');
    let results = dbr.DecodeFileInMemory(typedArray, "");
    console.timeEnd('wasm');
    let json = JSON.parse(results);
    let barcodeResults = json['textResult'];
    let txts = [];
    for (let i = 0; i < barcodeResults.length; ++i) {
        txts.push(Buffer.from(barcodeResults[i].BarcodeText, 'base64').toString('ascii'));
      }
    console.log(txts.join(", "));
};

Run the app:

node index.js

Web

var reader;
c.onRuntimeInitialized = function () {
  document.getElementById('anim-loading').style.display = 'none';
  buttonFile.disabled = false;
  buttonVideo.disabled = false;
  reader = new c.BarcodeReaderWasm("t0068NQAAAKTSQDbEid8CTEeNluhTXi+h35G8R03xIHsyYNzZoa2GiU2a8y7s5Z1lfHsMW5dNyZmH6jQL51HUcoB5EhpDeDk=");
};
 
if (reader) {
    try {
        // results = reader.DecodeBuffer(idd.buffer, imageWidth, imageHeight, imageWidth * 4, 7, "");
        let results = reader.DecodeFileInMemory(arrayBuffer, "");
        let json = JSON.parse(results);
        let barcodeResults = json['textResult'];
        let txts = [];
        for (let i = 0; i < barcodeResults.length; ++i) {
          txts.push(b64DecodeUnicode(barcodeResults[i].BarcodeText));
        }
        barcode_result.textContent = txts.join(", ");
      } catch (e) {
        console.log(e);
      }
}

Dynamsoft WebAssembly Barcode SDK

Conclusion

If you pursue extreme performance for Node.js, choose C++ addon. If the performance gap is not a big deal for you, WebAssembly is no doubt the best choice.

License

Get the trial license.

Source Code

https://github.com/dynamsoft-dbr/webassembly

The post JavaScript Barcode SDK: Native vs. WebAssembly appeared first on Code Pool.

Using Web Worker to Load WebAssembly Barcode SDK

$
0
0

Web Worker is a way to run JavaScript in background threads. The worker thread can perform some heavy works without interfering with the user interface. This article shares how to load WebAssembly and invoke Dynamsoft JavaScript barcode APIs in a web worker.

Web Worker for WASM

If you have tried the ‘hello world’ example of Dynamsoft JavaScript Barcode SDK, you should know that the SDK is built based on WebAssembly technology, which allows you to develop web client-side barcode reader app in pure JavaScript. The simple example demonstrates how to decode barcode from an input file.

However, in most scenarios, a web barcode reader features real-time decoding for camera video stream. The principle for building a camera app is don’t block the UI thread. If you call the barcode API in JavaScript main thread and the API takes more than 100ms to decode barcodes, the UI cannot render smoothly. That is why we need to use web workers.

When using WebAssembly, it may take a long time to download and compile the wasm file. Dynamsoft provides two JavaScript barcode editions built with different optimization levels which influence the final wasm file size and initialization time. In worker.js, add the following code:

function browserRedirect() {
    var deviceType;
    var sUserAgent = navigator.userAgent.toLowerCase();
    var bIsIpad = sUserAgent.match(/ipad/i) == "ipad";
    var bIsIphoneOs = sUserAgent.match(/iphone os/i) == "iphone os";
    var bIsMidp = sUserAgent.match(/midp/i) == "midp";
    var bIsUc7 = sUserAgent.match(/rv:1.2.3.4/i) == "rv:1.2.3.4";
    var bIsUc = sUserAgent.match(/ucweb/i) == "ucweb";
    var bIsAndroid = sUserAgent.match(/android/i) == "android";
    var bIsCE = sUserAgent.match(/windows ce/i) == "windows ce";
    var bIsWM = sUserAgent.match(/windows mobile/i) == "windows mobile";
    if (bIsIpad || bIsIphoneOs || bIsMidp || bIsUc7 || bIsUc || bIsAndroid || bIsCE || bIsWM) {
      deviceType = 'phone';
    } else {
      deviceType = 'pc';
    }
    return deviceType;
}

if (browserRedirect() === 'pc') {
    importScripts('https://demo.dynamsoft.com/dbr_wasm/js/dbr-6.3.0.1.min.js');
}
else {
    importScripts('https://demo.dynamsoft.com/dbr_wasm/js/dbr-6.3.0.1.mobile.min.js');
}

To load the WebAssembly in iOS Safari with less time, use  https://demo.dynamsoft.com/dbr_wasm/js/dbr-6.3.0.1.mobile.min.js.

Initialize the barcode reader:

var reader;
var dynamsoft = self.dynamsoft || {};
dynamsoft.dbrEnv = dynamsoft.dbrEnv || {};
dynamsoft.dbrEnv.resourcesPath = 'https://demo.dynamsoft.com/dbr_wasm/js/';

dynamsoft.dbrEnv.onAutoLoadWasmSuccess = function () {
    reader = new dynamsoft.BarcodeReader();
    postMessage({
        event: "onload",
        body: "Successfully loaded wasm."
    });
};
dynamsoft.dbrEnv.onAutoLoadWasmError = function (status) {
    postMessage({
        event: "onerror",
        body: "Failed to load wasm."
    });
};
//https://www.dynamsoft.com/CustomerPortal/Portal/TrialLicense.aspx
dynamsoft.dbrEnv.licenseKey = "t0068MgAAAD2IrA1WJjiVx78RfaZ46qMyCY8DaqpvAD57z5QWkwVQkVwZEf7lE+M2QYbnPx9Fu/aFvCL1mz0Kh2YK0milUng=";

Wait for barcode decoding event:

onmessage = function (e) {
    e = e.data;
    switch (e.type) {
        case "decodeBuffer":
            {
                self.reader.decodeBuffer(e.body, e.width, e.height, e.width * 4, dynamsoft.BarcodeReader.EnumImagePixelFormat.IPF_ARGB_8888).then(results => {
                    postMessage({
                        event: 'onresult',
                        body: results
                    });
                }).catch(ex => {
                    postMessage({
                        event: 'onresult',
                        body: 'No barcode detected'
                    });
                });
                break;
            }
        default:
            break;
    }
};

In the main thread, create the web worker:

if (window.Worker) {
  myWorker = new Worker('worker.js');
  myWorker.onmessage = function (e) {
    let data = e.data;
    if (data.event) {
      switch (data.event) {
        case 'onload':
          {
            document.getElementById('anim-loading').style.display = 'none';
            buttonFile.disabled = false;
            buttonVideo.disabled = false;
            break;
          }
        case 'onerror':
          {
            document.getElementById('anim-loading').style.display = 'none';
            break
          }
        case 'onresult':
          {
            let context = clearOverlay();

            let txts = [];
            try {
              let results = data.body;
              let localization;
              for (var i = 0; i < results.length; ++i) {
                if (results[i].LocalizationResult.ExtendedResultArray[0].Confidence >= 30) {
                  txts.push(results[i].BarcodeText);
                  localization = results[i].LocalizationResult
                  if (isVideoMode) {
                    drawResult(context, localization, results[i].BarcodeText);
                  }
                }
              }
              barcode_result.textContent = txts.join(', ');

              if (isVideoMode) {
                scanBarcode();
              }
            } catch (e) {
              if (isVideoMode) {
                scanBarcode();
              } else {
                barcode_result.textContent = data.body;
              }
            }

            break;
          }
      }
    }
  };
}

Capture a frame from the video and send it to the web worker:

function scanBarcode() {

  let context = ctx,
    width = videoWidth,
    height = videoHeight;

  context.drawImage(videoElement, 0, 0, width, height);
  var barcodeCanvas = document.createElement("canvas");
  barcodeCanvas.width = width;
  barcodeCanvas.height = height;
  var barcodeContext = barcodeCanvas.getContext('2d');
  barcodeContext.drawImage(videoElement, 0, 0, width, height);
  // read barcode
  if (myWorker) {
    myWorker.postMessage({
      type: 'decodeBuffer',
      body: barcodeContext.getImageData(0, 0, width, height).data,
      width: width,
      height: height
    });
  }
}

Draw returned results on overlay:

function drawResult(context, localization, text) {
  context.beginPath();
  context.moveTo(localization.X1, localization.Y1);
  context.lineTo(localization.X2, localization.Y2);
  context.lineTo(localization.X3, localization.Y3);
  context.lineTo(localization.X4, localization.Y4);
  context.lineTo(localization.X1, localization.Y1);
  context.stroke();

  context.font = "18px Verdana";
  context.fillStyle = '#ff0000';
  let x = [localization.X1, localization.X2, localization.X3, localization.X4];
  let y = [localization.Y1, localization.Y2, localization.Y3, localization.Y4];
  x.sort(function (a, b) {
    return a - b
  });
  y.sort(function (a, b) {
    return b - a
  });
  let left = x[0];
  let top = y[0];

  context.fillText(text, left, top + 50);
}

Deploy the project and then visit the app page:

web worker wasm

wasm web worker

Source Code

https://github.com/dynamsoft-dbr/javascript-barcode/tree/master/examples/webworker

The post Using Web Worker to Load WebAssembly Barcode SDK appeared first on Code Pool.

How to Package JNI Shared Library into Jar File

$
0
0

The article is not about how to create Java native methods invoking C/C++ APIs. It aims to help developers to build a jar package containing JNI shared library, made with Dynamsoft Barcode Reader, for Windows, Linux, and macOS from scratch. I will demonstrate how to create JNI shared libraries with CMake, as well as how to package class files and shared libraries into jar files with Eclipse and Maven.

How to Use Maven with Dynamsoft Barcode Reader

Dynamsoft has provided a full Java development package. You can use it with Maven as follows:

<repositories>
    <repository>
      <id>dbr</id>
      <url>https://download.dynamsoft.com/maven/dbr/jar</url>
    </repository>
  </repositories>
<dependencies>
    <dependency>
      <groupId>com.dynamsoft</groupId>
      <artifactId>dbr</artifactId>
      <version>6.2</version>
    </dependency>
  </dependencies>

If you are not interested in how to build such a jar package step by step, you can ignore the following paragraphs.

How to Define Native Methods in Java

Create a new Maven project in Eclipse.

Eclipse maven project

Create a Java class NativeBarcodeReader.java:

public class NativeBarcodeReader {
	
	private long nativePtr = 0;

	static {
		if (System.getProperty("java.vm.vendor").contains("Android")) {
			System.loadLibrary("dbr");
		} else {
			try {
				if (NativeLoader.load()) {
					System.out.println("Successfully loaded Dynamsoft Barcode Reader.");
				}
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
	public NativeBarcodeReader() {
		nativePtr = nativeCreateInstance();
	}
	
	public void destroyInstance() {
		if (nativePtr != 0)
			nativeDestroyInstance(nativePtr);
	}
	
	public void setLicense(String license) {
		nativeInitLicense(nativePtr, license);
	}
	
	public void decodeFile(String fileName) {
		nativeDecodeFile(nativePtr, fileName);
	}

	private native int nativeInitLicense(long nativePtr, String license);
	
	private native long nativeCreateInstance();
	
	private native void nativeDestroyInstance(long nativePtr);
	
	private native void nativeDecodeFile(long nativePtr, String fileName);
}

Note: If use System.load() method, you have to load all dependencies before loading the JNI shared library.

Eclipse will automatically compile the source code to a class file. Use javah to generates a C header NativeBarcodeReader.h from the class in jni folder.

mkdir jni
cd jni
javah -cp ..\target\classes -o NativeBarcodeReader.h com.dynamsoft.barcode.NativeBarcodeReader

Create the corresponding NativeBarcodeReader.cxx file:

#include "NativeBarcodeReader.h"
#include "DynamsoftBarcodeReader.h"

#ifdef __cplusplus
extern "C"
{
#endif

    /*
    * Class:     com_dynamsoft_barcode_NativeBarcodeReader
    * Method:    nativeInitLicense
    * Signature: (JLjava/lang/String;)I
    */
    JNIEXPORT jint JNICALL Java_com_dynamsoft_barcode_NativeBarcodeReader_nativeInitLicense(JNIEnv *env, jobject, jlong hBarcode, jstring license)
    {
        const char *pszLicense = env->GetStringUTFChars(license, NULL);

        if (hBarcode)
        {
            DBR_InitLicense((void *)hBarcode, pszLicense);
        }

        env->ReleaseStringUTFChars(license, pszLicense);
        return 0;
    }

    /*
    * Class:     com_dynamsoft_barcode_NativeBarcodeReader
    * Method:    nativeCreateInstance
    * Signature: ()J
    */
    JNIEXPORT jlong JNICALL Java_com_dynamsoft_barcode_NativeBarcodeReader_nativeCreateInstance(JNIEnv *, jobject)
    {
        return (jlong)DBR_CreateInstance();
    }

    /*
    * Class:     com_dynamsoft_barcode_NativeBarcodeReader
    * Method:    nativeDestroyInstance
    * Signature: (J)V
    */
    JNIEXPORT void JNICALL Java_com_dynamsoft_barcode_NativeBarcodeReader_nativeDestroyInstance(JNIEnv *, jobject, jlong hBarcode)
    {
        if (hBarcode)
        {
            DBR_DestroyInstance((void *)hBarcode);
        }
    }

    /*
    * Class:     com_dynamsoft_barcode_NativeBarcodeReader
    * Method:    nativeDecodeFile
    * Signature: (JLjava/lang/String;)V
    */
    JNIEXPORT void JNICALL Java_com_dynamsoft_barcode_NativeBarcodeReader_nativeDecodeFile(JNIEnv *env, jobject, jlong ptr, jstring fileName)
    {
        if (ptr)
        {
            void *hBarcode = (void *)ptr;
            const char *pszFileName = env->GetStringUTFChars(fileName, NULL);

            DBR_DecodeFile(hBarcode, pszFileName, "");

            STextResultArray *paryResult = NULL;
            DBR_GetAllTextResults(hBarcode, &paryResult);

            int count = paryResult->nResultsCount;
            int i = 0;
            for (; i < count; i++)
            {
                printf("Index: %d, Type: %s, Value: %s\n", i, paryResult->ppResults[i]->pszBarcodeFormatString, paryResult->ppResults[i]->pszBarcodeText); // Add results to list
            }

            // Release memory
            DBR_FreeTextResults(&paryResult);

            env->ReleaseStringUTFChars(fileName, pszFileName);
        }
    }

#ifdef __cplusplus
}
#endif

The code here is pretty simple. You can add more implementations if you like.

SDK

Download Dynamsoft Barcode Reader for Windows, Linux and macOS.

Copy OS-dependent shared libraries to jni/platforms folder.

  • jni/platforms/win
    • DBRx64.lib
    • DynamicPdfx64.dll
    • DynamsoftBarcodeReaderx64.dll
    • vcomp110.dll
  • jni/platforms/linux
    • libDynamicPdf.so
    • libDynamsoftBarcodeReader.so
  • jni/platforms/macos
    • libDynamsoftBarcodeReader.dylib

How to Use CMake to Build JNI Shared Library

Create a CMakeLists.txt file.

Define Java include and lib directories:

if (CMAKE_HOST_WIN32)
    set(WINDOWS 1)
    set(JAVA_INCLUDE "C:/Program Files/Java/jdk1.8.0_181/include")
    set(JAVA_INCLUDE_OS "C:/Program Files/Java/jdk1.8.0_181/include/win32")
elseif(CMAKE_HOST_APPLE)
    set(MACOS 1)
    set(JAVA_INCLUDE "/System/Library/Frameworks/JavaVM.framework/Headers")
    set(JAVA_INCLUDE_OS "")
elseif(CMAKE_HOST_UNIX)
    set(LINUX 1)
    set(JAVA_INCLUDE "/usr/lib/jvm/java-1.8.0-openjdk-amd64/include/")
    set(JAVA_INCLUDE_OS "/usr/lib/jvm/java-1.8.0-openjdk-amd64/include/linux")
endif()

if(WINDOWS)
    link_directories("${PROJECT_SOURCE_DIR}/platforms/win" "C:/Program Files/Java/jdk1.8.0_181/lib") 
    include_directories("${PROJECT_BINARY_DIR}" "${PROJECT_SOURCE_DIR}/include" "${PROJECT_SOURCE_DIR}" "${JAVA_INCLUDE}" "${JAVA_INCLUDE_OS}")
elseif(LINUX)
    link_directories("${PROJECT_SOURCE_DIR}/platforms/linux") 
    include_directories("${PROJECT_BINARY_DIR}" "${PROJECT_SOURCE_DIR}/include" "${PROJECT_SOURCE_DIR}" "${JAVA_INCLUDE}" "${JAVA_INCLUDE_OS}")
elseif(MACOS)
    link_directories("${PROJECT_SOURCE_DIR}/platforms/macos") 
    include_directories("${PROJECT_BINARY_DIR}" "${PROJECT_SOURCE_DIR}/include" "${PROJECT_SOURCE_DIR}" "${JAVA_INCLUDE}")
endif()

Link Dynamsoft Barcode Reader to generate JNI shared libraries for different platforms. Rename the file suffix from dylib to jnilib for macOS:

add_library(dbr SHARED NativeBarcodeReader.cxx)
if(MACOS)
    set_target_properties(dbr PROPERTIES SUFFIX ".jnilib")
endif()
if(WINDOWS)
    if(CMAKE_CL_64)
        target_link_libraries (dbr "DBRx64")
    else()
        target_link_libraries (dbr "DBRx86")
    endif()
else()
    target_link_libraries (dbr "DynamsoftBarcodeReader")
endif()

Install libraries:

set(CMAKE_INSTALL_PREFIX "${PROJECT_SOURCE_DIR}/../src/main/")
set(ECLIPSE_PATH "java/com/dynamsoft/barcode/native")
set(MAVEN_PATH "resources/com/dynamsoft/barcode/native")
if(WINDOWS)
    install (DIRECTORY "${PROJECT_SOURCE_DIR}/platforms/win" DESTINATION "${CMAKE_INSTALL_PREFIX}${ECLIPSE_PATH}")
    install (DIRECTORY "${PROJECT_SOURCE_DIR}/platforms/win" DESTINATION "${CMAKE_INSTALL_PREFIX}${MAVEN_PATH}")
    install (TARGETS dbr DESTINATION "${CMAKE_INSTALL_PREFIX}${ECLIPSE_PATH}/win")
    install (TARGETS dbr DESTINATION "${CMAKE_INSTALL_PREFIX}${MAVEN_PATH}/win")
elseif(LINUX)
    install (DIRECTORY "${PROJECT_SOURCE_DIR}/platforms/linux" DESTINATION "${CMAKE_INSTALL_PREFIX}${ECLIPSE_PATH}")
    install (DIRECTORY "${PROJECT_SOURCE_DIR}/platforms/linux" DESTINATION "${CMAKE_INSTALL_PREFIX}${MAVEN_PATH}")
    install (TARGETS dbr DESTINATION "${CMAKE_INSTALL_PREFIX}${ECLIPSE_PATH}/linux")
    install (TARGETS dbr DESTINATION "${CMAKE_INSTALL_PREFIX}${MAVEN_PATH}/linux")
elseif(MACOS)
    install (DIRECTORY "${PROJECT_SOURCE_DIR}/platforms/macos" DESTINATION "${CMAKE_INSTALL_PREFIX}${ECLIPSE_PATH}")
    install (DIRECTORY "${PROJECT_SOURCE_DIR}/platforms/macos" DESTINATION "${CMAKE_INSTALL_PREFIX}${MAVEN_PATH}")
    install (TARGETS dbr DESTINATION "${CMAKE_INSTALL_PREFIX}${ECLIPSE_PATH}/macos")
    install (TARGETS dbr DESTINATION "${CMAKE_INSTALL_PREFIX}${MAVEN_PATH}/macos")
endif()

The ECLIPSE_PATH  is used to export jar files by Eclipse, whereas the  MAVEN_PATH is used to export jar files by Maven.

Build the JNI shared library.

Windows

E.g., Visual Studio 2017

mkdir build
cd build
cmake -G"Visual Studio 15 2017 Win64" .. 
cmake --build . --config Release --target install

Linux & macOS

mkdir build
cd build
cmake .. 
cmake --build . --config Release --target install

How to Package Native Libraries into Jar File

Edit the pom.xml file to add the directory of shared libraries:

<project xmlns="http://maven.apache.org/POM/4.0.0" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.dynamsoft</groupId>
    <artifactId>barcode</artifactId>
    <version>1.0.0</version>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <build>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <excludes>
                    <exclude>**/*.md</exclude>
                    <exclude>**/*.h</exclude>
                    <exclude>**/*.lib</exclude>
                </excludes>
            </resource>
        </resources>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.5.1</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Generate the jar file in the target folder:

mvn package

Maven JNI shared library

Alternatively, you can use Eclipse to export the jar file.

Eclipse export JNI shared library

Here is the generated jar file.

java jni jar

How to Load JNI Shared Libraries from a Jar File

List all dependent library files:

String[] filenames = null;
		if (Utils.isWindows()) {
			filenames = new String[] {"vcomp110.dll", "DynamicPdfx64.dll", "DynamsoftBarcodeReaderx64.dll", "dbr.dll"};
		}
		else if (Utils.isLinux()) {
			filenames = new String[] {"libDynamicPdf.so", "libDynamsoftBarcodeReader.so", "libdbr.so"};
		}
		else if (Utils.isMac()) {
			filenames = new String[] {"libDynamsoftBarcodeReader.dylib", "libdbr.jnilib"};
		}
		
		boolean ret = true;
		
		for (String file : filenames) {
			ret &= extractAndLoadLibraryFile(dbrNativeLibraryPath, file, tempFolder);
		}

Extract the shared libraries to the temporary folder:

private static boolean extractAndLoadLibraryFile(String libFolderForCurrentOS, String libraryFileName,
			String targetFolder) {
		String nativeLibraryFilePath = libFolderForCurrentOS + "/" + libraryFileName;

		String extractedLibFileName = libraryFileName;
		File extractedLibFile = new File(targetFolder, extractedLibFileName);

		try {
			if (extractedLibFile.exists()) {
				// test md5sum value
				String md5sum1 = md5sum(NativeBarcodeReader.class.getResourceAsStream(nativeLibraryFilePath));
				String md5sum2 = md5sum(new FileInputStream(extractedLibFile));

				if (md5sum1.equals(md5sum2)) {
					return loadNativeLibrary(targetFolder, extractedLibFileName);
				} else {
					// remove old native library file
					boolean deletionSucceeded = extractedLibFile.delete();
					if (!deletionSucceeded) {
						throw new IOException(
								"failed to remove existing native library file: " + extractedLibFile.getAbsolutePath());
					}
				}
			}

			// Extract file into the current directory
			InputStream reader = NativeBarcodeReader.class.getResourceAsStream(nativeLibraryFilePath);
			FileOutputStream writer = new FileOutputStream(extractedLibFile);
			byte[] buffer = new byte[1024];
			int bytesRead = 0;
			while ((bytesRead = reader.read(buffer)) != -1) {
				writer.write(buffer, 0, bytesRead);
			}

			writer.close();
			reader.close();

			if (!System.getProperty("os.name").contains("Windows")) {
				try {
					Runtime.getRuntime().exec(new String[] { "chmod", "755", extractedLibFile.getAbsolutePath() })
							.waitFor();
				} catch (Throwable e) {
				}
			}

			return loadNativeLibrary(targetFolder, extractedLibFileName);
		} catch (IOException e) {
			System.err.println(e.getMessage());
			return false;
		}

	}

Load libraries with absolute path:

private static synchronized boolean loadNativeLibrary(String path, String name) {
		File libPath = new File(path, name);
		if (libPath.exists()) {
			try {
				System.load(new File(path, name).getAbsolutePath());
				return true;
			} catch (UnsatisfiedLinkError e) {
				System.err.println(e);
				return false;
			}

		} else
			return false;
	}

Run the test:

java -cp ./target/barcode-1.0.0.jar com.dynamsoft.barcode.Test

References

Source Code

https://github.com/dynamsoft-dbr/java-jni-barcode

The post How to Package JNI Shared Library into Jar File appeared first on Code Pool.

Rust Programming with Dynamsoft Barcode Reader

$
0
0

A few days ago, I accepted a new challenge of creating a simple command line barcode reader using Rust and Dynamsoft Barcode Reader SDK. Rust is a system programming language similar to C++. The learning process did not go through smoothly as I expected. It is not as easy as learning other high-level programming languages such as Java and Python. In this article, I share my experience of learning and using Rust.

Prerequisites

Building Rust Barcode Reader on Windows

Project initialization

Create a new project:

cargo new barcodereader

In main.rs, get the input file name from arguments:

use std::env;

fn main() {
    let args: Vec<String> = env::args().collect();
    if args.len() == 1 {
        println!("Please input an image file.");
        return
}
let file_name = env::args().nth(1).expect("Missing argument");
    println!("{}", file_name);

}

Build and run the app:

cargo run .\images\AllSupportedBarcodeTypes.tif

Bridging Rust and native methods

To simplify the invoking process, create bridge.h and bridge.c.

// bridge.h
typedef struct Barcode {
    char* barcode_type;
    char* barcode_value;
} Barcode;

typedef __int32 int32_t;
typedef void (*RustCallback)(int32_t, const char *, const char *);

int32_t register_callback(RustCallback callback);
void c_decodeFile(const char *fileName, const char *pszLicense);
// bridge.c
#include "bridge.h"
#include "DynamsoftBarcodeReader.h"
#include <stdio.h>

RustCallback cb;

int32_t register_callback(RustCallback callback) {
    cb = callback;
    return 1;
}

void c_decodeFile(const char *fileName, const char *pszLicense)
{
    void *hBarcode = DBR_CreateInstance();

    if (hBarcode)
    {
        int ret = DBR_InitLicense(hBarcode, pszLicense);
        STextResultArray *paryResult = NULL;
        ret = DBR_DecodeFile(hBarcode, fileName, "");
        DBR_GetAllTextResults(hBarcode, &paryResult);
        int count = paryResult->nResultsCount;
        printf("Barcode found: %d\n", count);
        int i = 0;
        for (; i < count; i++)
        {
            if (cb) 
            {
                cb(i, paryResult->ppResults[i]->pszBarcodeFormatString, paryResult->ppResults[i]->pszBarcodeText);
            }
        }
        DBR_FreeTextResults(&paryResult);
        DBR_DestroyInstance(hBarcode);
    }
}

Here I use a callback function to pass the barcode decoding results from C to Rust. Add the callback function to main.rs:

use std::ffi::CStr;

extern "C" fn callback(index: i32, barcode_type: *const c_char, barcode_value: *const c_char) {
    unsafe {
        println!(
            "Index {}, {}, {}",
            index,
            CStr::from_ptr(barcode_type).to_str().unwrap(),
            CStr::from_ptr(barcode_value).to_str().unwrap()
        );
    }
}

To link the native library and build the bridge, create build.rs in the project root:

extern crate cc;

fn main() {
    // Link Dynamsoft Barcode Reader.
    println!("cargo:rustc-link-search=./platforms/win");
    println!("cargo:rustc-link-lib=DBRx64");

    // Build C code.
    cc::Build::new()
        .include("include")
        .file("src/bridge.c")
        .compile("bridge");
}

Add the configuration to Cargo.toml:

[package]
# ...
build = "build.rs"
[build-dependencies]
cc = "1.0"

Why not call native methods directly? It is complicated. If you do this, you have to define all C structures in Rust. The next step is to generate Rust FFI bindings based on the bridge.h file.

Converting C header files to Rust FFI bindings

Use bindgen to convert bridge.h to bridge.rs:

bindgen.exe --no-doc-comments --no-layout-tests bridge.h -o bridge.rs

When I ran the above command line the first time, I got the following error message:

error: toolchain 'stable-x86_64-pc-windows-msvc' does not have the binary `rustfmt.exe`

To fix the issue, install rustfmt-preview:

rustup component add rustfmt-preview

We can automate the process by adding bindgen as a build dependency in Cargo.toml:

[build-dependencies]
bindgen = "0.42.1"

Then add the following code to build.rs:

extern crate bindgen;
fn main() {
	// Generates Rust FFI bindings.
    let bindings = bindgen::Builder::default()
        // The input header we would like to generate
        // bindings for.
        .header("src/bridge.h")
        // Finish the builder and generate the bindings.
        .generate()
        // Unwrap the Result and panic on failure.
        .expect("Unable to generate bindings");

    bindings
        .write_to_file("src/bridge.rs")
        .expect("Couldn't write bindings!");

}

Automatically copy *.dll files to the output directory after building the project

On Windows, we use .lib files for building projects and use .dll files for running apps. To make the program run, we have to copy DLL files to the output directory.

The first step is to get the path of the output folder:

let out_dir = env::var("OUT_DIR").unwrap();
    let debug_offset = out_dir.find("debug").unwrap_or(0);
    let release_offset = out_dir.find("release").unwrap_or(0);
    let mut path = String::from("");

    if debug_offset > 0 {
        println!(">>> where is debug {}", debug_offset);
        path.push_str(&format!("{}", &out_dir[..debug_offset]));
        path.push_str("debug");
        println!("{}", path);
    }

    if release_offset > 0 {
        println!(">>> where is release {}", release_offset);
        path.push_str(&format!("{}", &out_dir[..release_offset]));
        path.push_str("release");
        println!("{}", path);
    }

Copy DLL files:

let _src: String = String::from("./platforms/win/DynamsoftBarcodeReaderx64.dll");
path.push_str("/DynamsoftBarcodeReaderx64.dll");
let _result = fs::copy(_src, &path);

Build and run Rust barcode reader

Call the barcode detection function in main.rs:

use std::ffi::CStr;
use std::ffi::CString;
use std::os::raw::c_char;
use std::env;

mod bridge;
use bridge::*;

extern "C" fn callback(index: i32, barcode_type: *const c_char, barcode_value: *const c_char) {
    unsafe {
        println!(
            "Index {}, {}, {}",
            index,
            CStr::from_ptr(barcode_type).to_str().unwrap(),
            CStr::from_ptr(barcode_value).to_str().unwrap()
        );
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    if args.len() == 1 {
        println!("Please input an image file.");
        return
    }

    println!("Hello Dynamsoft Barcode Reader!");
    unsafe {
        register_callback(Some(callback));
        let image_file = CString::new(env::args().nth(1).expect("Missing argument")).unwrap();
        let license = CString::new("t0068NQAAAFKYHV9xSZDEThUtClXNzxXH9TLSj/vYcY8mSKa0RxaGw3qNynyAMJ9Ib8UPxzFsbAMIugqPO313BvfiOdmZFTY=").unwrap();
        c_decodeFile(image_file.as_ptr(), license.as_ptr());
    }

    println!("Bye!");
}

Build the app:

cargo build -vv

Clean the build:

cargo clean

Run the app:

cargo run <image file>

Rust barcode reader

References

Source Code

https://github.com/yushulx/rust-barcode

 

The post Rust Programming with Dynamsoft Barcode Reader appeared first on Code Pool.

Viewing all 145 articles
Browse latest View live