fix(form): remove widget refs from page Annots on removeField - #1785
fix(form): remove widget refs from page Annots on removeField#1785cozminv wants to merge 1 commit into
Conversation
removeField() passed the appearance stream ref to removeAnnot(), not the widget annotation ref listed in the page /Annots array. Widget objects were deleted from the document while stale /Annots entries remained. Co-authored-by: Cursor <cursoragent@cursor.com>
|
PR for #1784 |
|
Please bring this to @cantoo/pdf-lib for potential merge. It's the most advanced and maintained fork. This project is dead. |
|
Thanks — checked, and cantoo already carries this fix. I've since migrated to @cantoo/pdf-lib and confirmed on 2.9.2 that the /Annots bloat this PR describes is gone: the 8-page template that grew ~120 KB per round trip no longer accumulates dangling refs. Leaving this open in case anyone still on Hopding/pdf-lib@1.17.1 wants the patch, but no review is needed on my account. |
What?
Fix PDFForm.removeField() so it removes the widget annotation ref from each page's /Annots array, instead of passing an appearance-stream ref to removeAnnot().
Before (src/api/form/PDFForm.ts):
const widgetRef = this.findWidgetAppearanceRef(field, widget);
page.node.removeAnnot(widgetRef);
After:
const widgetRef = this.doc.context.getObjectRef(widget.dict);
if (widgetRef === undefined) {
throw new Error('Could not find PDFRef for widget annotation');
}
page.node.removeAnnot(widgetRef);
Added unit test "removes widget annotation refs from page Annots arrays" in tests/api/form/PDFForm.spec.ts.
Why?
removeField() currently calls page.node.removeAnnot() with the ref returned by findWidgetAppearanceRef() — an /AP/N appearance stream ref. Page /Annots arrays list widget annotation dict refs. PDFPageLeaf.removeAnnot() matches by exact PDFRef, so the widget entry is never removed. context.delete() then removes the widget object, leaving a dangling /Annots reference.
This was reported in #1001. PR #1002 fixed removal of child widget refs from the document context, but did not fix which ref is passed to removeAnnot().
Impact observed in a form-editor workflow (remove all fields, recreate them):
How?
For each widget returned by field.acroField.getWidgets():
Alternatives considered:
findWidgetAppearanceRef() is unchanged and remains used where appearance streams are needed (e.g. updateFieldAppearances, flatten).
Testing?
New Dependencies?
No
Screenshots
N/A — structural PDF fix; no visual appearance change in viewers when fields are removed correctly.
Suggested Reading?
Yes — PDF 32000 page annotations (/Annots) vs AcroForm field/widget structure; widget annotations use /Subtype /Widget and are listed on the page, separate from /AP appearance streams.
Anything Else?
Checklist