Files
ZLD_POC/backend/app/barcode_detector.py
2026-04-15 17:18:49 +08:00

104 lines
3.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Detect and decode barcodes / QR codes from an image file using zxing-cpp."""
from __future__ import annotations
import logging
from dataclasses import dataclass, field
from pathlib import Path
logger = logging.getLogger(__name__)
# Human-readable names for zxing BarcodeFormat values
_FORMAT_NAMES: dict[str, str] = {
"QRCode": "二维码 (QR Code)",
"DataMatrix": "DataMatrix",
"Aztec": "Aztec",
"PDF417": "PDF417",
"MicroQRCode": "微型二维码",
"RMQRCode": "R型QR码",
"EAN8": "EAN-8",
"EAN13": "EAN-13",
"UPCE": "UPC-E",
"UPCA": "UPC-A",
"Code39": "Code 39",
"Code93": "Code 93",
"Code128": "Code 128",
"ITF": "ITF交叉二五码",
"Codabar": "Codabar",
"DataBar": "DataBar",
"DataBarExpanded": "DataBar Expanded",
"MaxiCode": "MaxiCode",
"DXFilmEdge": "DXFilmEdge",
"LinearCodes": "一维码",
"MatrixCodes": "矩阵码",
}
@dataclass
class BarcodeResult:
format: str # zxing format string, e.g. "EAN13"
format_label: str # Chinese-friendly label
text: str # decoded text / number
# bounding box in image pixels (top-left origin)
x0: int
y0: int
x1: int
y1: int
valid: bool # zxing isValid
def detect_barcodes(image_path: Path) -> list[BarcodeResult]:
"""Scan *image_path* for all barcodes and QR codes.
Returns a list of :class:`BarcodeResult`, one entry per detected code.
Returns an empty list when nothing is found or on error.
"""
try:
import zxingcpp
except ImportError:
logger.warning("zxing-cpp not installed; barcode detection skipped")
return []
try:
from PIL import Image
img = Image.open(image_path).convert("RGB")
except Exception as exc:
logger.warning("barcode_detector: cannot open image %s: %s", image_path, exc)
return []
try:
results = zxingcpp.read_barcodes(img)
except Exception as exc:
logger.warning("barcode_detector: zxing scan failed: %s", exc)
return []
output: list[BarcodeResult] = []
for r in results:
fmt_str = str(r.format).replace("BarcodeFormat.", "")
label = _FORMAT_NAMES.get(fmt_str, fmt_str)
# zxing-cpp position: r.position is a quadrilateral with four points
try:
pts = r.position
xs = [pts.top_left.x, pts.top_right.x, pts.bottom_right.x, pts.bottom_left.x]
ys = [pts.top_left.y, pts.top_right.y, pts.bottom_right.y, pts.bottom_left.y]
x0, y0, x1, y1 = int(min(xs)), int(min(ys)), int(max(xs)), int(max(ys))
except Exception:
x0 = y0 = x1 = y1 = 0
output.append(BarcodeResult(
format=fmt_str,
format_label=label,
text=r.text,
x0=x0, y0=y0, x1=x1, y1=y1,
valid=r.valid,
))
logger.info(
"barcode_detector: found %s text=%r bbox=(%d,%d,%d,%d)",
fmt_str, r.text, x0, y0, x1, y1,
)
if not output:
logger.info("barcode_detector: no barcode/QR found in %s", image_path.name)
return output