When creating a barcode reader app with a free barcode SDK, you may come up with ZXing instantly. ZXing is an open-source barcode reading and decoding library implemented in Java. There are some third-party projects, either ports or bindings, available for other programming languages. So if you want to create a Python barcode reader, you can use Python ZXing, which is a Python wrapper for invoking ZXing Java class. If you care about the performance, we can use Python ZBar, a Python wrapper for the ZBar C++ code, as a comparison.
Making Python ZXing Work
Get the source code of ZXing:
git clone https://github.com/zxing/zxing.git
Build the project using Maven:
cd zxing mvn install
Generate a .jar file with dependencies:
cd javase mvn package assembly:single -DskipTests

On Windows 10, you may fail to decode a barcode image using the command as follows:
java -cp D:\zxing\javase\target\javase-3.4.1-SNAPSHOT-jar-with-dependencies.jar com.google.zxing.client.j2se.CommandLineRunner D:\dataset\20499525_2.jpg

If you change the backward slash contained in the file path to forward slash, you will get different error information:
java -cp D:\zxing\javase\target\javase-3.4.1-SNAPSHOT-jar-with-dependencies.jar com.google.zxing.client.j2se.CommandLineRunner D:/dataset/20499525_2.jpg

How to fix the unknown protocol error? The workaround is to use the URI scheme file:///D:/dataset/20499525_2.jpg:
java -cp D:\zxing\javase\target\javase-3.4.1-SNAPSHOT-jar-with-dependencies.jar com.google.zxing.client.j2se.CommandLineRunner file:///D:/dataset/20499525_2.jpg

Search for the keyword “Python” on the homepage of ZXing repository.

Visit the python-zxing project to get the source code:
git clone https://github.com/oostendo/python-zxing.git
Edit the line in zxing\__init__.py file. Replace the libs with the .jar file built from the ZXing source code:
libs = ["javase/target/javase-3.4.1-SNAPSHOT-jar-with-dependencies.jar"]

Build and install the Python module:
python setup.py build install
Create an app.py file:
import argparse import zxing def main(): ap = argparse.ArgumentParser() ap.add_argument("-i", "--image", type=str, help="path to input image") args = vars(ap.parse_args()) image = args["image"] if image == None: print('Try command: python app.py -i <image_file> ') return # ZXing reader = zxing.BarCodeReader('D:/zxing') # Set the ZXing project directory barcode = reader.decode('file:///' + image.replace('\\', '/')) print('ZXing: {}'.format(barcode.data.rstrip())) # Command: python app.py -i <image_file> if __name__ == "__main__": main()
The barcode result returned from ZXing contains a trailing newline, so we can use rstrip() to remove it.
Run the program:
> python app.py -i D:\dataset\20499525_2.jpg ZXing: 20499525

ZBar: The Alternative to ZXing
Not like ZXing, installing ZBar is much easier:
pip install pyzbar
Add the code snippet of using ZBar to app.py file:
import pyzbar.pyzbar as zbar from PIL import Image barcode = zbar.decode(Image.open(image)) print('ZBar: {}'.format(barcode[0].data.decode("utf-8")))
Rerun the Python program and we can see both of them decode barcode correctly:
> python3 app.py -i D:\dataset\20499525_2.jpg ZXing: 20499525 ZBar: 20499525
We can take a further look at the time cost of decoding barcode:
# ZXing reader = zxing.BarCodeReader('D:/zxing') # Set the ZXing project directory start = time.time() barcode = reader.decode('file:///' + image.replace('\\', '/')) elapsed_time = time.time() - start print('ZXing: {}. Elapsed time: {}ms'.format(barcode.data.rstrip(), int(elapsed_time * 1000))) # ZBar start = time.time() barcode = zbar.decode(Image.open(image)) elapsed_time = time.time() - start print('ZBar: {}. Elapsed time: {}ms'.format(barcode[0].data.decode("utf-8"), int(elapsed_time * 1000)))
Although they both return the correct results, Python ZBar is much faster than ZXing:
> python3 app.py -i D:\dataset\20499525_2.jpg ZXing: 20499525. Elapsed time: 2170ms ZBar: 20499525. Elapsed time: 207ms

The reason is Python ZXing uses subprocess module to get barcode results from Java process:
def decode(self, files, try_harder = False, qr_only = False): cmd = [self.command] cmd += self.args[:] #copy arg values if try_harder: cmd.append("--try_harder") if qr_only: cmd.append("--possibleFormats=QR_CODE") libraries = [self.location + "/" + l for l in self.libs] cmd = [ c if c != "LIBS" else os.pathsep.join(libraries) for c in cmd ] # send one file, or multiple files in a list SINGLE_FILE = False if type(files) != type(list()): cmd.append(files) SINGLE_FILE = True else: cmd += files (stdout, stderr) = subprocess.Popen(cmd, stdout=subprocess.PIPE, universal_newlines=True).communicate()
In my next article, I will use Python code to compare the recognition rate among ZXing, ZBar, and Dynamsoft Barcode Reader based on the public dataset https://drive.google.com/uc?id=1uThXXH8HiHAw6KlpdgcimBSbrvi0Mksf&export=download.
Source Code
https://github.com/yushulx/python-zxing-zbar-dbr
The post How to Use Python ZXing and Python ZBar on Windows 10 appeared first on Code Pool.