111 lines
3.5 KiB
Python
111 lines
3.5 KiB
Python
"""
|
||
check_pdf_size.py – verify that a PDF's page dimensions match 35 mm × 25 mm.
|
||
|
||
Usage:
|
||
python check_pdf_size.py [path/to/label.pdf]
|
||
|
||
If no path is given the script operates on every PDF found in pdf_backup/.
|
||
Exit code 0 = all OK, 1 = mismatch or error.
|
||
"""
|
||
|
||
import os
|
||
import sys
|
||
|
||
# ── Target dimensions ────────────────────────────────────────────────────────
|
||
TARGET_W_MM = 35.0 # width (landscape, wider side)
|
||
TARGET_H_MM = 25.0 # height
|
||
TOLERANCE_MM = 0.5 # ± 0.5 mm is acceptable rounding from PDF viewers
|
||
|
||
PT_PER_MM = 72.0 / 25.4 # 1 mm in points
|
||
|
||
|
||
def read_page_size_pt(pdf_path):
|
||
"""
|
||
Return (width_pt, height_pt) of the first page of *pdf_path*.
|
||
Tries pypdf first, then pymupdf (fitz) as a fallback.
|
||
Raises RuntimeError if neither library is available.
|
||
"""
|
||
# ── pypdf ────────────────────────────────────────────────────────────────
|
||
try:
|
||
from pypdf import PdfReader # type: ignore
|
||
reader = PdfReader(pdf_path)
|
||
page = reader.pages[0]
|
||
w = float(page.mediabox.width)
|
||
h = float(page.mediabox.height)
|
||
return w, h
|
||
except ImportError:
|
||
pass
|
||
|
||
# ── pymupdf (fitz) ───────────────────────────────────────────────────────
|
||
try:
|
||
import fitz # type: ignore
|
||
doc = fitz.open(pdf_path)
|
||
rect = doc[0].rect
|
||
return rect.width, rect.height
|
||
except ImportError:
|
||
pass
|
||
|
||
raise RuntimeError(
|
||
"Install pypdf or pymupdf:\n"
|
||
" pip install pypdf\n"
|
||
" pip install pymupdf"
|
||
)
|
||
|
||
|
||
def check_file(pdf_path):
|
||
"""Print a pass/fail line for one PDF. Returns True if dimensions match."""
|
||
if not os.path.exists(pdf_path):
|
||
print(f" MISS {pdf_path} (file not found)")
|
||
return False
|
||
|
||
try:
|
||
w_pt, h_pt = read_page_size_pt(pdf_path)
|
||
except Exception as e:
|
||
print(f" ERR {pdf_path} ({e})")
|
||
return False
|
||
|
||
w_mm = w_pt / PT_PER_MM
|
||
h_mm = h_pt / PT_PER_MM
|
||
|
||
w_ok = abs(w_mm - TARGET_W_MM) <= TOLERANCE_MM
|
||
h_ok = abs(h_mm - TARGET_H_MM) <= TOLERANCE_MM
|
||
ok = w_ok and h_ok
|
||
|
||
status = "PASS" if ok else "FAIL"
|
||
print(
|
||
f" {status} {os.path.basename(pdf_path)}"
|
||
f" {w_mm:.2f}×{h_mm:.2f} mm"
|
||
f" (target {TARGET_W_MM}×{TARGET_H_MM} mm ±{TOLERANCE_MM} mm)"
|
||
)
|
||
return ok
|
||
|
||
|
||
def main():
|
||
targets = sys.argv[1:]
|
||
|
||
if not targets:
|
||
backup_dir = os.path.join(os.path.dirname(__file__), "pdf_backup")
|
||
if os.path.isdir(backup_dir):
|
||
targets = [
|
||
os.path.join(backup_dir, f)
|
||
for f in sorted(os.listdir(backup_dir))
|
||
if f.lower().endswith(".pdf")
|
||
]
|
||
if not targets:
|
||
# fall back to test_label.pdf in cwd
|
||
targets = ["test_label.pdf"]
|
||
|
||
print(f"Checking {len(targets)} PDF(s)…")
|
||
results = [check_file(p) for p in targets]
|
||
|
||
total = len(results)
|
||
passed = sum(results)
|
||
failed = total - passed
|
||
print(f"\n {passed}/{total} passed" + (f", {failed} FAILED" if failed else ""))
|
||
sys.exit(0 if failed == 0 else 1)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|
||
|