Advanced GUI Python Barcode and QR Code Reader for Windows, Linux, macOS and Rasberry Pi OS
Qt Designer is a powerful tool for creating cross-platform graphical user interfaces (GUIs) using Qt widgets. In this guide, we’ll use Qt Designer to develop an advanced GUI for a Python-based barcode and QR code reader, leveraging the Dynamsoft Python Barcode SDK. This application will be compatible with Windows, Linux, macOS, and Raspberry Pi OS, and includes all the robust features of the Dynamsoft Barcode Reader.
This article is Part 3 in a 11-Part Series.
- Part 1 - Detecting and Decoding QR Codes in Python with YOLO and Dynamsoft Barcode Reader
- Part 2 - How to a GUI Barcode Reader with Qt PySide6 on Raspberry Pi
- Part 3 - Advanced GUI Python Barcode and QR Code Reader for Windows, Linux, macOS and Rasberry Pi OS
- Part 4 - Advanced QR Code Recognition: Handling Inverted Colors, Perspective Distortion, and Grayscale Images
- Part 5 - Scanning QR Code from Desktop Screen with Qt and Python Barcode SDK
- Part 6 - Building an Online Barcode and QR Code Scanning App with Python Django
- Part 7 - Real-Time Barcode and QR Code Scanning with Webcam, OpenCV, and Python
- Part 8 - How to Build Flet Chat App with Barcode and Gemini APIs
- Part 9 - Comparing Barcode Scanning in Python: ZXing vs. ZBar vs. Dynamsoft Barcode Reader
- Part 10 - Python Ctypes: Invoking C/C++ Shared Library and Native Threading
- Part 11 - A Guide to Running ARM32 and ARM64 Python Barcode Readers in Docker Containers
Prerequisites
-
OpenCV
python3 -m pip install opencv-python
-
PySide6
python3 -m pip install PySide6
-
Dynamsoft Barcode Reader
python3 -m pip install dbr
Creating the UI with Qt Designer
To build the GUI, you’ll need the following Qt widgets:
- Menu Bar
- Open file
- Open folder
- Save template
- Enter license key
- About
- Status Bar
- Show status information
- List Widget
- List loaded file names
- Label
- Display image or webcam frame
- Group Box
- Groups for camera, template and barcode type settings
- Push Button
- Start camera
- Stop camera
- Load barcode template file
- Export barcode template file
- Combo Box
- Camera resolution
- Check Box
- Auto-stop camera view when barcode recognition is done
- Synchronously or asynchronously display barcode results
- Text Edit
- Enter parameter template
- Show barcode decoding results
After designing your UI in Qt Designer, save the layout as a .ui file (e.g., design.ui). To use this layout in your Python application, convert the .ui file to a Python file using the following command:
PySide6-uic design.ui -o design.py
Steps to Build a Cross-platform Python Barcode and QR Code Reader with GUI
Let’s walk through building a Python barcode reader application step by step.
Loading the UI File
With the UI code ready, you can load it into your application as follows:
'''
Usage:
app.py <license.txt>
'''
import sys
from PySide6.QtGui import QPixmap, QImage
from PySide6.QtWidgets import QApplication, QMainWindow, QInputDialog
from PySide6.QtCore import QFile, QTimer
from PySide6.QtWidgets import *
from design import Ui_MainWindow
from barcode_manager import *
import os
import cv2
from dbr import EnumBarcodeFormat, EnumBarcodeFormat_2
class MainWindow(QMainWindow):
def __init__(self, license):
super(MainWindow, self).__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
def main():
try:
with open(sys.argv[1]) as f:
license = f.read()
except:
license = ""
app = QApplication(sys.argv)
window = MainWindow(license)
window.show()
sys.exit(app.exec_())
if __name__ == '__main__':
print(__doc__)
main()
Setting the License Key
To use the SDK, set the license key via the BarcodeReader
class:
from dbr import *
def set_license(self, key):
return BarcodeReader.init_license(key)
Signals and Slots
Next, initialize global variables and bind widget signals to slots for various functionalities:
# Initialization
self._all_data = {}
self._results = None
# Dynamsoft Barcode Reader
self._barcodeManager = BarcodeManager()
if license is not None and license != '':
error = self._barcodeManager.set_license(license)
if error[0] != EnumErrorCode.DBR_OK:
self.showMessageBox(error[1])
# Create a timer.
self.timer = None
# Open camera
self._cap = None
# self.openCamera()
# Resolution list
self.ui.comboBox.currentTextChanged.connect(self.onComboBoxChanged)
# The current path.
self._path = os.path.dirname(os.path.realpath(__file__))
# Camera button
self.ui.pushButton_open.clicked.connect(self.openCamera)
self.ui.pushButton_stop.clicked.connect(self.stopCamera)
# Load file
self.ui.actionOpen_File.triggered.connect(self.openFile)
# Load directory
self.ui.actionOpen_Folder.triggered.connect(self.openFolder)
# Export template
self.ui.actionExport_template.triggered.connect(self.exportTemplate)
# About
self.ui.actionAbout.triggered.connect(self.about)
# Set license
self.ui.actionEnter_License_Key.triggered.connect(self.setLicense)
## List widget
self.ui.listWidget.currentItemChanged.connect(self.currentItemChanged)
## Template load button
self.ui.pushButton_template.clicked.connect(self.loadTemplate)
## Template export button
self.ui.pushButton_export_template.clicked.connect(self.exportTemplate)
File Dialog for Opening and Saving Files
Handle essential file operations such as loading individual images, batch loading from folders, and saving template files:
-
Load a file:
def openFile(self): filename = QFileDialog.getOpenFileName(self, 'Open File', self._path, "Barcode images (*)") if filename is None or filename[0] == '': return filename = filename[0]
-
Load files from a folder:
def openFolder(self): dir = QFileDialog.getExistingDirectory(self, 'Open Folder', self._path, QFileDialog.ShowDirsOnly) if dir is '': return files = [os.path.join(dir, f) for f in os.listdir(dir) if os.path.isfile(os.path.join(dir, f))] if len(files) == 0: return for filename in files: self.appendFile(filename)
-
Save a template:
def exportTemplate(self): filename = QFileDialog.getSaveFileName(self, 'Save File', self._path, "Barcode Template (*.json)") if filename is None or filename[0] == '': return filename = filename[0]
Decoding Barcodes from JPEG, PNG, TIFF, PDF and GIF Files
OpenCV supports JPEG, PNG, and TIFF formats. To decode barcodes and QR codes from these formats, use:
frame = cv2.imread(filename)
results = self._reader.decode_buffer(frame)
For additional formats like PDF and GIF, use Dynamsoft’s SDK:
results = self._reader.decode_file(filename)
To display images in the label widget, convert the intermediate image data to a NumPy array:
intermediate_results = self._reader.get_all_intermediate_results()
imageData = intermediate_results[0].results[0]
buffer = imageData.bytes
width = imageData.width
height = imageData.height
stride = imageData.stride
format = imageData.image_pixel_format
channel = 3
if format == EnumImagePixelFormat.IPF_RGB_888:
channel = 3
elif format == EnumImagePixelFormat.IPF_BINARY or format == EnumImagePixelFormat.IPF_GRAYSCALED or format == EnumImagePixelFormat.IPF_BINARYINVERTED:
channel = 1
if format == EnumImagePixelFormat.IPF_BINARY or format == EnumImagePixelFormat.IPF_BINARYINVERTED:
whiteValue = 1
if format == EnumImagePixelFormat.IPF_BINARYINVERTED:
whiteValue = 0
binData = bytearray(len(buffer) << 3)
count = 0
for pos in range(len(buffer)):
for bit in range(7, -1, -1):
if (buffer[pos] >> bit) & 0x01 == whiteValue:
binData[count] = 255
else:
binData[count] = 0
count += 1
frame = np.ndarray((height, width, channel), np.uint8, binData, 0, (stride << 3, channel, 1))
else:
frame = np.ndarray((height, width, channel), np.uint8, buffer, 0, (stride, channel, 1))
Showing Webcam Stream
Trigger a timer to continuously update and display the webcam stream:
def openCamera(self):
width = 640; height = 480
self._cap = cv2.VideoCapture(0)
self._cap.set(cv2.CAP_PROP_FRAME_WIDTH, width)
self._cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
if not self._cap.isOpened():
self.showMessageBox('Error', "Failed to open camera.")
return
self.timer = QTimer()
self.timer.timeout.connect(self.nextFrameUpdate)
self.timer.start(1000./24)
def nextFrameUpdate(self):
ret, frame = self._cap.read()
frame, self._results = self._barcodeManager.decode_frame(frame)
self.showResults(frame, self._results)
Creating a Python Process for Real-Time Barcode Scanning
Since barcode decoding is CPU-intensive and Python’s GIL limits threading performance, use a separate process to avoid blocking the UI:
def create_barcode_process(self):
size = 1
self.frameQueue = Queue(size)
self.resultQueue = Queue(size)
self.barcodeScanning = Process(target=process_barcode_frame, args=(self.frameQueue, self.resultQueue, self._template, self._types, self._types2))
self.barcodeScanning.start()
Running the GUI Python Barcode and QR Code Reader
To run the application, execute the following command:
python3 app_advanced.py license.txt
Here are screenshots of the GUI barcode reader on different platforms:
-
Windows
-
Raspberry Pi OS
Source Code
https://github.com/yushulx/python-barcode-qrcode-sdk/tree/main/examples/official/9.x/qt_gui