How to Create Java Barcode Reader on Linux with JNI

A few days ago, Dynamsoft Labs released Barcode Reader SDK for Linux. The SDK package provides two shared libraries for C/C++ programming. If you want to write code with high-level programming languages such as Java, you need to create a wrapper. In this post, I will illustrate how to build a simple Java barcode reader on Ubuntu with JNI (Java Native Interface) from scratch.

Installing Dynamsoft Barcode Reader for Linux

To download Dynamsoft Barcode Reader SDK, you can visit the overview page and click v4.0.0-pre-alpha.tar.gz.

Extract the package with the command:

tar -xzf dbr-4.0.0-pre-alpha.tar.gz

Installing Eclipse and CDT for Ubuntu

To conveniently write Java and C/C++ code on Linux, I prefer using Eclipse and CDT. You can navigate Window > Preferences > Install/Update > Available Software Sites to add CDT URL.

eclipse CDT

Navigate Help > Install New Software > Work with to install CDT.

CDT installation

How to Implement Java Barcode Reader on Ubuntu with JNI

Create a Class DBRJNI with some native methods:

public class DBRJNI {

                static {

                                System.loadLibrary("dbr");

                }

                public native int initializeLicense(String license);

                public native ArrayList<BarcodeResult> readBarcode(String fileName);

}

Create a folder jni for writing C/C++ code in your project root directory. Generate a header file corresponding to the Class DBRJNI with the following command:

javah -o DBRJNI.h -classpath ../bin com.dynamsoft.DBRJNI

You will see the following unresolved issues:

jni error

To solve the problem, open project properties and add the Java include path (/usr/lib/jvm/java-7-openjdk-amd64/include) to Preprocessor Include Paths.

jni include path

Create DBRJNI.cpp to add function implementations:

JNIEXPORT jint JNICALL Java_com_dynamsoft_DBRJNI_initializeLicense(JNIEnv *env,

                                jobject obj, jstring license)

{

                const char *pszLicense = env->GetStringUTFChars(license, 0);

                int ret = DBR_InitLicense(pszLicense);

                // release license native string

                env->ReleaseStringUTFChars(license, pszLicense);

                return ret;

}

JNIEXPORT jobject JNICALL Java_com_dynamsoft_DBRJNI_readBarcode(JNIEnv *env,

                                jobject obj, jstring fileName)

{

                const char *pszFileName = env->GetStringUTFChars(fileName, 0);

                __int64 llFormat = OneD | QR_CODE | PDF417 | DATAMATRIX;

                int iMaxCount = 0x7FFFFFFF;

                ReaderOptions ro = { 0 };

                ro.llBarcodeFormat = llFormat;

                ro.iMaxBarcodesNumPerPage = iMaxCount;

                pBarcodeResultArray paryResult = NULL;

                int iRet = DBR_DecodeFile(pszFileName, &ro, &paryResult);

                if (iRet != DBR_OK) {

                                printf("Failed to read barcode: %s\n", DBR_GetErrorString(iRet));

                                return NULL;

                }

                if (paryResult->iBarcodeCount == 0)

                                {

                                                printf("No barcode found");

                                                DBR_FreeBarcodeResults(&paryResult);

                                                return 0;

                                }

                for (int iIndex = 0; iIndex < paryResult->iBarcodeCount; iIndex++)

                                {

                                                printf("Barcode %d:\n", iIndex + 1);

                                                printf("    Page: %d\n", paryResult->ppBarcodes[iIndex]->iPageNum);

                                                printf("    Type: %s\n", GetFormatStr(paryResult->ppBarcodes[iIndex]->llFormat));

                                                printf("    Value: %s\n", paryResult->ppBarcodes[iIndex]->pBarcodeData);

                                                printf("    Region: {Left: %d, Top: %d, Width: %d, Height: %d}\n\n",

                                                                paryResult->ppBarcodes[iIndex]->iLeft, paryResult->ppBarcodes[iIndex]->iTop,

                                                                paryResult->ppBarcodes[iIndex]->iWidth, paryResult->ppBarcodes[iIndex]->iHeight);

                                }

                                DBR_FreeBarcodeResults(&paryResult);

// release filename native string

                env->ReleaseStringUTFChars(fileName, pszFileName);

                return NULL;

}

Create a makefile:

CC=gcc 
CCFLAGS=-c -Wall -Werror -fpic -lstdc++
JNI_INCLUDE=/usr/lib/jvm/java-7-openjdk-amd64/include
CLASS_PATH=../bin
#DBRLIB_PATH=~/Dynamsoft/BarcodeReader4.0/Redist
#LDFLAGS=-L$(DBRLIB_PATH) -Wl,-rpath=$(DBRLIB_PATH)

ifeq ($(shell getconf LONG_BIT), 32)
	DBRLIB=-lDynamsoftBarcodeReaderx86
	LIBNAME=libDynamsoftBarcodeReaderx86.so
else
	DBRLIB=-lDynamsoftBarcodeReaderx64
	LIBNAME=libDynamsoftBarcodeReaderx64.so
endif

TARGET=libdbr.so
OBJECT=DBRJNI.o
SOURCE=DBRJNI.cpp

$(TARGET): $(OBJECT)
	$(CC) -shared -o $(TARGET) $(OBJECT) $(LDFLAGS) $(DBRLIB)
	$(shell sudo ln -s ~/Dynamsoft/BarcodeReader4.0/Redist/$(LIBNAME) /usr/lib/$(LIBNAME))

$(OBJECT): $(SOURCE)
	$(CC) $(CCFLAGS) -I$(JNI_INCLUDE) $(SOURCE) 
#DBRJNI.h : 
#	javah -o DBRJNI.h -classpath $(CLASS_PATH) com.dynamsoft.DBRJNI

# the clean target
.PHONY : clean
clean: 
	sudo rm -f $(OBJECT) $(TARGET) /usr/lib/$(LIBNAME)

If you don’t use the command $(shell sudo ln -s) to creates a symbolic link, you will see the following error:

/usr/bin/ld: cannot find -lDynamsoftBarcodeReaderx64

Build libdbr.so with make:

makefile

In order to correctly load the shared library that generated under the jni folder, specify the VM arguments in Run Configurations:

-Djava.library.path=jni

java lib path for eclipse

Test the Java barcode program with a few lines of code:

                static {

                                System.loadLibrary("dbr");

                }

                public native int initializeLicense(String license);

                public native ArrayList<BarcodeResult> readBarcode(String fileName);

                public static void main(String[] args) {

                                // invoke the native method

                                DBRJNI barcodeReader = new DBRJNI();

                                int ret = barcodeReader.initializeLicense("<DBR License>");

                                System.out.println("Initialize license: " + ret);

                                barcodeReader.readBarcode("<Image File>");

                }

jni barcode result

Source Code

https://github.com/dynamsoftsamples/java-barcode-reader-for-linux