mirror of
https://github.com/documenso/documenso
synced 2026-04-21 13:27:18 +00:00
fix: ensure PDF form appearance streams have required /Subtype /Form entry (#2328)
When flattening PDF forms, some appearance streams lack the required /Subtype /Form dictionary entry needed when used as XObjects. This causes corruption in Adobe Reader which fails to render these flattened fields. Per PDF spec, Form XObject streams require: - /Subtype /Form (required) - /FormType 1 (optional) The normalizeAppearanceStream function ensures these entries exist before adding appearance streams as XObjects to the page content stream. Fixes rendering issues where flattened fields don't display in PDF viewers.
This commit is contained in:
parent
c5c87e3fd1
commit
f129968968
1 changed files with 35 additions and 0 deletions
|
|
@ -4,8 +4,10 @@ import {
|
|||
PDFDict,
|
||||
type PDFDocument,
|
||||
PDFName,
|
||||
PDFNumber,
|
||||
PDFRadioGroup,
|
||||
PDFRef,
|
||||
PDFStream,
|
||||
drawObject,
|
||||
popGraphicsState,
|
||||
pushGraphicsState,
|
||||
|
|
@ -103,6 +105,36 @@ const getAppearanceRefForWidget = (field: PDFField, widget: PDFWidgetAnnotation)
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Ensures that an appearance stream has the required dictionary entries to be
|
||||
* used as a Form XObject. Some PDFs have appearance streams that are missing
|
||||
* the /Subtype /Form entry, which causes Adobe Reader to fail to render them.
|
||||
*
|
||||
* Per PDF spec, a Form XObject stream requires:
|
||||
* - /Subtype /Form (required)
|
||||
* - /BBox (required, but should already exist for appearance streams)
|
||||
* - /FormType 1 (optional, defaults to 1)
|
||||
*/
|
||||
const normalizeAppearanceStream = (document: PDFDocument, appearanceRef: PDFRef) => {
|
||||
const appearanceStream = document.context.lookup(appearanceRef);
|
||||
|
||||
if (!(appearanceStream instanceof PDFStream)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const dict = appearanceStream.dict;
|
||||
|
||||
// Ensure /Subtype /Form is set (required for XObject Form)
|
||||
if (!dict.has(PDFName.of('Subtype'))) {
|
||||
dict.set(PDFName.of('Subtype'), PDFName.of('Form'));
|
||||
}
|
||||
|
||||
// Ensure /FormType is set (optional, but good practice)
|
||||
if (!dict.has(PDFName.of('FormType'))) {
|
||||
dict.set(PDFName.of('FormType'), PDFNumber.of(1));
|
||||
}
|
||||
};
|
||||
|
||||
const flattenWidget = (document: PDFDocument, field: PDFField, widget: PDFWidgetAnnotation) => {
|
||||
try {
|
||||
const page = getPageForWidget(document, widget);
|
||||
|
|
@ -117,6 +149,9 @@ const flattenWidget = (document: PDFDocument, field: PDFField, widget: PDFWidget
|
|||
return;
|
||||
}
|
||||
|
||||
// Ensure the appearance stream has required XObject Form dictionary entries
|
||||
normalizeAppearanceStream(document, appearanceRef);
|
||||
|
||||
const xObjectKey = page.node.newXObject('FlatWidget', appearanceRef);
|
||||
|
||||
const rectangle = widget.getRectangle();
|
||||
|
|
|
|||
Loading…
Reference in a new issue