diff --git a/src/pdf_filler.py b/src/pdf_filler.py index 51a064e..77abbb1 100644 --- a/src/pdf_filler.py +++ b/src/pdf_filler.py @@ -11,6 +11,7 @@ from pathlib import Path from typing import Any, Dict, Optional from pypdf import PdfReader, PdfWriter +from pypdf.generic import NameObject, NumberObject from .config_loader import load_config from .exceptions import PdfTemplateError @@ -73,6 +74,43 @@ def build_field_dict( return fields +def _update_widget_visibility(writer: PdfWriter, fields: Dict[str, str]) -> None: + """Un-hide widget annotations for ist.N and plan.N fields that have a value. + + In the PDF template these fields carry annotation flag /F=6 (Print + Hidden) + by default. The form's JavaScript (ZeileBerechnen) normally removes the + hidden bit at runtime when ``anwesend.N`` is selected. Because we write + values directly without executing JavaScript we must clear the hidden bit + ourselves for every row where a value is present. + """ + HIDDEN_FIELD_PREFIXES = ("ist.", "plan.") + HIDDEN_BIT = 2 # PDF annotation flag bit 2 = Hidden + + for page in writer.pages: + annots = page.get("/Annots") + if not annots: + continue + for annot_ref in annots: + annot = annot_ref.get_object() + t = str(annot.get("/T", "")) + parent = annot.get("/Parent") + if parent: + par_t = str(parent.get_object().get("/T", "")) + full_name = f"{par_t}.{t}" + else: + full_name = t + + if not any(full_name.startswith(p) for p in HIDDEN_FIELD_PREFIXES): + continue + + has_value = bool(fields.get(full_name, "")) + current_f = int(annot.get("/F", 4)) + # Remove hidden bit when value present, keep/set it when absent + new_f = (current_f & ~HIDDEN_BIT) if has_value else (current_f | HIDDEN_BIT) + if new_f != current_f: + annot[NameObject("/F")] = NumberObject(new_f) + + def fill_pdf( attendance: MonthlyAttendance, template_path: str | Path, @@ -113,6 +151,8 @@ def fill_pdf( for page in writer.pages: writer.update_page_form_field_values(page, fields, auto_regenerate=False) + _update_widget_visibility(writer, fields) + output_path.parent.mkdir(parents=True, exist_ok=True) with output_path.open("wb") as fh: writer.write(fh)