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 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