Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file not shown.
10 changes: 5 additions & 5 deletions src/document/forms/acro-form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ export class AcroForm implements AcroFormLike {
return this.fieldsCache;
}

const fieldsArray = this.dict.getArray("Fields");
const fieldsArray = this.dict.getArray("Fields", this.registry.resolve.bind(this.registry));

if (!fieldsArray) {
return [];
Expand Down Expand Up @@ -592,7 +592,7 @@ export class AcroForm implements AcroFormLike {
fields.push(field);
} else {
// Non-terminal: recurse into children
const childKids = dict.getArray("Kids");
const childKids = dict.getArray("Kids", this.registry.resolve.bind(this.registry));

if (childKids) {
fields.push(...this.collectFields(childKids, visited, fullName));
Expand All @@ -611,7 +611,7 @@ export class AcroForm implements AcroFormLike {
* - Its /Kids contain widgets (no /T) rather than child fields (have /T)
*/
private isTerminalField(dict: PdfDict): boolean {
const kids = dict.getArray("Kids");
const kids = dict.getArray("Kids", this.registry.resolve.bind(this.registry));

if (!kids || kids.length === 0) {
return true;
Expand Down Expand Up @@ -722,7 +722,7 @@ export class AcroForm implements AcroFormLike {
* @param fieldRef Reference to the field dictionary
*/
addField(fieldRef: PdfRef): void {
let fieldsArray = this.dict.getArray("Fields");
let fieldsArray = this.dict.getArray("Fields", this.registry.resolve.bind(this.registry));

if (!fieldsArray) {
fieldsArray = new PdfArray([]);
Expand Down Expand Up @@ -752,7 +752,7 @@ export class AcroForm implements AcroFormLike {
* @returns true if the field was found and removed, false otherwise
*/
removeField(fieldRef: PdfRef): boolean {
const fieldsArray = this.dict.getArray("Fields");
const fieldsArray = this.dict.getArray("Fields", this.registry.resolve.bind(this.registry));

if (!fieldsArray) {
return false;
Expand Down
6 changes: 3 additions & 3 deletions src/document/forms/fields/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ export abstract class TerminalField extends FormField {
return this._widgets;
}

const kids = this.dict.getArray("Kids");
const kids = this.dict.getArray("Kids", this.registry.resolve.bind(this.registry));

if (!kids) {
this._widgets = [];
Expand Down Expand Up @@ -438,7 +438,7 @@ export abstract class TerminalField extends FormField {
}

// Otherwise, /Kids contains widgets
const kids = this.dict.getArray("Kids");
const kids = this.dict.getArray("Kids", this.registry.resolve.bind(this.registry));

if (!kids) {
this._widgets = [];
Expand Down Expand Up @@ -493,7 +493,7 @@ export abstract class TerminalField extends FormField {
const widgetRef = this.registry.register(widgetDict);

// Ensure /Kids array exists
let kids = this.dict.getArray("Kids");
let kids = this.dict.getArray("Kids", this.registry.resolve.bind(this.registry));

if (!kids) {
kids = new PdfArray([]);
Expand Down
12 changes: 8 additions & 4 deletions src/document/forms/fields/choice-fields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ export class DropdownField extends TerminalField {
* Get available options.
*/
getOptions(): ChoiceOption[] {
return parseChoiceOptions(this.dict.getArray("Opt"));
return parseChoiceOptions(this.dict.getArray("Opt", this.registry.resolve.bind(this.registry)));
}

/**
Expand Down Expand Up @@ -199,7 +199,7 @@ export class ListBoxField extends TerminalField {
* Get available options.
*/
getOptions(): ChoiceOption[] {
return parseChoiceOptions(this.dict.getArray("Opt"));
return parseChoiceOptions(this.dict.getArray("Opt", this.registry.resolve.bind(this.registry)));
}

/**
Expand All @@ -208,7 +208,7 @@ export class ListBoxField extends TerminalField {
*/
getValue(): string[] {
// /I (selection indices) takes precedence for multi-select
const indices = this.dict.getArray("I");
const indices = this.dict.getArray("I", this.registry.resolve.bind(this.registry));

if (indices && indices.length > 0) {
const options = this.getOptions();
Expand Down Expand Up @@ -297,7 +297,9 @@ export class ListBoxField extends TerminalField {
this.dict.set("V", PdfArray.of(...values.map(v => PdfString.fromString(v))));
}

// Set /I (indices) for multi-select
// Set /I (indices) to stay in sync with /V.
// For multi-select, /I stores the selected indices.
// For single-select, clear /I so it doesn't shadow /V.
if (this.isMultiSelect) {
const indices = values
.map(v => options.findIndex(o => o.value === v))
Expand All @@ -309,6 +311,8 @@ export class ListBoxField extends TerminalField {
} else {
this.dict.delete("I");
}
} else {
this.dict.delete("I");
}

this.needsAppearanceUpdate = true;
Expand Down
15 changes: 14 additions & 1 deletion src/document/forms/form-flattener.ts
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,20 @@ export class FormFlattener {
* This isolates the original page's graphics state from our additions.
*/
private wrapAndAppendContent(page: PdfDict, newContent: Uint8Array): void {
const existing = page.get("Contents");
let existing = page.get("Contents");

// Resolve indirect reference — /Contents may be a PdfRef pointing to a PdfArray
// of stream refs. Without resolving, we'd wrap the ref as-is, producing a
// nested array reference that PDF viewers cannot interpret.
// Only unwrap if the ref points to an array; if it points to a single stream,
// keep the PdfRef so it can be placed directly in the new contents array.
if (existing instanceof PdfRef) {
const resolved = this.registry.resolve(existing);

if (resolved instanceof PdfArray) {
existing = resolved;
}
}

// Create prefix stream with "q\n"
const prefixBytes = new Uint8Array([0x71, 0x0a]); // "q\n"
Expand Down
22 changes: 12 additions & 10 deletions src/document/forms/widget-annotation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,8 @@ export class WidgetAnnotation {
* @param state Optional state name for stateful widgets
*/
setNormalAppearance(stream: PdfStream, state?: string): void {
let ap = this.dict.getDict("AP");
const resolve = this.registry.resolve.bind(this.registry);
let ap = this.dict.getDict("AP", resolve);

if (!ap) {
ap = new PdfDict();
Expand All @@ -138,7 +139,7 @@ export class WidgetAnnotation {

if (state) {
// Stateful: AP.N is a dict of state -> stream
const nEntry = ap.get("N");
const nEntry = ap.get("N", resolve);
let nDict: PdfDict;

if (nEntry instanceof PdfDict && !(nEntry instanceof PdfStream)) {
Expand Down Expand Up @@ -183,7 +184,7 @@ export class WidgetAnnotation {
* For checkboxes/radios, this is the value when checked.
*/
getOnValue(): string | null {
const ap = this.dict.getDict("AP");
const ap = this.dict.getDict("AP", this.registry.resolve.bind(this.registry));

if (!ap) {
return null;
Expand Down Expand Up @@ -215,7 +216,7 @@ export class WidgetAnnotation {
* @returns True if all states have appearance streams
*/
hasAppearancesForStates(states: string[]): boolean {
const ap = this.dict.getDict("AP");
const ap = this.dict.getDict("AP", this.registry.resolve.bind(this.registry));

if (!ap) {
return false;
Expand Down Expand Up @@ -247,13 +248,14 @@ export class WidgetAnnotation {
* Check if this widget has any normal appearance stream.
*/
hasNormalAppearance(): boolean {
const ap = this.dict.getDict("AP");
const resolve = this.registry.resolve.bind(this.registry);
const ap = this.dict.getDict("AP", resolve);

if (!ap) {
return false;
}

const n = ap.get("N");
const n = ap.get("N", resolve);

return n !== null && n !== undefined;
}
Expand All @@ -263,7 +265,7 @@ export class WidgetAnnotation {
* For stateful widgets (checkbox/radio), pass the state name.
*/
getNormalAppearance(state?: string): PdfStream | null {
const ap = this.dict.getDict("AP");
const ap = this.dict.getDict("AP", this.registry.resolve.bind(this.registry));

if (!ap) {
return null;
Expand Down Expand Up @@ -298,7 +300,7 @@ export class WidgetAnnotation {
* Get rollover appearance stream (shown on mouse hover).
*/
getRolloverAppearance(state?: string): PdfStream | null {
const ap = this.dict.getDict("AP");
const ap = this.dict.getDict("AP", this.registry.resolve.bind(this.registry));

if (!ap) {
return null;
Expand Down Expand Up @@ -333,7 +335,7 @@ export class WidgetAnnotation {
* Get down appearance stream (shown when clicked).
*/
getDownAppearance(state?: string): PdfStream | null {
const ap = this.dict.getDict("AP");
const ap = this.dict.getDict("AP", this.registry.resolve.bind(this.registry));

if (!ap) {
return null;
Expand Down Expand Up @@ -368,7 +370,7 @@ export class WidgetAnnotation {
* Get border style.
*/
getBorderStyle(): BorderStyle | null {
const bs = this.dict.getDict("BS");
const bs = this.dict.getDict("BS", this.registry.resolve.bind(this.registry));

if (!bs) {
return null;
Expand Down
8 changes: 4 additions & 4 deletions src/document/name-tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ export class NameTree {
return null;
}

const kids = node.getArray("Kids");
const kids = node.getArray("Kids", this.resolver);

if (!kids || kids.length === 0) {
return null;
Expand Down Expand Up @@ -146,7 +146,7 @@ export class NameTree {
}

// We're at a leaf node - search the /Names array
const names = node.getArray("Names");
const names = node.getArray("Names", this.resolver);

if (!names) {
return null;
Expand Down Expand Up @@ -220,7 +220,7 @@ export class NameTree {

if (node.has("Kids")) {
// Intermediate node - queue children
const kids = node.getArray("Kids");
const kids = node.getArray("Kids", this.resolver);

if (kids) {
for (let i = 0; i < kids.length; i++) {
Expand All @@ -247,7 +247,7 @@ export class NameTree {
}
} else if (node.has("Names")) {
// Leaf node - yield entries
const names = node.getArray("Names");
const names = node.getArray("Names", this.resolver);

if (names) {
for (let i = 0; i < names.length; i += 2) {
Expand Down
Loading
Loading