From 10a0e66d4b90c83eba3139c45bede4ec1a081694 Mon Sep 17 00:00:00 2001 From: Alexander Kireev Date: Tue, 23 Jun 2026 18:53:30 +0700 Subject: [PATCH] Omit AcroForm field options with an undefined value Passing a field option whose value is `undefined` to `doc.form*()` serialized the key as the literal token `undefined` (e.g. `/SomeKey undefined`), producing an invalid PDF object that strict parsers (PDFium, iText) reject. #1738 only handled the mapped `value`/`defaultValue` keys; any other undefined option still leaked. Drop entries with an undefined value in `_fieldDict` so such a field serializes identically to one created without the option. Fixes #1735. --- lib/mixins/acroform.js | 8 ++++++++ tests/unit/acroform.spec.js | 20 ++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/lib/mixins/acroform.js b/lib/mixins/acroform.js index 4933acb8..febefb08 100644 --- a/lib/mixins/acroform.js +++ b/lib/mixins/acroform.js @@ -199,6 +199,14 @@ export default { opts.Parent = opts.parent; delete opts.parent; } + // Drop entries with an `undefined` value so they are not serialized as the + // literal token `undefined` (e.g. `/SomeKey undefined`), which produces an + // invalid PDF object that strict parsers reject. + Object.keys(opts).forEach((key) => { + if (opts[key] === undefined) { + delete opts[key]; + } + }); return opts; }, diff --git a/tests/unit/acroform.spec.js b/tests/unit/acroform.spec.js index d7fc9db6..77488d64 100644 --- a/tests/unit/acroform.spec.js +++ b/tests/unit/acroform.spec.js @@ -204,6 +204,26 @@ describe('acroform', () => { expect(docData).toContainChunk(expectedDocData); }); + + test('options with an undefined value are omitted', () => { + // A field created with an extra option set to `undefined` must serialize + // identically to one created without that option at all - the key must + // not leak into the dictionary as the literal token `undefined`, which is + // an invalid PDF object that strict parsers reject (issue #1735). + const expectedDoc = new PDFDocument({ + info: { CreationDate: new Date(Date.UTC(2018, 1, 1)) }, + }); + expectedDoc.initForm(); + const expectedDocData = logData(expectedDoc); + expectedDoc.formText('demofield', 20, 20, 50, 20, {}); + + doc.initForm(); + const docData = logData(doc); + doc.formText('demofield', 20, 20, 50, 20, { CustomKey: undefined }); + + expect(docData.join('')).not.toMatch(/undefined/); + expect(docData).toContainChunk(expectedDocData); + }); }); test('flags', () => {