""" Print a calibration label to verify physical geometry on the PT-E560BT. The label carries four things that can be measured with a ruler on the tape: 1. A hairline box exactly at the 63 x 20 mm content bounds 2. Corner ticks at 10 mm from each corner, for checking scale (a 10 mm tick measures 10 mm only if the driver did not rescale) 3. A QR symbol with a known 12.28 mm size and 3 dots per module 4. Ruler marks every 10 mm along the bottom edge Whether the driver is scaling, rotating or offsetting the page can be read directly off the print, instead of being inferred. """ import os import sys sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) os.chdir(os.path.dirname(os.path.abspath(__file__))) from reportlab.lib.units import mm from reportlab.pdfgen import canvas from label_config import load_config, save_config from ptouch_label import PRINTER_DPI, LabelConfig, build_code_bitmap PRINTER = "Brother PT-E560BT" # One module of the QR at 3 dots/module, i.e. what 0.4233 mm should measure. MODULE_MM = 3.0 / PRINTER_DPI * 25.4 def build_calibration_pdf(cfg: LabelConfig, path: str) -> str: page_w, page_h = cfg.page_size_mm ox, oy = cfg.origin_mm c = canvas.Canvas(path, pagesize=(page_w * mm, page_h * mm)) c.setTitle("PT-E560BT calibration") def X(label_mm: float) -> float: return (ox + label_mm) * mm def Y(label_mm: float) -> float: return (oy + label_mm) * mm # 1. Content bounds, hairline c.setStrokeColorRGB(0, 0, 0) c.setLineWidth(0.25) c.rect(X(0), Y(0), cfg.page_width_mm * mm, cfg.page_height_mm * mm) # 2. Corner ticks: 10 mm legs just inside the box c.setLineWidth(0.5) for cx, cy, dx, dy in [ (0, 0, 1, 1), (cfg.page_width_mm, 0, -1, 1), (0, 20, 1, -1), (cfg.page_width_mm, 20, -1, -1), ]: c.line(X(cx), Y(cy), X(cx + 10 * dx), Y(cy)) c.line(X(cx), Y(cy), X(cx), Y(cy + 10 * dy)) # 3. Ruler marks every 10 mm along the bottom, labelled c.setFont("Helvetica", 4) for i in range(0, 61, 10): tick_h = 2.0 if i % 20 == 0 else 1.0 c.setLineWidth(0.4) c.line(X(i + 1), Y(1), X(i + 1), Y(1 + tick_h)) if i % 20 == 0: c.drawString(X(i + 2), Y(1.2), str(i)) # 4. Column guides at the real boundaries: 20 mm and 45 mm c.setLineWidth(0.25) for x in (cfg.col_logo_mm, cfg.col_logo_mm + cfg.col_text_mm): c.line(X(x), Y(1), X(x), Y(cfg.page_height_mm - 1)) # 5. Labels so the print can be interpreted without this file c.setFont("Helvetica-Bold", 5) c.drawString(X(20.8), Y(16.2), "CALIBRATION") c.setFont("Helvetica", 4) c.drawString(X(20.8), Y(13.0), "box = 63 x 20 mm") c.drawString(X(20.8), Y(9.5), "ticks = 10 mm") c.drawString(X(20.8), Y(6.5), "columns at") c.drawString(X(20.8), Y(3.5), "20 / 45 mm") c.drawString(X(20.8), Y(1.6), f"qr mod {MODULE_MM:.3f}mm") # 6. The QR itself, with a known module size bitmap = build_code_bitmap(cfg, "CAL", 112) if bitmap is not None: temp = os.path.join(os.path.dirname(path), "_cal_qr.png") bitmap.image.save(temp, "PNG") geo_box_w = bitmap.width_mm c.drawImage( temp, X(cfg.page_width_mm - 1 - geo_box_w), Y((cfg.page_height_mm - geo_box_w) / 2), width=geo_box_w * mm, height=geo_box_w * mm, mask=None, ) os.remove(temp) print(f"QR: {bitmap.modules} modules, {bitmap.dots_per_module:.0f} dots/module, " f"{bitmap.width_mm:.2f} mm across") c.showPage() c.save() return path def main() -> int: cfg = load_config() if not os.path.exists("label_config.json"): save_config(cfg) out = os.path.join("pdf_backup", "calibration_63x20.pdf") os.makedirs("pdf_backup", exist_ok=True) build_calibration_pdf(cfg, out) print(f"Page : {cfg.page_size_mm[0]:.1f} x {cfg.page_size_mm[1]:.1f} mm") print(f"Content : {cfg.page_width_mm:.1f} x {cfg.page_height_mm:.1f} mm " f"at origin {cfg.origin_mm}") print(f"Written : {out}") if "--no-print" in sys.argv: print("(--no-print given, not sending to printer)") return 0 from print_label import print_to_printer ok = print_to_printer(PRINTER, out, settings=cfg.sumatra_settings) print(f"Printed : {'SUCCESS' if ok else 'FAILED'}") return 0 if ok else 1 if __name__ == "__main__": raise SystemExit(main())