import io from barcode import Code128 from barcode.writer import ImageWriter from PIL import Image from reportlab.graphics import renderPDF from reportlab.graphics.barcode import qr from reportlab.graphics.shapes import Drawing from reportlab.lib.units import mm from reportlab.lib.utils import ImageReader from reportlab.pdfgen import canvas # Karte 10: Code128 kameratauglich drucken - Mindesthöhe ~10mm, Ruhezone # (quiet zone) >= 10 Strichbreiten links/rechts ist laut Karte die häufigste # Ursache für Scan-Fehler bei selbstgedruckten Etiketten. module_width=0.3mm # * 10 = 3mm Mindest-Ruhezone, quiet_zone hier bewusst höher (5mm) angesetzt. _BARCODE_OPTIONEN = { "module_width": 0.3, "module_height": 10.0, "quiet_zone": 5.0, "font_size": 10, "text_distance": 3.0, "write_text": True, "dpi": 300, } _RAND = 5 * mm _MINDESTBREITE = 60 * mm def generiere_code128_label_pdf(code: str, klartext_zusatz: str | None = None) -> bytes: """Druckfertiges Vektor-Label: Code128-Barcode + Klartext-Zeile (Code selbst, via write_text der Bibliothek) + optionale zweite Klartext-Zeile (z. B. Objekt-/Materialname) als Scan-Ausfall-Fallback (Karte 10).""" barcode_puffer = io.BytesIO() Code128(code, writer=ImageWriter()).write(barcode_puffer, options=_BARCODE_OPTIONEN) barcode_puffer.seek(0) bild = Image.open(barcode_puffer) dpi = _BARCODE_OPTIONEN["dpi"] breite_pt = bild.width / dpi * 72 hoehe_pt = bild.height / dpi * 72 label_breite = max(breite_pt + 2 * _RAND, _MINDESTBREITE) zusatz_hoehe = 14 if klartext_zusatz else 0 label_hoehe = hoehe_pt + zusatz_hoehe + 2 * _RAND pdf_puffer = io.BytesIO() c = canvas.Canvas(pdf_puffer, pagesize=(label_breite, label_hoehe)) barcode_puffer.seek(0) bild_x = (label_breite - breite_pt) / 2 bild_y = label_hoehe - hoehe_pt - _RAND c.drawImage(ImageReader(barcode_puffer), bild_x, bild_y, width=breite_pt, height=hoehe_pt) if klartext_zusatz: c.setFont("Helvetica", 9) c.drawCentredString(label_breite / 2, _RAND - 2, klartext_zusatz) c.showPage() c.save() return pdf_puffer.getvalue() _QR_ZIELGROESSE = 25 * mm _QR_MINDESTBREITE = 30 * mm def generiere_qr_label_pdf(code: str, klartext_zusatz: str | None = None) -> bytes: """Alternative zum Code128-Label (Nutzer-Wunsch): QR-Code statt 1D-Barcode - robuster bei teilbeschädigtem Etikett (Fehlerkorrektur), von praktisch jeder Handy-Kamera nativ lesbar, kompakter am Objekt anbringbar. Gleicher Klartext-Code als Inhalt wie beim Code128-Label, damit beide Varianten denselben Scan-Lookup (/objekte/code/{code}) treffen.""" qr_code = qr.QrCodeWidget(code) qr_code.barWidth = _QR_ZIELGROESSE qr_code.barHeight = _QR_ZIELGROESSE bounds = qr_code.getBounds() qr_breite_pt = bounds[2] - bounds[0] qr_hoehe_pt = bounds[3] - bounds[1] zeichnung = Drawing(qr_breite_pt, qr_hoehe_pt, transform=[1, 0, 0, 1, -bounds[0], -bounds[1]]) zeichnung.add(qr_code) label_breite = max(qr_breite_pt + 2 * _RAND, _QR_MINDESTBREITE) zusatz_hoehe = 14 if klartext_zusatz else 0 label_hoehe = qr_hoehe_pt + zusatz_hoehe + 2 * _RAND pdf_puffer = io.BytesIO() c = canvas.Canvas(pdf_puffer, pagesize=(label_breite, label_hoehe)) zeichnung_x = (label_breite - qr_breite_pt) / 2 zeichnung_y = label_hoehe - qr_hoehe_pt - _RAND renderPDF.draw(zeichnung, c, zeichnung_x, zeichnung_y) if klartext_zusatz: c.setFont("Helvetica", 9) c.drawCentredString(label_breite / 2, _RAND - 2, klartext_zusatz) c.showPage() c.save() return pdf_puffer.getvalue()