Skip to content

Commit 2fdd5ee

Browse files
committed
Fixed compatibility issue
1 parent e67b833 commit 2fdd5ee

1 file changed

Lines changed: 84 additions & 20 deletions

File tree

  • examples/official/camera_file

examples/official/camera_file/gui.py

Lines changed: 84 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -67,16 +67,25 @@
6767
EnumCapturedResultItemType,
6868
EnumErrorCode,
6969
EnumImagePixelFormat,
70-
EnumLayoutElementSource,
71-
EnumLayoutPattern,
7270
EnumPresetTemplate,
7371
FileImageTag,
74-
LayoutAnalysisParameter,
75-
LayoutAnalyzer,
7672
LicenseManager,
7773
Quadrilateral,
7874
)
7975

76+
try:
77+
from dynamsoft_barcode_reader_bundle import (
78+
EnumLayoutElementSource,
79+
EnumLayoutPattern,
80+
LayoutAnalysisParameter,
81+
LayoutAnalyzer,
82+
)
83+
except ImportError:
84+
EnumLayoutElementSource = None
85+
EnumLayoutPattern = None
86+
LayoutAnalysisParameter = None
87+
LayoutAnalyzer = None
88+
8089
LICENSE_KEY = (
8190
"DLS2eyJoYW5kc2hha2VDb2RlIjoiMjAwMDAxLTE2NDk4Mjk3OTI2MzUiLCJvcmdhbml6"
8291
"YXRpb25JRCI6IjIwMDAwMSIsInNlc3Npb25QYXNzd29yZCI6IndTcGR6Vm05WDJrcEQ5"
@@ -96,6 +105,20 @@
96105
LAYOUT_DEEP_TEMPLATE_PATH = str(BASE_DIR / "GridDeepDecode.json")
97106
LAYOUT_DEEP_TEMPLATE_NAME = "GridDeepDecode"
98107
LAYOUT_ROI_SCALE_FACTOR = 2.0
108+
LAYOUT_ANALYSIS_AVAILABLE = all(
109+
symbol is not None
110+
for symbol in (
111+
EnumLayoutElementSource,
112+
EnumLayoutPattern,
113+
LayoutAnalysisParameter,
114+
LayoutAnalyzer,
115+
)
116+
)
117+
LAYOUT_ANALYSIS_UNAVAILABLE_REASON = (
118+
""
119+
if LAYOUT_ANALYSIS_AVAILABLE
120+
else "Layout analysis is unavailable in the installed Dynamsoft Barcode Reader Bundle version."
121+
)
99122

100123
TEMPLATES: List[Tuple[str, str]] = [
101124
("Read Barcodes (default)", EnumPresetTemplate.PT_READ_BARCODES.value),
@@ -137,6 +160,7 @@ class FileScanMetrics:
137160
barcode_count: int = 0
138161
decode_elapsed_ms: Optional[int] = None
139162
used_layout_analysis: bool = False
163+
template: Optional[str] = None
140164

141165

142166
@dataclass
@@ -273,6 +297,9 @@ def decode(self, image: np.ndarray, quad: Quadrilateral) -> Optional[BarcodeHit]
273297

274298

275299
def decode_with_layout_analysis(image: np.ndarray) -> Tuple[List[BarcodeHit], Optional[str]]:
300+
if not LAYOUT_ANALYSIS_AVAILABLE:
301+
return [], LAYOUT_ANALYSIS_UNAVAILABLE_REASON
302+
276303
common_result, error = _capture_layout_fast_scan(image)
277304
if error:
278305
return [], error
@@ -413,7 +440,7 @@ def render_detection_mats(file_path: str, page_records: List[PageData]) -> List[
413440
class ScannerSignals(QObject):
414441
fileStarted = Signal(str, int)
415442
pageReady = Signal(object)
416-
fileMetricsReady = Signal(str, int, int, bool)
443+
fileMetricsReady = Signal(str, int, int, bool, str)
417444
fileFinished = Signal(str)
418445
allFinished = Signal()
419446
error = Signal(str, str)
@@ -431,7 +458,7 @@ def __init__(
431458
super().__init__(parent)
432459
self.files = list(files)
433460
self.template = template
434-
self.use_layout_analysis = use_layout_analysis
461+
self.use_layout_analysis = use_layout_analysis and LAYOUT_ANALYSIS_AVAILABLE
435462
# {(file_path, page_idx) -> PageData} - rendered pages we can reuse
436463
# so a template-switch re-decode does not re-render PDFs/TIFFs.
437464
self.cached_pages = cached_pages or {}
@@ -571,7 +598,7 @@ def run(self) -> None:
571598
file_elapsed_ms = int((time.perf_counter() - file_start) * 1000)
572599
total_barcodes = sum(len(page_record.barcodes) for page_record in page_records)
573600
self.signals.fileMetricsReady.emit(
574-
file_path, total_barcodes, file_elapsed_ms, True
601+
file_path, total_barcodes, file_elapsed_ms, True, self.template
575602
)
576603
self.signals.fileFinished.emit(file_path)
577604
continue
@@ -592,7 +619,9 @@ def run(self) -> None:
592619
results = result_array.get_results() if result_array else None
593620
if not results:
594621
file_elapsed_ms = int((time.perf_counter() - file_start) * 1000)
595-
self.signals.fileMetricsReady.emit(file_path, 0, file_elapsed_ms, False)
622+
self.signals.fileMetricsReady.emit(
623+
file_path, 0, file_elapsed_ms, False, self.template
624+
)
596625
self.signals.fileFinished.emit(file_path)
597626
continue
598627

@@ -626,7 +655,7 @@ def run(self) -> None:
626655
page_records[0].decode_elapsed_ms = file_elapsed_ms
627656
self.signals.pageReady.emit(page_records[0])
628657
self.signals.fileMetricsReady.emit(
629-
file_path, total_barcodes, file_elapsed_ms, False
658+
file_path, total_barcodes, file_elapsed_ms, False, self.template
630659
)
631660
self.signals.fileFinished.emit(file_path)
632661

@@ -899,6 +928,11 @@ def _build_ui(self) -> None:
899928
self._layout_analysis_checkbox.toggled.connect(
900929
self._on_layout_analysis_toggled
901930
)
931+
if not LAYOUT_ANALYSIS_AVAILABLE:
932+
self._layout_analysis_checkbox.setEnabled(False)
933+
self._layout_analysis_checkbox.setToolTip(
934+
LAYOUT_ANALYSIS_UNAVAILABLE_REASON
935+
)
902936
toolbar.addWidget(self._layout_analysis_checkbox)
903937

904938
toolbar.addSeparator()
@@ -1003,7 +1037,14 @@ def _init_license(self) -> None:
10031037
return
10041038
if code in (EnumErrorCode.EC_OK, EnumErrorCode.EC_LICENSE_CACHE_USED):
10051039
self._license_ok = True
1006-
self._status_label.setText("License OK. Drop files/folders to scan.")
1040+
if LAYOUT_ANALYSIS_AVAILABLE:
1041+
self._status_label.setText(
1042+
"License OK. Drop files/folders to scan. Check 'Layout Analysis' to enable grid analysis."
1043+
)
1044+
else:
1045+
self._status_label.setText(
1046+
"License OK. Layout analysis is unavailable in this bundle version; standard decoding only."
1047+
)
10071048
else:
10081049
self._license_ok = False
10091050
QMessageBox.warning(
@@ -1077,6 +1118,14 @@ def _on_fit_to_window(self) -> None:
10771118
self._status_label.setText("Fitted current page to window.")
10781119

10791120
def _on_layout_analysis_toggled(self, checked: bool) -> None:
1121+
if checked and not LAYOUT_ANALYSIS_AVAILABLE:
1122+
self._layout_analysis_checkbox.blockSignals(True)
1123+
self._layout_analysis_checkbox.setChecked(False)
1124+
self._layout_analysis_checkbox.blockSignals(False)
1125+
self._layout_analysis_enabled = False
1126+
self._status_label.setText(LAYOUT_ANALYSIS_UNAVAILABLE_REASON)
1127+
return
1128+
10801129
self._layout_analysis_enabled = checked
10811130
file_path = self._current_file_path()
10821131
mode_label = "layout analysis" if checked else "standard decoding"
@@ -1227,11 +1276,13 @@ def _on_file_metrics_ready(
12271276
barcode_count: int,
12281277
decode_elapsed_ms: int,
12291278
used_layout_analysis: bool,
1279+
template: str,
12301280
) -> None:
12311281
self._file_metrics[file_path] = FileScanMetrics(
12321282
barcode_count=barcode_count,
12331283
decode_elapsed_ms=decode_elapsed_ms,
12341284
used_layout_analysis=used_layout_analysis,
1285+
template=template,
12351286
)
12361287

12371288
item = self._file_items.get(file_path)
@@ -1350,10 +1401,7 @@ def _on_tree_changed(self, current: Optional[QTreeWidgetItem], _prev) -> None:
13501401

13511402
file_path = current.data(0, self.FILE_ROLE)
13521403
if file_path:
1353-
metrics = self._file_metrics.get(file_path)
1354-
if metrics is not None and (
1355-
metrics.used_layout_analysis != self._layout_analysis_enabled
1356-
):
1404+
if self._file_needs_redecode(file_path):
13571405
mode_label = (
13581406
"layout analysis" if self._layout_analysis_enabled else "standard decoding"
13591407
)
@@ -1405,23 +1453,38 @@ def _page_from_item(self, item: QTreeWidgetItem) -> Optional[PageData]:
14051453
return None
14061454
return self._pages.get((file_path, int(page_idx)))
14071455

1456+
def _decode_mode_label(self, file_path: str) -> str:
1457+
metrics = self._file_metrics.get(file_path)
1458+
if metrics is not None and metrics.used_layout_analysis:
1459+
return "Layout analysis"
1460+
return "Standard decoding"
1461+
1462+
def _file_needs_redecode(self, file_path: str) -> bool:
1463+
metrics = self._file_metrics.get(file_path)
1464+
if metrics is None:
1465+
return False
1466+
if self._layout_analysis_enabled:
1467+
return not metrics.used_layout_analysis
1468+
return metrics.used_layout_analysis or metrics.template != self._current_template
1469+
14081470
def _show_page(self, page: PageData) -> None:
14091471
self.viewer.set_page(page)
14101472
self.results.clear()
14111473

14121474
metrics = self._file_metrics.get(page.file_path)
1475+
mode_label = self._decode_mode_label(page.file_path)
14131476
decode_elapsed_ms = page.decode_elapsed_ms
14141477
decode_scope = "Decode"
14151478
if decode_elapsed_ms is None and metrics is not None:
14161479
decode_elapsed_ms = metrics.decode_elapsed_ms
14171480
decode_scope = "File decode"
14181481

1482+
info_text = f"[info] Mode: {mode_label} | Count: {len(page.barcodes)} barcode(s)"
14191483
if decode_elapsed_ms is not None:
1420-
info_item = QListWidgetItem(
1421-
f"[info] Count: {len(page.barcodes)} barcode(s) | {decode_scope} time: {decode_elapsed_ms} ms"
1422-
)
1423-
info_item.setForeground(QBrush(QColor("#1c7ed6")))
1424-
self.results.addItem(info_item)
1484+
info_text += f" | {decode_scope} time: {decode_elapsed_ms} ms"
1485+
info_item = QListWidgetItem(info_text)
1486+
info_item.setForeground(QBrush(QColor("#1c7ed6")))
1487+
self.results.addItem(info_item)
14251488

14261489
if page.error:
14271490
err_item = QListWidgetItem(f"[error] {page.error}")
@@ -1438,7 +1501,8 @@ def _show_page(self, page: PageData) -> None:
14381501
page_text = (
14391502
f"{os.path.basename(page.file_path)} "
14401503
f"Page {page.page_index + 1} / {page.total_pages} "
1441-
f"{len(page.barcodes)} barcode(s)"
1504+
f"{len(page.barcodes)} barcode(s) "
1505+
f"Mode: {mode_label}"
14421506
)
14431507
if decode_elapsed_ms is not None:
14441508
page_text += f" {decode_scope}: {decode_elapsed_ms} ms"

0 commit comments

Comments
 (0)