feat: integrate native AcroForm widgets as typed fields - #4140
Conversation
|
❌ DCO Check Failed Hi @cau-git, your pull request has failed the Developer Certificate of Origin (DCO) check. This repository supports remediation commits, so you can fix this without rewriting history — but you must follow the required message format. 🛠 Quick Fix: Add a remediation commitRun this command: git commit --allow-empty -s -m "DCO Remediation Commit for Christoph Auer <cau@zurich.ibm.com>
I, Christoph Auer <cau@zurich.ibm.com>, hereby add my Signed-off-by to this commit: 06790b294d6bbcc692a257d2a0c6fad6afc6a916
I, Christoph Auer <cau@zurich.ibm.com>, hereby add my Signed-off-by to this commit: ac110b9a584a20d1a7a2f2da2bec3262536fa02c"
git push🔧 Advanced: Sign off each commit directlyFor the latest commit: git commit --amend --signoff
git push --force-with-leaseFor multiple commits: git rebase --signoff origin/main
git push --force-with-leaseMore info: DCO check report |
Merge Protections🔴 1 of 2 protections blocking · waiting on 👀 reviews
🔴 Require two reviewer for test updatesWaiting for
This rule is failing.When test data is updated, we require two reviewers
Show 1 satisfied protection🟢 Enforce conventional commitMake sure that we follow https://www.conventionalcommits.org/en/v1.0.0/
|
Extract native interactive PDF widgets from docling-parse parsed pages and materialize them as keyless, format-neutral fillable field values. A small PDF form-field stage runs after OCR and before layout postprocessing — the only point where both the raw layout FORM clusters and the parsed-page widgets are available. It normalizes each widget into a format-neutral field prediction, binds it to a raw FORM cluster (with a page-local fallback region for unmatched widgets), and never mutates the layout prediction or infers labels. Page assembly turns matched FORM clusters into FieldRegionElements and emits fallback regions; reading order materializes them as FieldRegionItem/FieldItem/FieldValueItem in native widget order. Raw AcroForm state (/Ff, /AS, field names) stays on SegmentedPdfPage.widgets; nothing PDF-specific enters DoclingDocument or add_field_value(). The legacy late-pypdfium2 FormItem+GraphData path (form_utils.py) is removed. Signed-off-by: Christoph Auer <cau@zurich.ibm.com>
68b775a to
6e5463b
Compare
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
|
Review notes on #4140, read against Well-Tagged PDF 1.0 (WTPDF), the basis of PDF/UA-2. The overall shape is right and I am building on it; these are the things I would change or decide before it lands.
Longer-term direction (structure-tree labels, PrintField for non-interactive forms, ordering by structure rather than |
Document experiment findings on native widget state vs. visual layout extraction colliding for filled form fields, alongside form field model and pipeline updates. Signed-off-by: Christoph Auer <cau@zurich.ibm.com>
Materialize a non-pushbutton /Btn widget as an empty-text FieldValueItem that nests a CHECKBOX_SELECTED/UNSELECTED child, instead of encoding state as a synthesized "checked"/"unchecked" value string. The value text stays empty so the doclang serializer inlines the <checkbox> token into <value>. Keeps /AS as the authoritative state and preserves the raw value in orig. Signed-off-by: Christoph Auer <cau@zurich.ibm.com>
…abel Reconcile the native /Btn widget with the layout CHECKBOX_* cluster it overlaps: match on widget-rect-in-cluster overlap, lift the cluster's option label (mark glyph stripped) onto the nested checkbox child, and promote the cluster out of the plain-text stream so it is no longer a disjoint duplicate. /AS stays authoritative for the selection state, overriding the glyph classifier. Unselected boxes with no overlapping cluster keep the widget-only path. Verified on f1040s1_filled: the checked option serializes as <value class="fillable"><checkbox class="selected"/>4797</value> with the duplicate cluster removed. Signed-off-by: Christoph Auer <cau@zurich.ibm.com>
…ts bbox as prov Drop the mark-glyph sanitation; the checkbox cluster's text is now lifted as-is onto the value, and the matched cluster bbox becomes the value's prov so the box wraps the whole checkbox+label rather than the tiny widget rect.
…ield_item
Introduce an item layer between field region and value: FieldRegionPrediction
now holds FieldItemPrediction items, each a keyless single value (today's flat
shape, unchanged) or a keyed group. A widget with no smaller enclosing container
than a text paragraph is matched to that paragraph -- the smallest enclosing
cluster wins over the page-wide FORM -- and widgets sharing one paragraph
accumulate under a single key (the paragraph text/bbox), with the paragraph
promoted out of the plain-text body. Reading order materializes the key via
add_field_key.
IRS Schedule 1 line 7 ("check here [] and enter amount repaid: 1221.00") now
emits one field_item: key + checkbox-unselected value + fillable "1221.00",
instead of two disjoint value-only fields.
…ld_region An inlined-widget paragraph was pulled out into its own field_region, detaching it from the list (and enclosing form region) it belonged to. Keep the paragraph cluster in the body and attach the keyed item onto its TextElement; reading order now emits a field_item in the paragraph's own place -- inside its list when it is a list item, else under the current parent -- with its text as the key. No separate field_region is created for the inline case. On IRS Sch.1, line 7's field_item now sits inside its list within the form's existing field_region instead of a standalone region ahead of it. Signed-off-by: Christoph Auer <cau@zurich.ibm.com>
A widget of zero height or width is an artifact (Well-Tagged PDF 1.0, 8.9.2.4.13) and a push button holds no field value; both were being emitted as empty fillable values. Skip them before normalization. Signed-off-by: Christoph Auer <cau@zurich.ibm.com>
Stacked on docling-project#4140. Well-Tagged PDF 1.0, the basis of PDF/UA-2, lists a field's /TU entry among the sources of context for a widget (8.10.2.1) and states that the field name (/T) does not contribute. A widget that is not inlined in a paragraph (a FORM-matched or fallback field) now gets a FieldKeyItem with its /TU text, without provenance since it is dictionary metadata rather than page text. Widgets inlined in a paragraph keep the paragraph as their key. FieldItemPrediction records where the key came from (layout or tooltip) so structure-tree labels can be added later without changing the contract. Docs and option text updated: fields are no longer described as keyless. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Jeff Witt <1848307+wittjeff@users.noreply.github.com>


What
Extracts native interactive PDF widgets (AcroForm) from docling-parse parsed pages and materializes them as keyless, format-neutral fillable field values in the
DoclingDocument.This supersedes and replaces #4055. That PR extracted fields late from pypdfium2 and attached legacy
FormItem + GraphDataobjects after document assembly; this change deletes that path (docling/utils/form_utils.py) entirely. #4055 should be closed once this lands.How
A small
PdfFormFieldModelstage runs after OCR and before layout postprocessing — the only point in the pipeline where both inputs exist:FORMcluster bboxes have not yet been tightened, andSegmentedPdfPage.widgets) are still available.The stage:
FieldValuePrediction(text/orig/bbox) — checkable controls resolve from widget-local/ASfirst, then/V; pushbuttons are excluded;FORMcluster by strong coverage (deterministic tie-break on coverage → smallest container → id);Page assembly replaces matched
FORMcontainer elements withFieldRegionElements (reusing the raw region bbox and the cluster's visible children) and emits fallback regions with collision-free synthetic ids. Reading order places each region by bbox and materializes it asFieldRegionItem → FieldItem → FieldValueItem(kind="fillable")in native widget order, with noFieldKeyItem.Boundaries
PdfWidgetand raw AcroForm state (/Ff,/AS, field names) stay onSegmentedPdfPage.widgets; nothing PDF-specific entersDoclingDocument,FieldValueItem, oradd_field_value().PdfWidgetsurvives past the form-field stage.extract_form_fields=Falseand documents without widgets are exact no-ops (layout prediction identical either way).Dependencies
Pins the AcroForm branches of the companion PRs (draft until they release):
feat/acroform-widget-extraction)/Ff,/AS, field name/type) — feat: expose complete AcroForm widget state docling-parse#334 (branchfeat/acroform-widget-extraction)pyproject.tomluses git-branch sources for these; they must be repointed to published versions before merge.Tests
tests/test_form_extraction.py:FIELD_KEY;What this does NOT solve (yet)
Deliberately out of scope for this PR — the fields are extracted and typed, but not yet semantically labeled or optimally ordered:
FieldValueItems. Raw AcroForm names (/T) and descriptions (/TU) are available onSegmentedPdfPage.widgetsbut are not associated with the value widgets asFieldKeyItems. No key is inferred from geometry, proximity, or/T//TU(an earlier reconciliation experiment that did this produced wrong keys and leaked machine names liketopmostSubform[0].Page1[0].f1_08[0]). Authoritative key↔value association is future work.