Rebuild missing AcroForm fields

This commit is contained in:
Calixte Denizet 2026-07-13 11:20:15 +02:00
parent dd7e3731d1
commit 922d57631b
2 changed files with 29 additions and 3 deletions

View File

@ -1209,7 +1209,7 @@ class PDFEditor {
annotationDict.get("FT"), annotationDict.get("FT"),
"Sig" "Sig"
); );
const parentRef = annotationDict.get("Parent") || null; const parentRef = annotationDict.getRaw("Parent") || null;
// We remove the parent to avoid visiting it when cloning the // We remove the parent to avoid visiting it when cloning the
// annotation. // annotation.
// It'll be fixed later in #mergeAcroForms when merging the // It'll be fixed later in #mergeAcroForms when merging the
@ -2109,14 +2109,14 @@ class PDFEditor {
* If the document has some fields but no Fields entry in the AcroForm, we * If the document has some fields but no Fields entry in the AcroForm, we
* need to fix that by creating a Fields entry with the oldest parent field * need to fix that by creating a Fields entry with the oldest parent field
* for each field. * for each field.
* @param {Map<Ref, Ref>} fieldToParent * @param {RefSetCache} fieldToParent
* @param {XRef} xref * @param {XRef} xref
* @returns {Array<Ref>} * @returns {Array<Ref>}
*/ */
#fixFields(fieldToParent, xref) { #fixFields(fieldToParent, xref) {
const newFields = []; const newFields = [];
const processed = new RefSet(); const processed = new RefSet();
for (const [fieldRef, parentRef] of fieldToParent) { for (const [fieldRef, parentRef] of fieldToParent.items()) {
if (!parentRef) { if (!parentRef) {
newFields.push(fieldRef); newFields.push(fieldRef);
continue; continue;

View File

@ -7501,6 +7501,32 @@ small scripts as well as for`);
return fontIndex < 0 ? null : operatorList.argsArray[fontIndex][0]; return fontIndex < 0 ? null : operatorList.argsArray[fontIndex][0];
}; };
it("rebuilds a missing AcroForm Fields array", async function () {
const data = assemblePdf([
"1 0 obj\n<< /Type /Catalog /Pages 2 0 R /AcroForm 6 0 R >>\nendobj\n",
"2 0 obj\n<< /Type /Pages /Kids [3 0 R] /Count 1 >>\nendobj\n",
"3 0 obj\n<< /Type /Page /Parent 2 0 R /MediaBox [0 0 100 100] " +
"/Annots [4 0 R] >>\nendobj\n",
"4 0 obj\n<< /Type /Annot /Subtype /Widget /Rect [0 0 20 10] " +
"/Parent 5 0 R >>\nendobj\n",
"5 0 obj\n<< /FT /Tx /T (group) /Kids [4 0 R] >>\nendobj\n",
"6 0 obj\n<< /DA (/Helv 10 Tf) >>\nendobj\n",
]);
let loadingTask = getDocument({ data });
let pdfDoc = await loadingTask.promise;
const extracted = await pdfDoc.extractPages([{ document: null }]);
expect(extracted).not.toBeNull();
await loadingTask.destroy();
loadingTask = getDocument({ data: extracted });
pdfDoc = await loadingTask.promise;
expect(Object.keys(await pdfDoc.getFieldObjects())).toEqual(["group"]);
const annotations = await (await pdfDoc.getPage(1)).getAnnotations();
expect(annotations[0].fieldName).toEqual("group");
await loadingTask.destroy();
});
it("extract page 2 and check AcroForm Fields T entries", async function () { it("extract page 2 and check AcroForm Fields T entries", async function () {
let loadingTask = getDocument( let loadingTask = getDocument(
buildGetDocumentParams("form_two_pages.pdf") buildGetDocumentParams("form_two_pages.pdf")