Skip to content

Commit 0dadc34

Browse files
committed
Add a Qt GUI example
1 parent 80d1993 commit 0dadc34

File tree

9 files changed

+1888
-0
lines changed

9 files changed

+1888
-0
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Python Barcode Reader with Desktop GUI
2+
This is a cross-platform GUI barcode reader application built with `Python 3`, `PySide6`, and the [Dynamsoft Python Barcode SDK](https://www.dynamsoft.com/barcode-reader/docs/server/programming/python/). It supports `Windows`, `Linux`, `macOS` and `Raspberry Pi OS`.
3+
4+
5+
## Prerequisites
6+
- **OpenCV**
7+
8+
```bash
9+
python3 -m pip install opencv-python
10+
```
11+
12+
- **PySide6**
13+
14+
```bash
15+
python3 -m pip install PySide6
16+
```
17+
18+
- **Dynamsoft Barcode Reader**
19+
20+
```
21+
python3 -m pip install dbr
22+
```
23+
24+
- [Dynamsoft Barcode SDK License](https://www.dynamsoft.com/customer/license/trialLicense?product=dbr)
25+
26+
27+
## Usage
28+
29+
- **Simple Demo**
30+
31+
```
32+
python3 app.py license.txt
33+
```
34+
35+
![Python Barcode Reader](./screenshots/simple-demo.png)
36+
37+
- **Advanced Demo**
38+
39+
The advanced demo supports reading barcodes from image files, webcam, and desktop screenshots:
40+
41+
```
42+
pyside2-uic design.ui -o design.py
43+
python3 app_advanced.py license.txt
44+
```
45+
46+
![Python Barcode Reader](./screenshots/advanced-demo.png)
47+
48+
49+
## Blog
50+
- [How to Create a Python Barcode Reader to Scan QR Code from Desktop Screen](https://www.dynamsoft.com/codepool/scan-qr-code-from-desktop-screen.html)
51+
- [Advanced GUI Python Barcode Reader for Windows, Linux, macOS and Rasberry Pi OS](https://www.dynamsoft.com/codepool/gui-barcode-reader-windows-linux-macos.html)

examples/official/9.x/qt_gui/app.py

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
#!/usr/bin/env python3
2+
3+
'''
4+
Usage:
5+
app.py <license.txt>
6+
'''
7+
8+
import sys
9+
from PySide6.QtGui import QPixmap, QImage
10+
11+
from PySide6.QtWidgets import QApplication, QLabel, QPushButton, QVBoxLayout, QWidget, QFileDialog, QTextEdit, QMessageBox, QHBoxLayout
12+
from PySide6.QtCore import QTimer
13+
14+
from barcode_manager import *
15+
import os
16+
import cv2
17+
18+
19+
class UI_Window(QWidget):
20+
21+
def __init__(self):
22+
QWidget.__init__(self)
23+
24+
self.FRAME_WIDTH = 640
25+
self.FRAME_HEIGHT = 480
26+
self.WINDOW_WIDTH = 1280
27+
self.WINDOW_HEIGHT = 1000
28+
self._results = None
29+
# Initialize Dynamsoft Barcode Reader
30+
self._barcodeManager = BarcodeManager()
31+
32+
# Initialize OpenCV camera
33+
self._cap = cv2.VideoCapture(0)
34+
# cap.set(5, 30) #set FPS
35+
self._cap.set(cv2.CAP_PROP_FRAME_WIDTH, self.FRAME_WIDTH)
36+
self._cap.set(cv2.CAP_PROP_FRAME_HEIGHT, self.FRAME_HEIGHT)
37+
38+
# The current path.
39+
self._path = os.path.dirname(os.path.realpath(__file__))
40+
41+
# Create a timer.
42+
self.timer = QTimer()
43+
self.timer.timeout.connect(self.nextFrameUpdate)
44+
45+
# Create a layout.
46+
layout = QVBoxLayout()
47+
48+
# Add a button
49+
self.btn = QPushButton("Load an image")
50+
self.btn.clicked.connect(self.pickFile)
51+
layout.addWidget(self.btn)
52+
53+
# Add a button
54+
button_layout = QHBoxLayout()
55+
56+
btnCamera = QPushButton("Open camera")
57+
btnCamera.clicked.connect(self.openCamera)
58+
button_layout.addWidget(btnCamera)
59+
60+
btnCamera = QPushButton("Stop camera")
61+
btnCamera.clicked.connect(self.stopCamera)
62+
button_layout.addWidget(btnCamera)
63+
64+
layout.addLayout(button_layout)
65+
66+
# Add a label
67+
self.label = QLabel()
68+
self.label.setFixedSize(self.WINDOW_WIDTH - 30,
69+
self.WINDOW_HEIGHT - 160)
70+
layout.addWidget(self.label)
71+
72+
# Add a text area
73+
self.results = QTextEdit()
74+
layout.addWidget(self.results)
75+
76+
# Set the layout
77+
self.setLayout(layout)
78+
self.setWindowTitle("Dynamsoft Barcode Reader")
79+
self.setFixedSize(self.WINDOW_WIDTH, self.WINDOW_HEIGHT)
80+
81+
# https://stackoverflow.com/questions/1414781/prompt-on-exit-in-pyqt-application
82+
83+
def closeEvent(self, event):
84+
85+
msg = "Close the app?"
86+
reply = QMessageBox.question(self, 'Message',
87+
msg, QMessageBox.Yes, QMessageBox.No)
88+
89+
if reply == QMessageBox.Yes:
90+
self.stopCamera()
91+
event.accept()
92+
else:
93+
event.ignore()
94+
95+
def resizeImage(self, pixmap):
96+
lwidth = self.label.maximumWidth()
97+
pwidth = pixmap.width()
98+
lheight = self.label.maximumHeight()
99+
pheight = pixmap.height()
100+
101+
wratio = pwidth * 1.0 / lwidth
102+
hratio = pheight * 1.0 / lheight
103+
104+
if pwidth > lwidth or pheight > lheight:
105+
if wratio > hratio:
106+
lheight = pheight / wratio
107+
else:
108+
lwidth = pwidth / hratio
109+
110+
scaled_pixmap = pixmap.scaled(lwidth, lheight)
111+
return scaled_pixmap
112+
else:
113+
return pixmap
114+
115+
def showMessageBox(self, text):
116+
msgBox = QMessageBox()
117+
msgBox.setText(text)
118+
msgBox.exec()
119+
120+
def pickFile(self):
121+
self.stopCamera()
122+
# Load an image file.
123+
filename = QFileDialog.getOpenFileName(self, 'Open file',
124+
self._path, "Barcode images (*)")
125+
if filename is None or filename[0] == '':
126+
self.showMessageBox("No file selected")
127+
return
128+
129+
# Read barcodes
130+
frame, results = self._barcodeManager.decode_file(filename[0])
131+
if frame is None:
132+
self.showMessageBox("Cannot decode " + filename[0])
133+
return
134+
135+
self.showResults(frame, results)
136+
137+
def openCamera(self):
138+
139+
if not self._cap.isOpened():
140+
self.showMessageBox("Failed to open camera.")
141+
return
142+
143+
self._barcodeManager.create_barcode_process()
144+
self.timer.start(1000./24)
145+
146+
def stopCamera(self):
147+
self._barcodeManager.destroy_barcode_process()
148+
self.timer.stop()
149+
150+
def showResults(self, frame, results):
151+
out = ''
152+
index = 0
153+
154+
if results is not None and results[0] is not None:
155+
thickness = 2
156+
color = (0, 255, 0)
157+
out = 'Elapsed time: ' + "{:.2f}".format(results[1]) + 'ms\n\n'
158+
for result in results[0]:
159+
points = result.localization_result.localization_points
160+
out += "Index: " + str(index) + "\n"
161+
out += "Barcode format: " + result.barcode_format_string + '\n'
162+
out += "Barcode value: " + result.barcode_text + '\n'
163+
out += "Bounding box: " + \
164+
str(points[0]) + ' ' + str(points[1]) + ' ' + \
165+
str(points[2]) + ' ' + str(points[3]) + '\n'
166+
out += '-----------------------------------\n'
167+
index += 1
168+
169+
cv2.line(frame, points[0], points[1], color, thickness)
170+
cv2.line(frame, points[1], points[2], color, thickness)
171+
cv2.line(frame, points[2], points[3], color, thickness)
172+
cv2.line(frame, points[3], points[0], color, thickness)
173+
cv2.putText(frame, result.barcode_text,
174+
points[0], cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255))
175+
176+
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
177+
image = QImage(
178+
frame, frame.shape[1], frame.shape[0], frame.strides[0], QImage.Format_RGB888)
179+
pixmap = QPixmap.fromImage(image)
180+
pixmap = self.resizeImage(pixmap)
181+
self.label.setPixmap(pixmap)
182+
self.results.setText(out)
183+
184+
def nextFrameUpdate(self):
185+
ret, frame = self._cap.read()
186+
187+
if not ret:
188+
self.showMessageBox('Failed to get camera frame!')
189+
return
190+
191+
self._barcodeManager.append_frame(frame)
192+
self._results = self._barcodeManager.peek_results()
193+
194+
self.showResults(frame, self._results)
195+
196+
197+
def main():
198+
try:
199+
with open(sys.argv[1]) as f:
200+
license = f.read()
201+
BarcodeReader.init_license(
202+
license)
203+
except:
204+
BarcodeReader.init_license(
205+
"DLS2eyJoYW5kc2hha2VDb2RlIjoiMjAwMDAxLTE2NDk4Mjk3OTI2MzUiLCJvcmdhbml6YXRpb25JRCI6IjIwMDAwMSIsInNlc3Npb25QYXNzd29yZCI6IndTcGR6Vm05WDJrcEQ5YUoifQ==")
206+
207+
app = QApplication(sys.argv)
208+
ex = UI_Window()
209+
ex.show()
210+
sys.exit(app.exec())
211+
212+
213+
if __name__ == '__main__':
214+
print(__doc__)
215+
main()

0 commit comments

Comments
 (0)