pdf-lite 1.6.4 → 1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/dist/acroform/appearance/pdf-button-appearance-stream.js +1 -1
  2. package/dist/acroform/appearance/pdf-graphics.d.ts +48 -0
  3. package/dist/acroform/appearance/pdf-graphics.js +177 -4
  4. package/dist/acroform/appearance/pdf-text-appearance-stream.d.ts +3 -0
  5. package/dist/acroform/appearance/pdf-text-appearance-stream.js +58 -29
  6. package/dist/acroform/fields/pdf-button-form-field.d.ts +11 -2
  7. package/dist/acroform/fields/pdf-button-form-field.js +76 -37
  8. package/dist/acroform/fields/pdf-choice-form-field.js +2 -2
  9. package/dist/acroform/fields/pdf-form-field.d.ts +39 -9
  10. package/dist/acroform/fields/pdf-form-field.js +234 -46
  11. package/dist/acroform/fields/pdf-text-form-field.js +23 -3
  12. package/dist/acroform/pdf-acro-form.d.ts +1 -0
  13. package/dist/acroform/pdf-acro-form.js +15 -4
  14. package/dist/acroform/xfa/pdf-xfa-data.d.ts +2 -1
  15. package/dist/acroform/xfa/pdf-xfa-data.js +36 -28
  16. package/dist/annotations/pdf-annotation.d.ts +1 -1
  17. package/dist/annotations/pdf-annotation.js +16 -2
  18. package/dist/core/objects/pdf-array.d.ts +6 -1
  19. package/dist/core/objects/pdf-array.js +3 -0
  20. package/dist/core/objects/pdf-boolean.d.ts +6 -2
  21. package/dist/core/objects/pdf-boolean.js +3 -0
  22. package/dist/core/objects/pdf-comment.d.ts +6 -2
  23. package/dist/core/objects/pdf-comment.js +3 -0
  24. package/dist/core/objects/pdf-date.d.ts +4 -0
  25. package/dist/core/objects/pdf-date.js +3 -0
  26. package/dist/core/objects/pdf-dictionary.d.ts +5 -0
  27. package/dist/core/objects/pdf-dictionary.js +16 -0
  28. package/dist/core/objects/pdf-hexadecimal.d.ts +6 -2
  29. package/dist/core/objects/pdf-hexadecimal.js +3 -0
  30. package/dist/core/objects/pdf-indirect-object.d.ts +8 -1
  31. package/dist/core/objects/pdf-indirect-object.js +14 -0
  32. package/dist/core/objects/pdf-name.d.ts +6 -2
  33. package/dist/core/objects/pdf-name.js +3 -0
  34. package/dist/core/objects/pdf-null.d.ts +5 -2
  35. package/dist/core/objects/pdf-null.js +3 -0
  36. package/dist/core/objects/pdf-number.d.ts +6 -1
  37. package/dist/core/objects/pdf-number.js +3 -0
  38. package/dist/core/objects/pdf-object-reference.d.ts +5 -0
  39. package/dist/core/objects/pdf-object-reference.js +7 -0
  40. package/dist/core/objects/pdf-object.d.ts +1 -0
  41. package/dist/core/objects/pdf-start-xref.d.ts +6 -1
  42. package/dist/core/objects/pdf-start-xref.js +3 -0
  43. package/dist/core/objects/pdf-stream.d.ts +8 -0
  44. package/dist/core/objects/pdf-stream.js +7 -0
  45. package/dist/core/objects/pdf-string.d.ts +8 -2
  46. package/dist/core/objects/pdf-string.js +9 -0
  47. package/dist/core/objects/pdf-trailer.d.ts +7 -0
  48. package/dist/core/objects/pdf-trailer.js +3 -0
  49. package/dist/core/objects/pdf-xref-table.d.ts +31 -5
  50. package/dist/core/objects/pdf-xref-table.js +23 -0
  51. package/dist/fonts/font-family.d.ts +12 -0
  52. package/dist/fonts/font-family.js +1 -0
  53. package/dist/fonts/index.d.ts +1 -0
  54. package/dist/fonts/index.js +1 -0
  55. package/dist/fonts/parsers/otf-parser.d.ts +2 -2
  56. package/dist/fonts/parsers/ttf-parser.d.ts +2 -2
  57. package/dist/fonts/parsers/woff-parser.d.ts +2 -0
  58. package/dist/fonts/parsers/woff-parser.js +6 -0
  59. package/dist/fonts/pdf-font.js +94 -8
  60. package/dist/fonts/types.d.ts +10 -0
  61. package/dist/pdf/pdf-document.d.ts +7 -0
  62. package/dist/pdf/pdf-document.js +6 -0
  63. package/dist/pdf/pdf-revision.d.ts +4 -0
  64. package/dist/pdf/pdf-revision.js +6 -0
  65. package/dist/utils/iterable-readable-stream.d.ts +2 -0
  66. package/dist/utils/iterable-readable-stream.js +8 -1
  67. package/dist/utils/parse-markdown-segments.d.ts +12 -0
  68. package/dist/utils/parse-markdown-segments.js +27 -0
  69. package/dist/utils/xml.d.ts +9 -0
  70. package/dist/utils/xml.js +59 -0
  71. package/package.json +2 -2
@@ -91,7 +91,7 @@ export class PdfChoiceFormField extends PdfFormField {
91
91
  const fontResources = this.buildFontResources(parsed.fontName);
92
92
  const isUnicode = font?.isUnicode ?? false;
93
93
  const reverseEncodingMap = font?.reverseEncodingMap;
94
- this.setAppearanceStream(new PdfChoiceAppearanceStream({
94
+ this.appearanceStream = new PdfChoiceAppearanceStream({
95
95
  rect: rect,
96
96
  value,
97
97
  da: parsed,
@@ -101,7 +101,7 @@ export class PdfChoiceFormField extends PdfFormField {
101
101
  reverseEncodingMap,
102
102
  displayOptions: this.options.map((opt) => opt.label),
103
103
  selectedIndex: this.selectedIndex,
104
- }));
104
+ });
105
105
  if (options?.makeReadOnly) {
106
106
  this.readOnly = true;
107
107
  this.print = true;
@@ -4,6 +4,7 @@ import { PdfString } from '../../core/objects/pdf-string.js';
4
4
  import { PdfObjectReference } from '../../core/objects/pdf-object-reference.js';
5
5
  import { PdfIndirectObject } from '../../core/objects/pdf-indirect-object.js';
6
6
  import { PdfFont } from '../../fonts/pdf-font.js';
7
+ import type { FontFamily } from '../../fonts/font-family.js';
7
8
  import { PdfStream } from '../../core/objects/pdf-stream.js';
8
9
  import { PdfWidgetAnnotation } from '../../annotations/pdf-widget-annotation.js';
9
10
  import type { PdfFieldType } from './types.js';
@@ -19,12 +20,16 @@ import { PdfJavaScriptAction } from '../js/pdf-javascript-action.js';
19
20
  */
20
21
  export declare abstract class PdfFormField extends PdfWidgetAnnotation {
21
22
  defaultGenerateAppearance: boolean;
23
+ /** Raw markdown string set by markdownValue; cleared by setRawValue. */
24
+ protected _markdownValue?: string;
25
+ private _fontFamily?;
22
26
  /** @internal */
23
27
  _form?: PdfAcroForm;
24
28
  constructor(other?: PdfIndirectObject | {
25
29
  form?: PdfAcroForm;
26
30
  });
27
31
  set form(f: PdfAcroForm);
32
+ static getFieldType(other: PdfIndirectObject): 'Btn' | 'Sig' | 'Tx' | 'Ch' | null;
28
33
  static create(other?: PdfIndirectObject): PdfFormField;
29
34
  get parent(): PdfFormField | undefined;
30
35
  set parent(field: PdfFormField | PdfIndirectObject | undefined);
@@ -40,25 +45,43 @@ export declare abstract class PdfFormField extends PdfWidgetAnnotation {
40
45
  * Returns undefined if neither source provides the font.
41
46
  */
42
47
  buildFontResources(fontName: string): PdfDictionary | undefined;
48
+ /**
49
+ * Like buildFontResources but includes multiple font names (regular +
50
+ * variant fonts) in a single Resources/Font dictionary. Falls through to
51
+ * buildFontResources when only one name is provided.
52
+ */
53
+ buildAllFontResources(fontNames: string[]): PdfDictionary | undefined;
43
54
  get fieldType(): PdfFieldType | null;
44
55
  set fieldType(type: PdfFieldType | null);
45
56
  get name(): string;
46
57
  set name(name: string);
47
58
  get defaultValue(): string;
48
59
  set defaultValue(val: string);
60
+ get onStates(): string[];
61
+ get onState(): string | null;
62
+ set onState(state: string);
49
63
  get value(): string;
64
+ protected setRawValue(val: string | PdfString): void;
50
65
  set value(val: string | PdfString);
51
- /**
52
- * Writes the value to the dictionary. Returns true if appearance generation
53
- * should proceed, false to skip it (e.g. when value was cleared).
54
- * Override in subclasses to change the stored representation.
55
- */
56
- protected _storeValue(val: string | PdfString, fieldParent: PdfFormField | undefined): boolean;
66
+ set markdownValue(val: string);
57
67
  get fontSize(): number | null;
58
68
  set fontSize(size: number);
59
69
  get fontName(): string | null;
60
70
  set fontName(fontName: string);
61
71
  set font(font: PdfFont | null);
72
+ private _embedFontInDR;
73
+ get fontFamily(): FontFamily | null;
74
+ set fontFamily(family: FontFamily | null);
75
+ get fontVariantNames(): {
76
+ bold?: string;
77
+ italic?: string;
78
+ boldItalic?: string;
79
+ };
80
+ protected get resolvedVariantFonts(): {
81
+ bold?: PdfFont;
82
+ italic?: PdfFont;
83
+ boldItalic?: PdfFont;
84
+ };
62
85
  get flags(): PdfFormFieldFlags;
63
86
  set flags(v: PdfFormFieldFlags);
64
87
  get readOnly(): boolean;
@@ -108,16 +131,23 @@ export declare abstract class PdfFormField extends PdfWidgetAnnotation {
108
131
  abstract generateAppearance(options?: {
109
132
  makeReadOnly?: boolean;
110
133
  textYOffset?: number;
134
+ onStateName?: string;
111
135
  }): boolean;
112
- setAppearanceStream(stream: PdfIndirectObject | {
136
+ set appearanceStream(stream: PdfIndirectObject | {
113
137
  [key: string]: PdfIndirectObject;
114
- }): void;
138
+ });
139
+ set downAppearanceStream(stream: PdfIndirectObject | {
140
+ [key: string]: PdfIndirectObject;
141
+ });
142
+ get appearanceState(): string | null;
143
+ set appearanceState(state: string | null);
115
144
  /**
116
145
  * Returns the list of appearance state names from the normal appearance
117
146
  * dictionary (e.g. ["Yes", "Off"] for a checkbox).
118
147
  */
119
- get appearanceStates(): string[];
148
+ get appearanceStates(): ReadonlyArray<string>;
120
149
  getAppearanceStream(setting?: string): PdfIndirectObject<PdfStream> | null;
150
+ hasAppearanceStream(setting: string): boolean;
121
151
  private static _fallbackCtor?;
122
152
  private static _registry;
123
153
  static registerFieldType(ft: 'Sig' | 'Btn' | 'Tx' | 'Ch', ctor: new (other?: PdfIndirectObject) => PdfFormField, options?: {
@@ -14,6 +14,7 @@ import { PdfFieldType as PdfFieldTypeConst } from './types.js';
14
14
  import { PdfFormFieldFlags } from './pdf-form-field-flags.js';
15
15
  import { PdfFieldActions } from '../js/pdf-field-actions.js';
16
16
  import { PdfJavaScriptAction } from '../js/pdf-javascript-action.js';
17
+ import { parseMarkdownSegments } from '../../utils/parse-markdown-segments.js';
17
18
  /**
18
19
  * Abstract base form field class. Extends PdfWidgetAnnotation with form-specific properties:
19
20
  * FT, V, DA, Ff, T (name), field hierarchy (parent/children/siblings).
@@ -21,6 +22,9 @@ import { PdfJavaScriptAction } from '../js/pdf-javascript-action.js';
21
22
  */
22
23
  export class PdfFormField extends PdfWidgetAnnotation {
23
24
  defaultGenerateAppearance = true;
25
+ /** Raw markdown string set by markdownValue; cleared by setRawValue. */
26
+ _markdownValue;
27
+ _fontFamily;
24
28
  /** @internal */
25
29
  _form;
26
30
  constructor(other) {
@@ -32,10 +36,25 @@ export class PdfFormField extends PdfWidgetAnnotation {
32
36
  set form(f) {
33
37
  this._form = f;
34
38
  }
39
+ static getFieldType(other) {
40
+ if (!(other.content instanceof PdfDictionary))
41
+ return null;
42
+ const ft = other.content.get('FT')?.as(PdfName)?.value;
43
+ if (ft)
44
+ return ft;
45
+ const parentRef = other.content.get('Parent');
46
+ if (parentRef instanceof PdfObjectReference) {
47
+ const parentResolved = parentRef.resolve();
48
+ if (parentResolved?.content instanceof PdfDictionary) {
49
+ return (parentResolved.content.get('FT')?.as(PdfName)?.value ?? null);
50
+ }
51
+ }
52
+ return null;
53
+ }
35
54
  static create(other) {
36
55
  if (!(other?.content instanceof PdfDictionary))
37
56
  throw new Error('Invalid form field object');
38
- const ft = other?.content.get('FT')?.as(PdfName)?.value;
57
+ const ft = PdfFormField.getFieldType(other);
39
58
  const cls = ft ? PdfFormField._registry.get(ft) : undefined;
40
59
  if (!cls) {
41
60
  if (PdfFormField._fallbackCtor) {
@@ -60,14 +79,23 @@ export class PdfFormField extends PdfWidgetAnnotation {
60
79
  if (field instanceof PdfFormField) {
61
80
  field.children = [...field.children, this];
62
81
  }
82
+ // Auto-add widget to page's Annots array
83
+ const page = this.page;
84
+ if (page) {
85
+ const annots = page.annotations;
86
+ const ref = this.reference;
87
+ const key = ref.key;
88
+ const alreadyPresent = annots.items.some((r) => r instanceof PdfObjectReference && r.key === key);
89
+ if (!alreadyPresent) {
90
+ annots.items.push(ref);
91
+ }
92
+ }
63
93
  }
64
94
  get children() {
65
95
  const kids = this.content.get('Kids')?.items ?? [];
66
96
  const result = [];
67
97
  for (const ref of kids) {
68
98
  const resolved = ref.resolve();
69
- if (!resolved || !(resolved.content instanceof PdfDictionary))
70
- continue;
71
99
  result.push(PdfFormField.create(resolved));
72
100
  }
73
101
  return result;
@@ -156,9 +184,41 @@ export class PdfFormField extends PdfWidgetAnnotation {
156
184
  }
157
185
  return undefined;
158
186
  }
187
+ /**
188
+ * Like buildFontResources but includes multiple font names (regular +
189
+ * variant fonts) in a single Resources/Font dictionary. Falls through to
190
+ * buildFontResources when only one name is provided.
191
+ */
192
+ buildAllFontResources(fontNames) {
193
+ if (fontNames.length <= 1)
194
+ return this.buildFontResources(fontNames[0]);
195
+ const dr = this.defaultResources;
196
+ const fontRaw = dr?.get('Font');
197
+ let drFontDict;
198
+ if (fontRaw instanceof PdfObjectReference) {
199
+ const resolved = fontRaw.resolve()?.content;
200
+ if (resolved instanceof PdfDictionary)
201
+ drFontDict = resolved;
202
+ }
203
+ else if (fontRaw instanceof PdfDictionary) {
204
+ drFontDict = fontRaw;
205
+ }
206
+ const resFontDict = new PdfDictionary();
207
+ for (const name of fontNames) {
208
+ if (drFontDict?.get(name)) {
209
+ resFontDict.set(name, drFontDict.get(name));
210
+ }
211
+ }
212
+ if (resFontDict.keys().length > 0) {
213
+ const resources = new PdfDictionary();
214
+ resources.set('Font', resFontDict);
215
+ return resources;
216
+ }
217
+ // Fallback to single-font path for the primary font name
218
+ return this.buildFontResources(fontNames[0]);
219
+ }
159
220
  get fieldType() {
160
- const ft = this.content.get('FT')?.as(PdfName)?.value ??
161
- this.parent?.content.get('FT')?.as(PdfName)?.value;
221
+ const ft = PdfFormField.getFieldType(this);
162
222
  switch (ft) {
163
223
  case 'Tx':
164
224
  return 'Text';
@@ -202,6 +262,27 @@ export class PdfFormField extends PdfWidgetAnnotation {
202
262
  set defaultValue(val) {
203
263
  this.content.set('DV', new PdfString(val));
204
264
  }
265
+ get onStates() {
266
+ return this.appearanceStates.filter((s) => s !== 'Off');
267
+ }
268
+ get onState() {
269
+ return this.appearanceStates.find((s) => s !== 'Off') || null;
270
+ }
271
+ set onState(state) {
272
+ if (!this.appearanceStates.includes(state)) {
273
+ const currentOnState = this.onState;
274
+ if (currentOnState) {
275
+ this.appearanceStreamDict
276
+ ?.get('N')
277
+ ?.as(PdfDictionary)
278
+ ?.move(currentOnState, state);
279
+ }
280
+ else {
281
+ // No existing on-state; generate a new appearance stream for the new state
282
+ this.generateAppearance({ onStateName: state });
283
+ }
284
+ }
285
+ }
205
286
  get value() {
206
287
  const v = this.content.get('V') ?? this.parent?.content.get('V');
207
288
  if (v instanceof PdfString) {
@@ -221,48 +302,67 @@ export class PdfFormField extends PdfWidgetAnnotation {
221
302
  }
222
303
  return '';
223
304
  }
224
- set value(val) {
225
- if (this.value === val)
226
- return;
227
- const fieldParent = this.parent?.content.get('FT')
228
- ? this.parent
229
- : undefined;
230
- const generateAppearance = this._storeValue(val, fieldParent);
231
- if (generateAppearance && this.defaultGenerateAppearance) {
232
- this.generateAppearance();
233
- for (const sibling of this.siblings) {
234
- if (sibling !== this &&
235
- sibling.rect &&
236
- sibling.defaultGenerateAppearance) {
237
- sibling.generateAppearance();
238
- }
305
+ setRawValue(val) {
306
+ this._markdownValue = undefined;
307
+ const targets = [this];
308
+ const parent = this.parent;
309
+ if (parent?.fieldType) {
310
+ targets.push(parent);
311
+ }
312
+ const pdfVal = val instanceof PdfString ? val : new PdfString(val);
313
+ const isEmpty = pdfVal.length === 0;
314
+ for (const target of targets) {
315
+ if (isEmpty) {
316
+ target.content.delete('V');
317
+ target.appearanceState = null;
239
318
  }
240
- // Separated field/widget structure: field has no Rect but its Kids
241
- // are widget annotations that do. Generate appearances for them.
242
- if (!this.rect) {
243
- for (const child of this.children) {
244
- if (child.rect && child.defaultGenerateAppearance) {
245
- if (this._form)
246
- child.form = this._form;
247
- child.generateAppearance();
248
- }
249
- }
319
+ else {
320
+ target.content.set('V', pdfVal);
250
321
  }
251
322
  }
252
- if (this._form) {
253
- this._form.xfa?.datasets?.updateField(this.name, this.value);
323
+ if (isEmpty) {
324
+ this._form?.xfa?.datasets?.updateField(this.name, '');
254
325
  }
326
+ if (this.defaultGenerateAppearance) {
327
+ this.generateAppearance();
328
+ }
329
+ for (const sibling of this.siblings) {
330
+ if (sibling !== this && sibling.defaultGenerateAppearance) {
331
+ sibling.generateAppearance();
332
+ }
333
+ }
334
+ // Separated field/widget structure: field has no Rect but its Kids
335
+ // are widget annotations that do. Clear stale V entries on children
336
+ // so they inherit the parent's value, then generate appearances.
337
+ for (const child of this.children) {
338
+ if (child.content.has('V')) {
339
+ child.content.delete('V');
340
+ }
341
+ if (child.defaultGenerateAppearance) {
342
+ if (this._form)
343
+ child.form = this._form;
344
+ child.generateAppearance();
345
+ }
346
+ }
347
+ this._form?.xfa?.datasets?.updateField(this.name, this.value);
255
348
  }
256
- /**
257
- * Writes the value to the dictionary. Returns true if appearance generation
258
- * should proceed, false to skip it (e.g. when value was cleared).
259
- * Override in subclasses to change the stored representation.
260
- */
261
- _storeValue(val, fieldParent) {
262
- const pdfVal = val instanceof PdfString ? val : new PdfString(val);
263
- this.content.set('V', pdfVal);
264
- fieldParent?.content.set('V', pdfVal);
265
- return true;
349
+ set value(val) {
350
+ this.setRawValue(val);
351
+ }
352
+ set markdownValue(val) {
353
+ const plainText = parseMarkdownSegments(val)
354
+ .map((s) => s.text)
355
+ .join('');
356
+ // Store plain text as V without triggering appearance generation yet
357
+ const saved = this.defaultGenerateAppearance;
358
+ this.defaultGenerateAppearance = false;
359
+ this.setRawValue(plainText);
360
+ this.defaultGenerateAppearance = saved;
361
+ // setRawValue cleared _markdownValue; store the markdown string now
362
+ this._markdownValue = val;
363
+ if (this.defaultGenerateAppearance) {
364
+ this.generateAppearance();
365
+ }
266
366
  }
267
367
  get fontSize() {
268
368
  const da = this.defaultAppearance || '';
@@ -305,6 +405,8 @@ export class PdfFormField extends PdfWidgetAnnotation {
305
405
  }
306
406
  const resourceName = font.resourceName;
307
407
  const currentSize = this.fontSize ?? 12;
408
+ this._embedFontInDR(font);
409
+ // Update the DA string to use the font
308
410
  const da = this.defaultAppearance || '';
309
411
  if (!da) {
310
412
  this.content.set('DA', new PdfDefaultAppearance(resourceName, currentSize, '0 g'));
@@ -316,6 +418,62 @@ export class PdfFormField extends PdfWidgetAnnotation {
316
418
  this.content.set('DA', parsed);
317
419
  }
318
420
  }
421
+ _embedFontInDR(font) {
422
+ const resourceName = font.resourceName;
423
+ // Add font to field's default resources
424
+ const dr = this.content.get('DR') || new PdfDictionary();
425
+ let fontDict = dr.get('Font');
426
+ if (!fontDict) {
427
+ fontDict = new PdfDictionary();
428
+ dr.set('Font', fontDict);
429
+ }
430
+ fontDict.set(resourceName, font.reference);
431
+ this.content.set('DR', dr);
432
+ // Also add to form's default resources if available
433
+ if (this._form) {
434
+ const formDr = this._form.defaultResources ||
435
+ new PdfDictionary();
436
+ let formFontDict = formDr.get('Font');
437
+ if (!formFontDict) {
438
+ formFontDict = new PdfDictionary();
439
+ formDr.set('Font', formFontDict);
440
+ }
441
+ formFontDict.set(resourceName, font.reference);
442
+ this._form.defaultResources = formDr;
443
+ }
444
+ }
445
+ get fontFamily() {
446
+ return this._fontFamily ?? null;
447
+ }
448
+ set fontFamily(family) {
449
+ if (family === null) {
450
+ this._fontFamily = undefined;
451
+ return;
452
+ }
453
+ this._fontFamily = family;
454
+ // Setting regular via the existing setter keeps DA string in sync
455
+ this.font = family.regular;
456
+ if (family.bold)
457
+ this._embedFontInDR(family.bold);
458
+ if (family.italic)
459
+ this._embedFontInDR(family.italic);
460
+ if (family.boldItalic)
461
+ this._embedFontInDR(family.boldItalic);
462
+ }
463
+ get fontVariantNames() {
464
+ return {
465
+ bold: this._fontFamily?.bold?.resourceName,
466
+ italic: this._fontFamily?.italic?.resourceName,
467
+ boldItalic: this._fontFamily?.boldItalic?.resourceName,
468
+ };
469
+ }
470
+ get resolvedVariantFonts() {
471
+ return {
472
+ bold: this._fontFamily?.bold,
473
+ italic: this._fontFamily?.italic,
474
+ boldItalic: this._fontFamily?.boldItalic,
475
+ };
476
+ }
319
477
  get flags() {
320
478
  const flags = new PdfFormFieldFlags(this.content.get('Ff') ?? this.parent?.content.get('Ff') ?? 0);
321
479
  flags.onChange(() => {
@@ -499,7 +657,7 @@ export class PdfFormField extends PdfWidgetAnnotation {
499
657
  engine: this._form?.jsEngine,
500
658
  });
501
659
  }
502
- setAppearanceStream(stream) {
660
+ set appearanceStream(stream) {
503
661
  this.appearanceStreamDict ||= new PdfDictionary();
504
662
  if (stream instanceof PdfIndirectObject) {
505
663
  this.appearanceStreamDict.set('N', stream.reference);
@@ -512,6 +670,35 @@ export class PdfFormField extends PdfWidgetAnnotation {
512
670
  this.appearanceStreamDict.set('N', dict);
513
671
  }
514
672
  }
673
+ set downAppearanceStream(stream) {
674
+ this.appearanceStreamDict ||= new PdfDictionary();
675
+ if (stream instanceof PdfIndirectObject) {
676
+ this.appearanceStreamDict.set('D', stream.reference);
677
+ }
678
+ else {
679
+ const dict = new PdfDictionary();
680
+ for (const key in stream) {
681
+ dict.set(key, stream[key].reference);
682
+ }
683
+ this.appearanceStreamDict.set('D', dict);
684
+ }
685
+ }
686
+ get appearanceState() {
687
+ return this.content.get('AS')?.as(PdfName)?.value ?? null;
688
+ }
689
+ set appearanceState(state) {
690
+ if (state === null) {
691
+ this.content.delete('AS');
692
+ return;
693
+ }
694
+ else {
695
+ this.content.set('AS', new PdfName(state));
696
+ }
697
+ if (this.defaultGenerateAppearance &&
698
+ !this.hasAppearanceStream(state)) {
699
+ this.generateAppearance();
700
+ }
701
+ }
515
702
  /**
516
703
  * Returns the list of appearance state names from the normal appearance
517
704
  * dictionary (e.g. ["Yes", "Off"] for a checkbox).
@@ -534,9 +721,7 @@ export class PdfFormField extends PdfWidgetAnnotation {
534
721
  }
535
722
  }
536
723
  else if (n instanceof PdfDictionary) {
537
- const key = setting ??
538
- this.content.get('AS')?.as(PdfName)?.value ??
539
- undefined;
724
+ const key = setting ?? this.appearanceState ?? undefined;
540
725
  if (key) {
541
726
  const entry = n.get(key);
542
727
  if (entry instanceof PdfObjectReference) {
@@ -549,6 +734,9 @@ export class PdfFormField extends PdfWidgetAnnotation {
549
734
  }
550
735
  return null;
551
736
  }
737
+ hasAppearanceStream(setting) {
738
+ return this.appearanceStates.includes(setting);
739
+ }
552
740
  static _fallbackCtor;
553
741
  static _registry = new Map();
554
742
  static registerFieldType(ft, ctor, options) {
@@ -21,10 +21,27 @@ export class PdfTextFormField extends PdfFormField {
21
21
  if (!parsed)
22
22
  return false;
23
23
  const font = this.font;
24
- const fontResources = this.buildFontResources(parsed.fontName);
24
+ const variantNames = this.fontVariantNames;
25
+ const variantFonts = this.resolvedVariantFonts;
26
+ const allFontNames = [
27
+ parsed.fontName,
28
+ variantNames.bold,
29
+ variantNames.italic,
30
+ variantNames.boldItalic,
31
+ ].filter((n) => !!n);
32
+ const fontResources = this.buildAllFontResources(allFontNames);
33
+ const resolvedFonts = new Map();
34
+ if (font)
35
+ resolvedFonts.set(parsed.fontName, font);
36
+ if (variantFonts.bold)
37
+ resolvedFonts.set(variantNames.bold, variantFonts.bold);
38
+ if (variantFonts.italic)
39
+ resolvedFonts.set(variantNames.italic, variantFonts.italic);
40
+ if (variantFonts.boldItalic)
41
+ resolvedFonts.set(variantNames.boldItalic, variantFonts.boldItalic);
25
42
  const isUnicode = font?.isUnicode ?? false;
26
43
  const reverseEncodingMap = font?.reverseEncodingMap;
27
- this.setAppearanceStream(new PdfTextAppearanceStream({
44
+ this.appearanceStream = new PdfTextAppearanceStream({
28
45
  rect: rect,
29
46
  value: this.value,
30
47
  da: parsed,
@@ -32,9 +49,12 @@ export class PdfTextFormField extends PdfFormField {
32
49
  comb: this.comb,
33
50
  maxLen: this.maxLen,
34
51
  fontResources,
52
+ resolvedFonts,
35
53
  isUnicode,
36
54
  reverseEncodingMap,
37
- }));
55
+ markdown: this._markdownValue,
56
+ fontVariantNames: variantNames,
57
+ });
38
58
  if (options?.makeReadOnly) {
39
59
  this.readOnly = true;
40
60
  if (!this.print)
@@ -36,6 +36,7 @@ export declare class PdfAcroForm<T extends Record<string, string> = Record<strin
36
36
  set defaultResources(resources: PdfDefaultResourcesDictionary | null);
37
37
  get fields(): ReadonlyArray<PdfFormField>;
38
38
  addField(...fields: PdfFormField[]): void;
39
+ private _addWidgetToPage;
39
40
  set fields(newFields: PdfFormField[]);
40
41
  setValues(values: Partial<T>): void;
41
42
  importData(fields: T): void;
@@ -108,13 +108,24 @@ export class PdfAcroForm extends PdfIndirectObject {
108
108
  }
109
109
  for (const field of fields) {
110
110
  fieldsArray.items.push(field.reference);
111
- // Auto-add to the page's Annots array
112
- const page = field.page;
113
- if (page) {
114
- page.annotations.items.push(field.reference);
111
+ this._addWidgetToPage(field);
112
+ // Also register any child widgets (e.g. radio button group kids)
113
+ for (const child of field.children) {
114
+ this._addWidgetToPage(child);
115
115
  }
116
116
  }
117
117
  }
118
+ _addWidgetToPage(field) {
119
+ const page = field.page;
120
+ if (!page)
121
+ return;
122
+ const ref = field.reference;
123
+ const key = ref.key;
124
+ const alreadyPresent = page.annotations.items.some((r) => r instanceof PdfObjectReference && r.key === key);
125
+ if (!alreadyPresent) {
126
+ page.annotations.items.push(ref);
127
+ }
128
+ }
118
129
  set fields(newFields) {
119
130
  this.content.set('Fields', PdfArray.refs(newFields));
120
131
  }
@@ -17,5 +17,6 @@ export declare class PdfXfaData extends PdfIndirectObject<PdfStream> {
17
17
  getFieldValue(name: string): string | null;
18
18
  importData(fields: Record<string, string | undefined>): void;
19
19
  private static updateFieldValue;
20
- private static escapeRegex;
20
+ private static leafName;
21
+ private static cleanSegments;
21
22
  }