Building Python Barcode Extension with DBR 5.2 for Linux

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 for Linux provides C/C++ APIs, which means you need to create a Python wrapper yourself.

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