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