modern-pdf-lib 0.15.0 → 0.19.9

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 (95) hide show
  1. package/README.md +106 -7
  2. package/dist/batchOptimize-7U_kD3_j.mjs +392 -0
  3. package/dist/batchOptimize-xo6BXbGZ.cjs +427 -0
  4. package/dist/{bridge-C7U4E7St.mjs → bridge-DTH5LMAK.mjs} +3 -3
  5. package/dist/{bridge-DUcJFVsk.cjs → bridge-DYCQzxF7.cjs} +2 -2
  6. package/dist/browser.cjs +621 -0
  7. package/dist/browser.d.cts +190 -0
  8. package/dist/browser.d.cts.map +1 -0
  9. package/dist/browser.d.mts +190 -0
  10. package/dist/browser.d.mts.map +1 -0
  11. package/dist/browser.mjs +212 -0
  12. package/dist/cli/index.cjs +247 -0
  13. package/dist/cli/index.d.cts +1 -0
  14. package/dist/cli/index.d.mts +1 -0
  15. package/dist/cli/index.mjs +248 -0
  16. package/dist/compressionAnalysis-BBv4BkQP.d.mts +261 -0
  17. package/dist/compressionAnalysis-BBv4BkQP.d.mts.map +1 -0
  18. package/dist/compressionAnalysis-Bw2alOxt.mjs +1490 -0
  19. package/dist/compressionAnalysis-CtJ2X9l2.d.cts +261 -0
  20. package/dist/compressionAnalysis-CtJ2X9l2.d.cts.map +1 -0
  21. package/dist/compressionAnalysis-eXYyDsrh.cjs +1525 -0
  22. package/dist/create.cjs +35 -0
  23. package/dist/create.d.cts +3 -0
  24. package/dist/create.d.mts +3 -0
  25. package/dist/create.mjs +5 -0
  26. package/dist/deduplicateImages-B5lmzL9j.cjs +113 -0
  27. package/dist/deduplicateImages-BX3Zg8Qp.mjs +102 -0
  28. package/dist/{fflateAdapter-DX0VqT5k.mjs → fflateAdapter-CBQpGTlx.mjs} +2 -2
  29. package/dist/{fflateAdapter-AHC_S3cb.cjs → fflateAdapter-LTAeAhaD.cjs} +1 -1
  30. package/dist/fieldAppearance-C8PoLFSc.d.mts +136 -0
  31. package/dist/fieldAppearance-C8PoLFSc.d.mts.map +1 -0
  32. package/dist/fieldAppearance-CdiGFG5e.d.cts +136 -0
  33. package/dist/fieldAppearance-CdiGFG5e.d.cts.map +1 -0
  34. package/dist/fontEmbed-Dsu9fo4U.d.mts +636 -0
  35. package/dist/fontEmbed-Dsu9fo4U.d.mts.map +1 -0
  36. package/dist/fontEmbed-LID6yG6g.d.cts +636 -0
  37. package/dist/fontEmbed-LID6yG6g.d.cts.map +1 -0
  38. package/dist/{fontSubset-pFc8Dueu.cjs → fontSubset-5SLWMmEw.cjs} +1 -1
  39. package/dist/{fontSubset-ZpLoOZ2e.mjs → fontSubset-DWpduoY2.mjs} +2 -2
  40. package/dist/forms.cjs +13 -0
  41. package/dist/forms.d.cts +3 -0
  42. package/dist/forms.d.mts +3 -0
  43. package/dist/forms.mjs +3 -0
  44. package/dist/grayscaleDetect-C2m-eEXR.cjs +96 -0
  45. package/dist/grayscaleDetect-C6kFF3dk.mjs +84 -0
  46. package/dist/imageExtract-B6OvUEp-.mjs +155 -0
  47. package/dist/imageExtract-PxdBvpHj.cjs +166 -0
  48. package/dist/index-BtYOx5wh.d.mts +4904 -0
  49. package/dist/index-BtYOx5wh.d.mts.map +1 -0
  50. package/dist/index-bpktKzCA.d.cts +4904 -0
  51. package/dist/index-bpktKzCA.d.cts.map +1 -0
  52. package/dist/index.cjs +288 -25851
  53. package/dist/index.d.cts +7 -9151
  54. package/dist/index.d.mts +7 -9151
  55. package/dist/index.mjs +17 -25665
  56. package/dist/layout-BZ8tTeAk.mjs +438 -0
  57. package/dist/layout-Inbqegsk.cjs +563 -0
  58. package/dist/{libdeflateWasm-Enus0G1k.cjs → libdeflateWasm-BdiDEJOj.cjs} +2 -2
  59. package/dist/{libdeflateWasm-82loOtIV.mjs → libdeflateWasm-rLppXytE.mjs} +3 -3
  60. package/dist/loader-3u6Tw5T-.mjs +328 -0
  61. package/dist/loader-I4zdkoWc.cjs +393 -0
  62. package/dist/parse.cjs +24 -0
  63. package/dist/parse.d.cts +4 -0
  64. package/dist/parse.d.mts +4 -0
  65. package/dist/parse.mjs +7 -0
  66. package/dist/pdfCatalog-CYy4NXEY.cjs +173 -0
  67. package/dist/pdfCatalog-IImGcMbR.mjs +138 -0
  68. package/dist/pdfDocument-BSiQdNZq.d.cts +4640 -0
  69. package/dist/pdfDocument-BSiQdNZq.d.cts.map +1 -0
  70. package/dist/pdfDocument-DOg240g9.mjs +13685 -0
  71. package/dist/pdfDocument-Duf9LelM.cjs +14110 -0
  72. package/dist/pdfDocument-i6U5fQ91.d.mts +4640 -0
  73. package/dist/pdfDocument-i6U5fQ91.d.mts.map +1 -0
  74. package/dist/pdfForm-9gd40uz9.cjs +1796 -0
  75. package/dist/pdfForm-BiyNtYem.d.mts +905 -0
  76. package/dist/pdfForm-BiyNtYem.d.mts.map +1 -0
  77. package/dist/pdfForm-Cn-cVicP.mjs +1695 -0
  78. package/dist/pdfForm-SOXJ72LW.d.cts +905 -0
  79. package/dist/pdfForm-SOXJ72LW.d.cts.map +1 -0
  80. package/dist/{pdfCatalog-COKoYQ8C.cjs → pdfObjects-1veop1_d.cjs} +2 -172
  81. package/dist/{pdfCatalog-BB2Wnmud.mjs → pdfObjects-uEsWlfzU.mjs} +3 -138
  82. package/dist/{pdfPage-N1K2U3jI.mjs → pdfPage-BacMkrLe.mjs} +3024 -4
  83. package/dist/{pdfPage-DBfdinTR.cjs → pdfPage-CirlQRzJ.cjs} +3148 -104
  84. package/dist/{pngEmbed-gaJ9S2Dk.mjs → pngEmbed-BLj2zi-5.mjs} +3 -3
  85. package/dist/{pngEmbed-10m4CfBU.cjs → pngEmbed-D4X4ZN-3.cjs} +2 -2
  86. package/dist/src-BLWEEbd7.cjs +11852 -0
  87. package/dist/src-x0g7wiRq.mjs +11103 -0
  88. package/dist/streamDecode-Bs0_MT_Q.cjs +4607 -0
  89. package/dist/streamDecode-CWN-nfPJ.mjs +4596 -0
  90. package/package.json +33 -1
  91. package/dist/index.d.cts.map +0 -1
  92. package/dist/index.d.mts.map +0 -1
  93. package/dist/loader-1VJXLlMZ.mjs +0 -164
  94. package/dist/loader-CKlBOHma.cjs +0 -166
  95. package/dist/rolldown-runtime-95iHPtFO.mjs +0 -18
@@ -0,0 +1,1796 @@
1
+ const require_pdfObjects = require('./pdfObjects-1veop1_d.cjs');
2
+
3
+ //#region src/form/pdfField.ts
4
+ /**
5
+ * @module form/pdfField
6
+ *
7
+ * Base class for all PDF form fields (AcroForm fields).
8
+ *
9
+ * Each concrete field type extends this class and implements
10
+ * `getValue()`, `setValue()`, and `generateAppearance()`.
11
+ *
12
+ * Reference: PDF 1.7 spec, SS12.7 (Interactive Forms).
13
+ */
14
+ /** Common field flags (/Ff) — bit positions (0-indexed). */
15
+ const FieldFlags = {
16
+ ReadOnly: 1,
17
+ Required: 2,
18
+ NoExport: 4,
19
+ Multiline: 4096,
20
+ Password: 8192,
21
+ DoNotScroll: 1 << 20,
22
+ RichText: 1 << 25,
23
+ NoToggleToOff: 16384,
24
+ Radio: 32768,
25
+ Pushbutton: 65536,
26
+ RadiosInUnison: 1 << 25,
27
+ Combo: 1 << 17,
28
+ Edit: 1 << 18,
29
+ Sort: 1 << 19,
30
+ MultiSelect: 1 << 21
31
+ };
32
+ /**
33
+ * Resolve an object that may be a PdfRef using a resolver function.
34
+ * If it is not a ref, return as-is.
35
+ */
36
+ function resolveIfRef(obj, resolver) {
37
+ if (obj === void 0) return void 0;
38
+ if (obj.kind === "ref") return resolver(obj);
39
+ return obj;
40
+ }
41
+ /**
42
+ * Extract a numeric value from a PdfObject.
43
+ */
44
+ function numVal(obj) {
45
+ if (obj !== void 0 && obj.kind === "number") return obj.value;
46
+ }
47
+ /**
48
+ * Extract a string value from a PdfObject.
49
+ */
50
+ function strVal(obj) {
51
+ if (obj !== void 0 && obj.kind === "string") return obj.value;
52
+ }
53
+ /**
54
+ * Extract a name value (without leading `/`) from a PdfObject.
55
+ */
56
+ function nameVal(obj) {
57
+ if (obj !== void 0 && obj.kind === "name") {
58
+ const val = obj.value;
59
+ return val.startsWith("/") ? val.slice(1) : val;
60
+ }
61
+ }
62
+ /**
63
+ * Abstract base class for all AcroForm field types.
64
+ *
65
+ * Each field holds a reference to the underlying field dictionary
66
+ * (which may be a merged field+widget dictionary in simple forms)
67
+ * and an optional separate widget annotation dictionary.
68
+ */
69
+ var PdfField = class {
70
+ /** The fully-qualified field name. */
71
+ name;
72
+ /**
73
+ * The underlying field dictionary (may contain both field and widget
74
+ * entries for simple one-widget fields).
75
+ */
76
+ dict;
77
+ /**
78
+ * The widget annotation dictionary. For merged field+widget dicts,
79
+ * this is the same object as `dict`.
80
+ */
81
+ widgetDict;
82
+ /** Parent field dictionary chain for building full names. */
83
+ parentNames;
84
+ constructor(name, dict, widgetDict, parentNames = []) {
85
+ this.name = name;
86
+ this.dict = dict;
87
+ this.widgetDict = widgetDict;
88
+ this.parentNames = parentNames;
89
+ }
90
+ /** Get the partial field name (/T entry). */
91
+ getName() {
92
+ return this.name;
93
+ }
94
+ /**
95
+ * Get the fully qualified field name (Parent.Child.Name format).
96
+ * Per PDF spec SS12.7.3.2, the full name is formed by concatenating
97
+ * ancestor /T values with periods.
98
+ */
99
+ getFullName() {
100
+ if (this.parentNames.length === 0) return this.name;
101
+ return [...this.parentNames, this.name].join(".");
102
+ }
103
+ /** Return the underlying field dictionary (for internal use by PdfForm). */
104
+ getDict() {
105
+ return this.dict;
106
+ }
107
+ /** Get the raw /Ff (field flags) integer value. */
108
+ getFieldFlags() {
109
+ return numVal(this.dict.get("/Ff")) ?? 0;
110
+ }
111
+ /** Set the raw /Ff (field flags) integer value. */
112
+ setFieldFlags(flags) {
113
+ this.dict.set("/Ff", require_pdfObjects.PdfNumber.of(flags));
114
+ }
115
+ /** Check if a specific flag bit is set. */
116
+ hasFlag(flag) {
117
+ return (this.getFieldFlags() & flag) !== 0;
118
+ }
119
+ /** Set or clear a specific flag bit. */
120
+ setFlag(flag, on) {
121
+ const current = this.getFieldFlags();
122
+ if (on) this.setFieldFlags(current | flag);
123
+ else this.setFieldFlags(current & ~flag);
124
+ }
125
+ /** Whether the field is read-only. */
126
+ isReadOnly() {
127
+ return this.hasFlag(FieldFlags.ReadOnly);
128
+ }
129
+ /** Set the read-only flag. */
130
+ setReadOnly(readOnly) {
131
+ this.setFlag(FieldFlags.ReadOnly, readOnly);
132
+ }
133
+ /** Whether the field is required. */
134
+ isRequired() {
135
+ return this.hasFlag(FieldFlags.Required);
136
+ }
137
+ /** Set the required flag. */
138
+ setRequired(required) {
139
+ this.setFlag(FieldFlags.Required, required);
140
+ }
141
+ /** Whether the field should not be exported. */
142
+ isNoExport() {
143
+ return this.hasFlag(FieldFlags.NoExport);
144
+ }
145
+ /** Whether the field is exported (inverse of NoExport flag). */
146
+ isExported() {
147
+ return !this.hasFlag(FieldFlags.NoExport);
148
+ }
149
+ /** Enable exporting this field (clear the NoExport flag). */
150
+ enableExporting() {
151
+ this.setFlag(FieldFlags.NoExport, false);
152
+ }
153
+ /** Disable exporting this field (set the NoExport flag). */
154
+ disableExporting() {
155
+ this.setFlag(FieldFlags.NoExport, true);
156
+ }
157
+ /**
158
+ * Get the field's widget rectangle as `[x1, y1, x2, y2]`.
159
+ * The /Rect entry comes from the widget annotation dictionary.
160
+ */
161
+ getRect() {
162
+ const rectObj = this.widgetDict.get("/Rect");
163
+ if (rectObj !== void 0 && rectObj.kind === "array") {
164
+ const arr = rectObj;
165
+ return [
166
+ numVal(arr.items[0]) ?? 0,
167
+ numVal(arr.items[1]) ?? 0,
168
+ numVal(arr.items[2]) ?? 0,
169
+ numVal(arr.items[3]) ?? 0
170
+ ];
171
+ }
172
+ return [
173
+ 0,
174
+ 0,
175
+ 0,
176
+ 0
177
+ ];
178
+ }
179
+ /**
180
+ * Add this field's widget annotation to a page.
181
+ *
182
+ * Ensures the widget dict has `/Type /Annot` and `/Subtype /Widget`,
183
+ * then adds it to the page's annotation list so it appears in the
184
+ * rendered PDF.
185
+ *
186
+ * @param page A page that implements {@link WidgetAnnotationHost}.
187
+ */
188
+ addToPage(page) {
189
+ if (!this.widgetDict.has("/Type")) this.widgetDict.set("/Type", require_pdfObjects.PdfName.of("Annot"));
190
+ if (!this.widgetDict.has("/Subtype")) this.widgetDict.set("/Subtype", require_pdfObjects.PdfName.of("Widget"));
191
+ page.addWidgetAnnotation(this.widgetDict);
192
+ }
193
+ /**
194
+ * Get the underlying widget annotation dictionary.
195
+ * @internal
196
+ */
197
+ getWidgetDict() {
198
+ return this.widgetDict;
199
+ }
200
+ };
201
+
202
+ //#endregion
203
+ //#region src/form/fieldAppearance.ts
204
+ /**
205
+ * @module form/fieldAppearance
206
+ *
207
+ * Generates PDF appearance streams (/AP /N) for AcroForm fields.
208
+ *
209
+ * Each generator creates a PdfStream whose content is a valid PDF
210
+ * content stream that visually renders the field's current value.
211
+ *
212
+ * Reference: PDF 1.7 spec, SS12.5.5 (Appearance Streams),
213
+ * SS12.7.3.3 (Variable Text).
214
+ */
215
+ /** Format a number for PDF content stream output. */
216
+ function n$2(value) {
217
+ if (Number.isInteger(value)) return value.toString();
218
+ const s = value.toFixed(6).replace(/\.?0+$/, "");
219
+ return s === "-0" ? "0" : s;
220
+ }
221
+ /** Escape a string for use in a PDF literal string. */
222
+ function escapePdf(text) {
223
+ return text.replace(/\\/g, "\\\\").replace(/\(/g, "\\(").replace(/\)/g, "\\)").replace(/\r/g, "\\r").replace(/\n/g, "\\n");
224
+ }
225
+ /**
226
+ * Generate the appearance stream for a text field.
227
+ *
228
+ * The stream renders the text value within the widget rectangle,
229
+ * using Tf/Td/Tj operators. Handles single-line and multiline,
230
+ * alignment (quadding), and auto font-size calculation.
231
+ */
232
+ function generateTextAppearance(options) {
233
+ const { value, rect, fontName = "Helv", fontSize: requestedSize = 0, alignment = 0, multiline = false, borderWidth = 1 } = options;
234
+ const width = rect[2] - rect[0];
235
+ const height = rect[3] - rect[1];
236
+ const padding = borderWidth + 1;
237
+ let fontSize = requestedSize;
238
+ if (fontSize <= 0) if (multiline) fontSize = 10;
239
+ else fontSize = Math.min(Math.max(height - 2 * padding, 4), 20);
240
+ let ops = "";
241
+ ops += `/Tx BMC\n`;
242
+ ops += `q\n`;
243
+ ops += `${n$2(padding)} ${n$2(padding)} ${n$2(width - 2 * padding)} ${n$2(height - 2 * padding)} re\n`;
244
+ ops += `W\n`;
245
+ ops += `n\n`;
246
+ ops += `BT\n`;
247
+ ops += `/${fontName} ${n$2(fontSize)} Tf\n`;
248
+ ops += `0 g\n`;
249
+ if (multiline) {
250
+ const lines = value.split("\n");
251
+ const lineHeight = fontSize * 1.2;
252
+ const startY = height - padding - fontSize;
253
+ for (let i = 0; i < lines.length; i++) {
254
+ const line = lines[i] ?? "";
255
+ const tx = computeAlignmentOffset(line, fontSize, width - 2 * padding, alignment);
256
+ const ty = startY - i * lineHeight;
257
+ if (ty < padding) break;
258
+ ops += `${n$2(tx + padding)} ${n$2(ty)} Td\n`;
259
+ ops += `(${escapePdf(line)}) Tj\n`;
260
+ if (i < lines.length - 1) ops += `${n$2(-(tx + padding))} ${n$2(-ty)} Td\n`;
261
+ }
262
+ } else {
263
+ const tx = computeAlignmentOffset(value, fontSize, width - 2 * padding, alignment);
264
+ const ty = (height - fontSize) / 2;
265
+ ops += `${n$2(tx + padding)} ${n$2(ty)} Td\n`;
266
+ ops += `(${escapePdf(value)}) Tj\n`;
267
+ }
268
+ ops += `ET\n`;
269
+ ops += `Q\n`;
270
+ ops += `EMC\n`;
271
+ return buildAppearanceStream(ops, width, height);
272
+ }
273
+ /**
274
+ * Compute horizontal text offset for alignment.
275
+ * Rough approximation: assume average char width = fontSize * 0.5.
276
+ */
277
+ function computeAlignmentOffset(text, fontSize, availableWidth, alignment) {
278
+ const textWidth = text.length * fontSize * .5;
279
+ switch (alignment) {
280
+ case 1: return Math.max(0, (availableWidth - textWidth) / 2);
281
+ case 2: return Math.max(0, availableWidth - textWidth);
282
+ default: return 0;
283
+ }
284
+ }
285
+ /**
286
+ * Generate the appearance stream for a checkbox — checked state.
287
+ *
288
+ * Renders a checkmark (a simple cross/tick path) inside the widget
289
+ * rectangle when checked, or an empty box when unchecked.
290
+ */
291
+ function generateCheckboxAppearance(options) {
292
+ const { checked, rect } = options;
293
+ const width = rect[2] - rect[0];
294
+ const height = rect[3] - rect[1];
295
+ let ops = "";
296
+ if (checked) {
297
+ const margin = Math.min(width, height) * .15;
298
+ const x1 = margin;
299
+ const y1 = height * .5;
300
+ const x2 = width * .4;
301
+ const y2 = margin;
302
+ const x3 = width - margin;
303
+ const y3 = height - margin;
304
+ ops += `q\n`;
305
+ ops += `${n$2(2)} w\n`;
306
+ ops += `0 0 0 RG\n`;
307
+ ops += `${n$2(x1)} ${n$2(y1)} m\n`;
308
+ ops += `${n$2(x2)} ${n$2(y2)} l\n`;
309
+ ops += `${n$2(x3)} ${n$2(y3)} l\n`;
310
+ ops += `S\n`;
311
+ ops += `Q\n`;
312
+ }
313
+ return buildAppearanceStream(ops, width, height);
314
+ }
315
+ /**
316
+ * Generate the appearance stream for a radio button option.
317
+ *
318
+ * Selected: filled circle inside the widget.
319
+ * Unselected: empty circle (border only).
320
+ */
321
+ function generateRadioAppearance(options) {
322
+ const { selected, rect } = options;
323
+ const width = rect[2] - rect[0];
324
+ const height = rect[3] - rect[1];
325
+ const cx = width / 2;
326
+ const cy = height / 2;
327
+ const outerRadius = Math.min(cx, cy) - 1;
328
+ let ops = "";
329
+ ops += `q\n`;
330
+ ops += `0 0 0 RG\n`;
331
+ ops += `0.5 w\n`;
332
+ ops += circlePath(cx, cy, outerRadius);
333
+ ops += `S\n`;
334
+ ops += `Q\n`;
335
+ if (selected) {
336
+ const innerRadius = outerRadius * .5;
337
+ ops += `q\n`;
338
+ ops += `0 0 0 rg\n`;
339
+ ops += circlePath(cx, cy, innerRadius);
340
+ ops += `f\n`;
341
+ ops += `Q\n`;
342
+ }
343
+ return buildAppearanceStream(ops, width, height);
344
+ }
345
+ /**
346
+ * Generate the appearance stream for a dropdown (combo box).
347
+ * Renders the selected value text, similar to a text field.
348
+ */
349
+ function generateDropdownAppearance(options) {
350
+ return generateTextAppearance({
351
+ value: options.value,
352
+ rect: options.rect,
353
+ fontName: options.fontName,
354
+ fontSize: options.fontSize,
355
+ alignment: 0,
356
+ multiline: false
357
+ });
358
+ }
359
+ /**
360
+ * Generate the appearance stream for a listbox.
361
+ * Renders visible options with highlighting for selected items.
362
+ */
363
+ function generateListboxAppearance(options) {
364
+ const { options: items, selected, rect, fontName = "Helv", fontSize = 10 } = options;
365
+ const width = rect[2] - rect[0];
366
+ const height = rect[3] - rect[1];
367
+ const lineHeight = fontSize * 1.4;
368
+ const padding = 2;
369
+ const selectedSet = new Set(selected);
370
+ let ops = "";
371
+ ops += `q\n`;
372
+ ops += `${n$2(0)} ${n$2(0)} ${n$2(width)} ${n$2(height)} re\n`;
373
+ ops += `W\n`;
374
+ ops += `n\n`;
375
+ const visibleItems = Math.floor(height / lineHeight);
376
+ const renderCount = Math.min(items.length, visibleItems);
377
+ for (let i = 0; i < renderCount; i++) {
378
+ const item = items[i] ?? "";
379
+ const y = height - (i + 1) * lineHeight;
380
+ if (selectedSet.has(item)) {
381
+ ops += `0 0 0.5 rg\n`;
382
+ ops += `${n$2(0)} ${n$2(y)} ${n$2(width)} ${n$2(lineHeight)} re\n`;
383
+ ops += `f\n`;
384
+ ops += `1 1 1 rg\n`;
385
+ } else ops += `0 0 0 rg\n`;
386
+ ops += `BT\n`;
387
+ ops += `/${fontName} ${n$2(fontSize)} Tf\n`;
388
+ ops += `${n$2(padding)} ${n$2(y + lineHeight * .25)} Td\n`;
389
+ ops += `(${escapePdf(item)}) Tj\n`;
390
+ ops += `ET\n`;
391
+ }
392
+ ops += `Q\n`;
393
+ return buildAppearanceStream(ops, width, height);
394
+ }
395
+ /**
396
+ * Generate the appearance stream for a pushbutton.
397
+ * Renders a 3D-ish raised button with centered caption text.
398
+ */
399
+ function generateButtonAppearance(options) {
400
+ const { caption, rect, fontName = "Helv", fontSize: requestedSize = 0 } = options;
401
+ const width = rect[2] - rect[0];
402
+ const height = rect[3] - rect[1];
403
+ let fontSize = requestedSize;
404
+ if (fontSize <= 0) fontSize = Math.min(Math.max(height - 6, 4), 16);
405
+ let ops = "";
406
+ ops += `q\n`;
407
+ ops += `0.75 g\n`;
408
+ ops += `${n$2(0)} ${n$2(0)} ${n$2(width)} ${n$2(height)} re\n`;
409
+ ops += `f\n`;
410
+ ops += `Q\n`;
411
+ const tx = (width - caption.length * fontSize * .5) / 2;
412
+ const ty = (height - fontSize) / 2;
413
+ ops += `BT\n`;
414
+ ops += `/${fontName} ${n$2(fontSize)} Tf\n`;
415
+ ops += `0 g\n`;
416
+ ops += `${n$2(tx)} ${n$2(ty)} Td\n`;
417
+ ops += `(${escapePdf(caption)}) Tj\n`;
418
+ ops += `ET\n`;
419
+ return buildAppearanceStream(ops, width, height);
420
+ }
421
+ /**
422
+ * Generate the appearance stream for a signature field.
423
+ *
424
+ * Unsigned: dashed border rectangle.
425
+ * Signed: "Signed" text with a line through it.
426
+ */
427
+ function generateSignatureAppearance(options) {
428
+ const { signed, rect } = options;
429
+ const width = rect[2] - rect[0];
430
+ const height = rect[3] - rect[1];
431
+ let ops = "";
432
+ if (signed) {
433
+ ops += `q\n`;
434
+ ops += `0.8 g\n`;
435
+ ops += `${n$2(0)} ${n$2(0)} ${n$2(width)} ${n$2(height)} re\n`;
436
+ ops += `f\n`;
437
+ ops += `Q\n`;
438
+ ops += `BT\n`;
439
+ ops += `/Helv 10 Tf\n`;
440
+ ops += `0 g\n`;
441
+ const tx = (width - 30) / 2;
442
+ const ty = (height - 10) / 2;
443
+ ops += `${n$2(tx)} ${n$2(ty)} Td\n`;
444
+ ops += `(Signed) Tj\n`;
445
+ ops += `ET\n`;
446
+ } else {
447
+ ops += `q\n`;
448
+ ops += `[3 3] 0 d\n`;
449
+ ops += `0.5 G\n`;
450
+ ops += `0.5 w\n`;
451
+ ops += `${n$2(1)} ${n$2(1)} ${n$2(width - 2)} ${n$2(height - 2)} re\n`;
452
+ ops += `S\n`;
453
+ ops += `Q\n`;
454
+ }
455
+ return buildAppearanceStream(ops, width, height);
456
+ }
457
+ /**
458
+ * Build a PdfStream from content stream operators with proper BBox.
459
+ */
460
+ function buildAppearanceStream(operators, width, height) {
461
+ const dict = new require_pdfObjects.PdfDict();
462
+ dict.set("/Type", require_pdfObjects.PdfName.of("XObject"));
463
+ dict.set("/Subtype", require_pdfObjects.PdfName.of("Form"));
464
+ dict.set("/BBox", require_pdfObjects.PdfArray.fromNumbers([
465
+ 0,
466
+ 0,
467
+ width,
468
+ height
469
+ ]));
470
+ const resources = new require_pdfObjects.PdfDict();
471
+ const fontDict = new require_pdfObjects.PdfDict();
472
+ const helvetica = new require_pdfObjects.PdfDict();
473
+ helvetica.set("/Type", require_pdfObjects.PdfName.of("Font"));
474
+ helvetica.set("/Subtype", require_pdfObjects.PdfName.of("Type1"));
475
+ helvetica.set("/BaseFont", require_pdfObjects.PdfName.of("Helvetica"));
476
+ fontDict.set("/Helv", helvetica);
477
+ resources.set("/Font", fontDict);
478
+ dict.set("/Resources", resources);
479
+ return require_pdfObjects.PdfStream.fromString(operators, dict);
480
+ }
481
+ /**
482
+ * Approximate circle path using 4 cubic Bezier curves.
483
+ */
484
+ function circlePath(cx, cy, radius) {
485
+ const kappa = .5522847498;
486
+ const ox = radius * kappa;
487
+ const oy = radius * kappa;
488
+ let ops = "";
489
+ ops += `${n$2(cx)} ${n$2(cy + radius)} m\n`;
490
+ ops += `${n$2(cx + ox)} ${n$2(cy + radius)} ${n$2(cx + radius)} ${n$2(cy + oy)} ${n$2(cx + radius)} ${n$2(cy)} c\n`;
491
+ ops += `${n$2(cx + radius)} ${n$2(cy - oy)} ${n$2(cx + ox)} ${n$2(cy - radius)} ${n$2(cx)} ${n$2(cy - radius)} c\n`;
492
+ ops += `${n$2(cx - ox)} ${n$2(cy - radius)} ${n$2(cx - radius)} ${n$2(cy - oy)} ${n$2(cx - radius)} ${n$2(cy)} c\n`;
493
+ ops += `${n$2(cx - radius)} ${n$2(cy + oy)} ${n$2(cx - ox)} ${n$2(cy + radius)} ${n$2(cx)} ${n$2(cy + radius)} c\n`;
494
+ return ops;
495
+ }
496
+
497
+ //#endregion
498
+ //#region src/form/fields/textField.ts
499
+ /**
500
+ * @module form/fields/textField
501
+ *
502
+ * PDF text form field (/FT /Tx).
503
+ *
504
+ * Reference: PDF 1.7 spec, SS12.7.4.3 (Text Fields).
505
+ */
506
+ /** Format a number for PDF content stream output. */
507
+ function n$1(value) {
508
+ if (Number.isInteger(value)) return value.toString();
509
+ const s = value.toFixed(6).replace(/\.?0+$/, "");
510
+ return s === "-0" ? "0" : s;
511
+ }
512
+ /**
513
+ * A PDF text form field (/FT /Tx).
514
+ *
515
+ * Stores a string value and supports properties like alignment,
516
+ * multiline mode, password masking, and maximum length.
517
+ */
518
+ var PdfTextField = class extends PdfField {
519
+ fieldType = "text";
520
+ /** Get the text value of this field. */
521
+ getText() {
522
+ return strVal(this.dict.get("/V")) ?? "";
523
+ }
524
+ /**
525
+ * Set the text value of this field.
526
+ * Also updates /V and removes /AP to force regeneration.
527
+ */
528
+ setText(value) {
529
+ this.dict.set("/V", require_pdfObjects.PdfString.literal(value));
530
+ this.widgetDict.delete("/AP");
531
+ }
532
+ /** Alias for getText(). */
533
+ getValue() {
534
+ return this.getText();
535
+ }
536
+ /** Alias for setText(). */
537
+ setValue(value) {
538
+ this.setText(typeof value === "string" ? value : String(value));
539
+ }
540
+ /**
541
+ * Get the font size from the /DA (default appearance) string.
542
+ * Returns 0 if the font size is not specified or is auto.
543
+ */
544
+ getFontSize() {
545
+ const da = strVal(this.dict.get("/DA"));
546
+ if (da === void 0) return 0;
547
+ const match = da.match(/\/(\w+)\s+([\d.]+)\s+Tf/);
548
+ if (match?.[2] !== void 0) return parseFloat(match[2]);
549
+ return 0;
550
+ }
551
+ /**
552
+ * Set the font size in the /DA string.
553
+ * Creates or updates the /DA entry.
554
+ */
555
+ setFontSize(size) {
556
+ const fontName = this.getFontName();
557
+ this.dict.set("/DA", require_pdfObjects.PdfString.literal(`/${fontName} ${size} Tf 0 g`));
558
+ this.widgetDict.delete("/AP");
559
+ }
560
+ /**
561
+ * Get the font name from the /DA string.
562
+ * Returns "Helv" (Helvetica) as default.
563
+ */
564
+ getFontName() {
565
+ const da = strVal(this.dict.get("/DA"));
566
+ if (da === void 0) return "Helv";
567
+ return da.match(/\/(\w+)\s+[\d.]+\s+Tf/)?.[1] ?? "Helv";
568
+ }
569
+ /**
570
+ * Get the text alignment.
571
+ * /Q: 0 = left, 1 = center, 2 = right.
572
+ */
573
+ getAlignment() {
574
+ switch (numVal(this.dict.get("/Q"))) {
575
+ case 1: return "center";
576
+ case 2: return "right";
577
+ default: return "left";
578
+ }
579
+ }
580
+ /** Set the text alignment. */
581
+ setAlignment(align) {
582
+ const q = align === "center" ? 1 : align === "right" ? 2 : 0;
583
+ this.dict.set("/Q", require_pdfObjects.PdfNumber.of(q));
584
+ this.widgetDict.delete("/AP");
585
+ }
586
+ /** Whether this is a multiline text field. */
587
+ isMultiline() {
588
+ return this.hasFlag(FieldFlags.Multiline);
589
+ }
590
+ /** Set the multiline flag. */
591
+ setMultiline(multiline) {
592
+ this.setFlag(FieldFlags.Multiline, multiline);
593
+ }
594
+ /** Whether this is a password field. */
595
+ isPassword() {
596
+ return this.hasFlag(FieldFlags.Password);
597
+ }
598
+ /** Get the maximum length, or undefined if no limit. */
599
+ getMaxLength() {
600
+ return numVal(this.dict.get("/MaxLen"));
601
+ }
602
+ /** Set the maximum length. */
603
+ setMaxLength(maxLength) {
604
+ this.dict.set("/MaxLen", require_pdfObjects.PdfNumber.of(maxLength));
605
+ }
606
+ /**
607
+ * Set an image on this text field.
608
+ *
609
+ * Creates an appearance stream that paints the image XObject scaled
610
+ * to fit the widget rectangle. This replaces the text appearance.
611
+ *
612
+ * @param imageRef An object with `name` (resource name) and `ref` (PdfRef)
613
+ * pointing to the image XObject, plus `width` and `height`.
614
+ */
615
+ setImage(imageRef) {
616
+ const rect = this.getRect();
617
+ const fieldW = Math.abs(rect[2] - rect[0]);
618
+ const fieldH = Math.abs(rect[3] - rect[1]);
619
+ const scaleX = fieldW / imageRef.width;
620
+ const scaleY = fieldH / imageRef.height;
621
+ const scale = Math.min(scaleX, scaleY);
622
+ const drawW = imageRef.width * scale;
623
+ const drawH = imageRef.height * scale;
624
+ const offsetX = (fieldW - drawW) / 2;
625
+ const offsetY = (fieldH - drawH) / 2;
626
+ const ops = `q\n${n$1(drawW)} 0 0 ${n$1(drawH)} ${n$1(offsetX)} ${n$1(offsetY)} cm\n/${imageRef.name} Do\nQ\n`;
627
+ const apDict = new require_pdfObjects.PdfDict();
628
+ apDict.set("/Type", require_pdfObjects.PdfName.of("XObject"));
629
+ apDict.set("/Subtype", require_pdfObjects.PdfName.of("Form"));
630
+ apDict.set("/BBox", require_pdfObjects.PdfArray.fromNumbers([
631
+ 0,
632
+ 0,
633
+ fieldW,
634
+ fieldH
635
+ ]));
636
+ const resources = new require_pdfObjects.PdfDict();
637
+ const xObjectDict = new require_pdfObjects.PdfDict();
638
+ xObjectDict.set(`/${imageRef.name}`, imageRef.ref);
639
+ resources.set("/XObject", xObjectDict);
640
+ apDict.set("/Resources", resources);
641
+ const stream = require_pdfObjects.PdfStream.fromString(ops, apDict);
642
+ const apWrapper = new require_pdfObjects.PdfDict();
643
+ apWrapper.set("/N", stream);
644
+ this.widgetDict.set("/AP", apWrapper);
645
+ }
646
+ /** Generate the appearance stream for this text field. */
647
+ generateAppearance() {
648
+ return generateTextAppearance({
649
+ value: this.getText(),
650
+ rect: this.getRect(),
651
+ fontName: this.getFontName(),
652
+ fontSize: this.getFontSize(),
653
+ alignment: {
654
+ left: 0,
655
+ center: 1,
656
+ right: 2
657
+ }[this.getAlignment()],
658
+ multiline: this.isMultiline()
659
+ });
660
+ }
661
+ };
662
+
663
+ //#endregion
664
+ //#region src/form/fields/checkboxField.ts
665
+ /**
666
+ * @module form/fields/checkboxField
667
+ *
668
+ * PDF checkbox form field (/FT /Btn without Radio or Pushbutton flags).
669
+ *
670
+ * Reference: PDF 1.7 spec, SS12.7.4.2.1 (Check Boxes).
671
+ */
672
+ /**
673
+ * A PDF checkbox form field (/FT /Btn).
674
+ *
675
+ * The value is either the "on" name (typically "Yes") or "/Off".
676
+ * The /AS (appearance state) entry controls which appearance is shown.
677
+ */
678
+ var PdfCheckboxField = class extends PdfField {
679
+ fieldType = "checkbox";
680
+ /**
681
+ * Check whether the checkbox is currently checked.
682
+ *
683
+ * The checkbox is checked when /V or /AS is not "/Off".
684
+ */
685
+ isChecked() {
686
+ const v = nameVal(this.dict.get("/V"));
687
+ if (v !== void 0) return v !== "Off";
688
+ const as = nameVal(this.widgetDict.get("/AS"));
689
+ return as !== void 0 && as !== "Off";
690
+ }
691
+ /** Check the checkbox (set to the "on" value). */
692
+ check() {
693
+ const onValue = this.getOnValue();
694
+ this.dict.set("/V", require_pdfObjects.PdfName.of(onValue));
695
+ this.widgetDict.set("/AS", require_pdfObjects.PdfName.of(onValue));
696
+ this.widgetDict.delete("/AP");
697
+ }
698
+ /** Uncheck the checkbox (set to /Off). */
699
+ uncheck() {
700
+ this.dict.set("/V", require_pdfObjects.PdfName.of("Off"));
701
+ this.widgetDict.set("/AS", require_pdfObjects.PdfName.of("Off"));
702
+ this.widgetDict.delete("/AP");
703
+ }
704
+ /** Toggle the checkbox. */
705
+ toggle() {
706
+ if (this.isChecked()) this.uncheck();
707
+ else this.check();
708
+ }
709
+ /**
710
+ * Get the "on" value name for this checkbox.
711
+ *
712
+ * Examines the /AP /N dictionary for a key that is not "/Off".
713
+ * Falls back to "Yes" if no appearance dictionary is found.
714
+ */
715
+ getOnValue() {
716
+ const ap = this.widgetDict.get("/AP");
717
+ if (ap !== void 0 && ap.kind === "dict") {
718
+ const nObj = ap.get("/N");
719
+ if (nObj !== void 0 && nObj.kind === "dict") {
720
+ const nDict = nObj;
721
+ for (const [key] of nDict) {
722
+ const cleanKey = key.startsWith("/") ? key.slice(1) : key;
723
+ if (cleanKey !== "Off") return cleanKey;
724
+ }
725
+ }
726
+ }
727
+ const v = nameVal(this.dict.get("/V"));
728
+ if (v !== void 0 && v !== "Off") return v;
729
+ return "Yes";
730
+ }
731
+ /** Get the value: "Yes"/"Off" as boolean for convenience. */
732
+ getValue() {
733
+ return this.isChecked();
734
+ }
735
+ /** Set the value as boolean. */
736
+ setValue(value) {
737
+ if (typeof value === "boolean") if (value) this.check();
738
+ else this.uncheck();
739
+ else {
740
+ const str = typeof value === "string" ? value : String(value);
741
+ if (str === "Off" || str === "false" || str === "0" || str === "") this.uncheck();
742
+ else this.check();
743
+ }
744
+ }
745
+ /** Generate the appearance stream for this checkbox. */
746
+ generateAppearance() {
747
+ return generateCheckboxAppearance({
748
+ checked: this.isChecked(),
749
+ rect: this.getRect()
750
+ });
751
+ }
752
+ };
753
+
754
+ //#endregion
755
+ //#region src/form/fields/radioGroup.ts
756
+ /**
757
+ * @module form/fields/radioGroup
758
+ *
759
+ * PDF radio button group (/FT /Btn with Radio flag set).
760
+ *
761
+ * A radio group is a single field with multiple widget annotations
762
+ * (one per option). The /V entry on the field indicates which option
763
+ * is selected.
764
+ *
765
+ * Reference: PDF 1.7 spec, SS12.7.4.2.2 (Radio Buttons).
766
+ */
767
+ /**
768
+ * A PDF radio button group (/FT /Btn with Radio flag).
769
+ *
770
+ * Multiple widget annotations represent the individual options.
771
+ * The field's /V value is the name of the selected option.
772
+ */
773
+ var PdfRadioGroup = class extends PdfField {
774
+ fieldType = "radio";
775
+ /** The individual widget annotation dictionaries. */
776
+ widgets;
777
+ constructor(name, dict, widgetDict, parentNames = [], widgets = []) {
778
+ super(name, dict, widgetDict, parentNames);
779
+ this.widgets = widgets.length > 0 ? widgets : [widgetDict];
780
+ }
781
+ /**
782
+ * Add all radio button widgets to a page.
783
+ *
784
+ * Unlike other field types that have a single widget, a radio group
785
+ * has multiple widget annotations (one per option). This override
786
+ * adds all of them.
787
+ */
788
+ addToPage(page) {
789
+ for (const widget of this.widgets) {
790
+ if (!widget.has("/Type")) widget.set("/Type", require_pdfObjects.PdfName.of("Annot"));
791
+ if (!widget.has("/Subtype")) widget.set("/Subtype", require_pdfObjects.PdfName.of("Widget"));
792
+ page.addWidgetAnnotation(widget);
793
+ }
794
+ }
795
+ /**
796
+ * Get the currently selected option name.
797
+ * Returns undefined if no option is selected.
798
+ */
799
+ getSelected() {
800
+ const v = nameVal(this.dict.get("/V"));
801
+ if (v !== void 0 && v !== "Off") return v;
802
+ }
803
+ /**
804
+ * Select an option by its name.
805
+ *
806
+ * Sets /V on the field and updates /AS on each widget to
807
+ * show the correct appearance state.
808
+ */
809
+ select(optionName) {
810
+ this.dict.set("/V", require_pdfObjects.PdfName.of(optionName));
811
+ for (const widget of this.widgets) {
812
+ if (this.getWidgetOptionName(widget) === optionName) widget.set("/AS", require_pdfObjects.PdfName.of(optionName));
813
+ else widget.set("/AS", require_pdfObjects.PdfName.of("Off"));
814
+ widget.delete("/AP");
815
+ }
816
+ }
817
+ /**
818
+ * Get the list of option names available in this radio group.
819
+ * Derived from the /AP /N dictionaries of each widget.
820
+ */
821
+ getOptions() {
822
+ const options = [];
823
+ for (const widget of this.widgets) {
824
+ const optName = this.getWidgetOptionName(widget);
825
+ if (optName !== void 0) options.push(optName);
826
+ }
827
+ return options;
828
+ }
829
+ /** Get the widget annotation dictionaries. */
830
+ getWidgets() {
831
+ return [...this.widgets];
832
+ }
833
+ /** Get the value: the selected option name or undefined. */
834
+ getValue() {
835
+ return this.getSelected() ?? "";
836
+ }
837
+ /** Set the value: select the named option. */
838
+ setValue(value) {
839
+ const str = typeof value === "string" ? value : String(value);
840
+ this.select(str);
841
+ }
842
+ /**
843
+ * Get the option name for a widget annotation.
844
+ * Looks in the /AP /N dictionary for a key that is not "Off".
845
+ */
846
+ getWidgetOptionName(widget) {
847
+ const ap = widget.get("/AP");
848
+ if (ap !== void 0 && ap.kind === "dict") {
849
+ const nObj = ap.get("/N");
850
+ if (nObj !== void 0 && nObj.kind === "dict") {
851
+ const nDict = nObj;
852
+ for (const [key] of nDict) {
853
+ const cleanKey = key.startsWith("/") ? key.slice(1) : key;
854
+ if (cleanKey !== "Off") return cleanKey;
855
+ }
856
+ }
857
+ }
858
+ }
859
+ /**
860
+ * Generate the appearance stream for the first widget.
861
+ * For full appearance generation, use generateAppearanceForWidget().
862
+ */
863
+ generateAppearance() {
864
+ const selected = this.getSelected();
865
+ const firstWidget = this.widgets[0] ?? this.widgetDict;
866
+ return generateRadioAppearance({
867
+ selected: this.getWidgetOptionName(firstWidget) === selected,
868
+ rect: this.getRect()
869
+ });
870
+ }
871
+ };
872
+
873
+ //#endregion
874
+ //#region src/form/fields/dropdownField.ts
875
+ /**
876
+ * @module form/fields/dropdownField
877
+ *
878
+ * PDF dropdown (combo box) form field (/FT /Ch with Combo flag).
879
+ *
880
+ * Reference: PDF 1.7 spec, SS12.7.4.4 (Choice Fields).
881
+ */
882
+ /**
883
+ * A PDF dropdown (combo box) field (/FT /Ch with Combo flag).
884
+ *
885
+ * Options are stored in the /Opt array. The selected value is in /V.
886
+ * Optionally editable (bit 18 of /Ff).
887
+ */
888
+ var PdfDropdownField = class extends PdfField {
889
+ fieldType = "dropdown";
890
+ /** Get the currently selected value. */
891
+ getSelected() {
892
+ return strVal(this.dict.get("/V")) ?? "";
893
+ }
894
+ /** Select a value from the options. */
895
+ select(value) {
896
+ this.dict.set("/V", require_pdfObjects.PdfString.literal(value));
897
+ this.widgetDict.delete("/AP");
898
+ }
899
+ /** Alias for getSelected(). */
900
+ getValue() {
901
+ return this.getSelected();
902
+ }
903
+ /** Alias for select(). */
904
+ setValue(value) {
905
+ this.select(typeof value === "string" ? value : String(value));
906
+ }
907
+ /**
908
+ * Get the list of options.
909
+ *
910
+ * /Opt may be an array of strings, or an array of two-element arrays
911
+ * where element [0] is the export value and element [1] is the display
912
+ * value. We return the display values (or export values if no display).
913
+ */
914
+ getOptions() {
915
+ const optObj = this.dict.get("/Opt");
916
+ if (optObj === void 0 || optObj.kind !== "array") return [];
917
+ const arr = optObj;
918
+ const options = [];
919
+ for (const item of arr.items) if (item.kind === "string") options.push(item.value);
920
+ else if (item.kind === "array") {
921
+ const subArr = item;
922
+ const display = subArr.items[1] ?? subArr.items[0];
923
+ if (display !== void 0 && display.kind === "string") options.push(display.value);
924
+ }
925
+ return options;
926
+ }
927
+ /** Set the list of options. */
928
+ setOptions(options) {
929
+ const arr = require_pdfObjects.PdfArray.of(options.map((o) => require_pdfObjects.PdfString.literal(o)));
930
+ this.dict.set("/Opt", arr);
931
+ this.widgetDict.delete("/AP");
932
+ }
933
+ /** Whether the dropdown allows manual text entry. */
934
+ isEditable() {
935
+ return this.hasFlag(FieldFlags.Edit);
936
+ }
937
+ /** Set whether the dropdown allows manual text entry. */
938
+ setEditable(editable) {
939
+ this.setFlag(FieldFlags.Edit, editable);
940
+ }
941
+ /** Generate the appearance stream for this dropdown. */
942
+ generateAppearance() {
943
+ return generateDropdownAppearance({
944
+ value: this.getSelected(),
945
+ rect: this.getRect()
946
+ });
947
+ }
948
+ };
949
+
950
+ //#endregion
951
+ //#region src/form/fields/listboxField.ts
952
+ /**
953
+ * @module form/fields/listboxField
954
+ *
955
+ * PDF listbox form field (/FT /Ch without Combo flag).
956
+ *
957
+ * Reference: PDF 1.7 spec, SS12.7.4.4 (Choice Fields).
958
+ */
959
+ /**
960
+ * A PDF listbox field (/FT /Ch without Combo flag).
961
+ *
962
+ * Displays a scrollable list of options. May allow multi-select.
963
+ * The /V entry holds the selected value(s).
964
+ */
965
+ var PdfListboxField = class extends PdfField {
966
+ fieldType = "listbox";
967
+ /**
968
+ * Get the currently selected value(s).
969
+ *
970
+ * Returns an array of strings (may contain one element for
971
+ * single-select listboxes).
972
+ */
973
+ getSelected() {
974
+ const v = this.dict.get("/V");
975
+ if (v === void 0) return [];
976
+ if (v.kind === "string") return [v.value];
977
+ if (v.kind === "array") return v.items.filter((item) => item.kind === "string").map((item) => item.value);
978
+ return [];
979
+ }
980
+ /** Select one or more values. */
981
+ select(values) {
982
+ if (values.length === 1) this.dict.set("/V", require_pdfObjects.PdfString.literal(values[0]));
983
+ else {
984
+ const arr = require_pdfObjects.PdfArray.of(values.map((v) => require_pdfObjects.PdfString.literal(v)));
985
+ this.dict.set("/V", arr);
986
+ }
987
+ this.widgetDict.delete("/AP");
988
+ }
989
+ /** Get value as string array. */
990
+ getValue() {
991
+ return this.getSelected();
992
+ }
993
+ /** Set value from string array. */
994
+ setValue(value) {
995
+ if (Array.isArray(value)) this.select(value);
996
+ else this.select([String(value)]);
997
+ }
998
+ /** Get the list of options. */
999
+ getOptions() {
1000
+ const optObj = this.dict.get("/Opt");
1001
+ if (optObj === void 0 || optObj.kind !== "array") return [];
1002
+ const arr = optObj;
1003
+ const options = [];
1004
+ for (const item of arr.items) if (item.kind === "string") options.push(item.value);
1005
+ else if (item.kind === "array") {
1006
+ const subArr = item;
1007
+ const display = subArr.items[1] ?? subArr.items[0];
1008
+ if (display !== void 0 && display.kind === "string") options.push(display.value);
1009
+ }
1010
+ return options;
1011
+ }
1012
+ /** Set the list of options. */
1013
+ setOptions(options) {
1014
+ const arr = require_pdfObjects.PdfArray.of(options.map((o) => require_pdfObjects.PdfString.literal(o)));
1015
+ this.dict.set("/Opt", arr);
1016
+ this.widgetDict.delete("/AP");
1017
+ }
1018
+ /** Generate the appearance stream for this listbox. */
1019
+ generateAppearance() {
1020
+ return generateListboxAppearance({
1021
+ options: this.getOptions(),
1022
+ selected: this.getSelected(),
1023
+ rect: this.getRect()
1024
+ });
1025
+ }
1026
+ };
1027
+
1028
+ //#endregion
1029
+ //#region src/form/fields/buttonField.ts
1030
+ /**
1031
+ * @module form/fields/buttonField
1032
+ *
1033
+ * PDF pushbutton form field (/FT /Btn with Pushbutton flag).
1034
+ *
1035
+ * Reference: PDF 1.7 spec, SS12.7.4.2.3 (Push-Buttons).
1036
+ */
1037
+ /** Format a number for PDF content stream output. */
1038
+ function n(value) {
1039
+ if (Number.isInteger(value)) return value.toString();
1040
+ const s = value.toFixed(6).replace(/\.?0+$/, "");
1041
+ return s === "-0" ? "0" : s;
1042
+ }
1043
+ /**
1044
+ * A PDF pushbutton field (/FT /Btn with Pushbutton flag).
1045
+ *
1046
+ * Pushbuttons have no permanent value. They may have an associated
1047
+ * action (e.g. JavaScript, submit form, reset form) and display a
1048
+ * caption via the /MK dictionary.
1049
+ */
1050
+ var PdfButtonField = class extends PdfField {
1051
+ fieldType = "button";
1052
+ /**
1053
+ * Get the button caption from the /MK dictionary.
1054
+ * Returns undefined if no caption is set.
1055
+ */
1056
+ getCaption() {
1057
+ const mk = this.widgetDict.get("/MK");
1058
+ if (mk !== void 0 && mk.kind === "dict") return strVal(mk.get("/CA"));
1059
+ }
1060
+ /**
1061
+ * Set the button caption in the /MK dictionary.
1062
+ * Creates the /MK dictionary if it does not exist.
1063
+ */
1064
+ setCaption(caption) {
1065
+ let mk = this.widgetDict.get("/MK");
1066
+ if (mk === void 0 || mk.kind !== "dict") {
1067
+ mk = new require_pdfObjects.PdfDict();
1068
+ this.widgetDict.set("/MK", mk);
1069
+ }
1070
+ mk.set("/CA", require_pdfObjects.PdfString.literal(caption));
1071
+ this.widgetDict.delete("/AP");
1072
+ }
1073
+ /**
1074
+ * Set an image on this button field.
1075
+ *
1076
+ * Creates an appearance stream that paints the image XObject scaled
1077
+ * to fit the widget rectangle.
1078
+ *
1079
+ * @param imageRef An object with `name` (resource name) and `ref` (PdfRef)
1080
+ * pointing to the image XObject, plus `width` and `height`.
1081
+ */
1082
+ setImage(imageRef) {
1083
+ const rect = this.getRect();
1084
+ const fieldW = Math.abs(rect[2] - rect[0]);
1085
+ const fieldH = Math.abs(rect[3] - rect[1]);
1086
+ const scaleX = fieldW / imageRef.width;
1087
+ const scaleY = fieldH / imageRef.height;
1088
+ const scale = Math.min(scaleX, scaleY);
1089
+ const drawW = imageRef.width * scale;
1090
+ const drawH = imageRef.height * scale;
1091
+ const offsetX = (fieldW - drawW) / 2;
1092
+ const offsetY = (fieldH - drawH) / 2;
1093
+ const ops = `q\n${n(drawW)} 0 0 ${n(drawH)} ${n(offsetX)} ${n(offsetY)} cm\n/${imageRef.name} Do\nQ\n`;
1094
+ const apDict = new require_pdfObjects.PdfDict();
1095
+ apDict.set("/Type", require_pdfObjects.PdfName.of("XObject"));
1096
+ apDict.set("/Subtype", require_pdfObjects.PdfName.of("Form"));
1097
+ apDict.set("/BBox", require_pdfObjects.PdfArray.fromNumbers([
1098
+ 0,
1099
+ 0,
1100
+ fieldW,
1101
+ fieldH
1102
+ ]));
1103
+ const resources = new require_pdfObjects.PdfDict();
1104
+ const xObjectDict = new require_pdfObjects.PdfDict();
1105
+ xObjectDict.set(`/${imageRef.name}`, imageRef.ref);
1106
+ resources.set("/XObject", xObjectDict);
1107
+ apDict.set("/Resources", resources);
1108
+ const stream = require_pdfObjects.PdfStream.fromString(ops, apDict);
1109
+ const apWrapper = new require_pdfObjects.PdfDict();
1110
+ apWrapper.set("/N", stream);
1111
+ this.widgetDict.set("/AP", apWrapper);
1112
+ }
1113
+ /** Pushbuttons have no value; returns empty string. */
1114
+ getValue() {
1115
+ return "";
1116
+ }
1117
+ /** Pushbuttons have no value; no-op. */
1118
+ setValue(_value) {}
1119
+ /** Generate the appearance stream for this button. */
1120
+ generateAppearance() {
1121
+ return generateButtonAppearance({
1122
+ caption: this.getCaption() ?? "",
1123
+ rect: this.getRect()
1124
+ });
1125
+ }
1126
+ };
1127
+
1128
+ //#endregion
1129
+ //#region src/form/fields/signatureField.ts
1130
+ /**
1131
+ * A PDF signature form field (/FT /Sig).
1132
+ *
1133
+ * The /V entry is a signature dictionary containing the cryptographic
1134
+ * signature data. This class provides read access to check whether the
1135
+ * field is signed, but does not implement signing (see Phase 6).
1136
+ */
1137
+ var PdfSignatureField = class extends PdfField {
1138
+ fieldType = "signature";
1139
+ /**
1140
+ * Whether this signature field has been signed.
1141
+ * A signed field has a /V entry that is a dictionary.
1142
+ */
1143
+ isSigned() {
1144
+ const v = this.dict.get("/V");
1145
+ return v !== void 0 && v.kind === "dict";
1146
+ }
1147
+ /**
1148
+ * Get the signature dictionary, if signed.
1149
+ * Returns undefined if the field has not been signed.
1150
+ */
1151
+ getSignatureValue() {
1152
+ const v = this.dict.get("/V");
1153
+ if (v !== void 0 && v.kind === "dict") return v;
1154
+ }
1155
+ /** Get value: returns "signed" or "unsigned". */
1156
+ getValue() {
1157
+ return this.isSigned() ? "signed" : "unsigned";
1158
+ }
1159
+ /** Signature fields cannot be set via setValue. */
1160
+ setValue(_value) {}
1161
+ /** Generate the appearance stream for this signature field. */
1162
+ generateAppearance() {
1163
+ return generateSignatureAppearance({
1164
+ signed: this.isSigned(),
1165
+ rect: this.getRect()
1166
+ });
1167
+ }
1168
+ };
1169
+
1170
+ //#endregion
1171
+ //#region src/form/pdfForm.ts
1172
+ /**
1173
+ * @module form/pdfForm
1174
+ *
1175
+ * The main AcroForm class — manages the field tree, provides typed
1176
+ * field accessors, and implements fill/flatten operations.
1177
+ *
1178
+ * Reference: PDF 1.7 spec, SS12.7 (Interactive Forms).
1179
+ */
1180
+ /**
1181
+ * Determine the field type from a field dictionary.
1182
+ *
1183
+ * Uses /FT (field type) and /Ff (field flags) to distinguish
1184
+ * between the various field subtypes.
1185
+ */
1186
+ function classifyField(dict, resolver) {
1187
+ const ft = nameVal(resolveIfRef(dict.get("/FT"), resolver));
1188
+ if (ft === void 0) return void 0;
1189
+ switch (ft) {
1190
+ case "Tx": return "text";
1191
+ case "Btn": {
1192
+ const ff = numVal(resolveIfRef(dict.get("/Ff"), resolver)) ?? 0;
1193
+ if (ff & FieldFlags.Pushbutton) return "button";
1194
+ if (ff & FieldFlags.Radio) return "radio";
1195
+ return "checkbox";
1196
+ }
1197
+ case "Ch":
1198
+ if ((numVal(resolveIfRef(dict.get("/Ff"), resolver)) ?? 0) & FieldFlags.Combo) return "dropdown";
1199
+ return "listbox";
1200
+ case "Sig": return "signature";
1201
+ default: return;
1202
+ }
1203
+ }
1204
+ /**
1205
+ * Resolve a PdfObject if it is a PdfRef using the resolver.
1206
+ */
1207
+ function resolveObj(obj, resolver) {
1208
+ if (obj.kind === "ref") return resolver(obj);
1209
+ return obj;
1210
+ }
1211
+ /**
1212
+ * Create the appropriate PdfField subclass for a given field dictionary.
1213
+ */
1214
+ function createFieldInstance(type, name, dict, widgetDict, parentNames, widgets) {
1215
+ switch (type) {
1216
+ case "text": return new PdfTextField(name, dict, widgetDict, parentNames);
1217
+ case "checkbox": return new PdfCheckboxField(name, dict, widgetDict, parentNames);
1218
+ case "radio": return new PdfRadioGroup(name, dict, widgetDict, parentNames, widgets);
1219
+ case "dropdown": return new PdfDropdownField(name, dict, widgetDict, parentNames);
1220
+ case "listbox": return new PdfListboxField(name, dict, widgetDict, parentNames);
1221
+ case "button": return new PdfButtonField(name, dict, widgetDict, parentNames);
1222
+ case "signature": return new PdfSignatureField(name, dict, widgetDict, parentNames);
1223
+ }
1224
+ }
1225
+ /**
1226
+ * Represents a PDF document's interactive form (AcroForm).
1227
+ *
1228
+ * Provides access to all form fields, bulk fill, and flatten operations.
1229
+ */
1230
+ var PdfForm = class PdfForm {
1231
+ /** All fields in the form (flat list). */
1232
+ fields;
1233
+ /** The underlying /AcroForm dictionary. */
1234
+ acroFormDict;
1235
+ /** Map from field name to field for fast lookup. */
1236
+ fieldsByName;
1237
+ constructor(fields, acroFormDict) {
1238
+ this.fields = fields;
1239
+ this.acroFormDict = acroFormDict;
1240
+ this.fieldsByName = /* @__PURE__ */ new Map();
1241
+ for (const field of fields) {
1242
+ this.fieldsByName.set(field.getFullName(), field);
1243
+ if (field.getName() !== field.getFullName()) this.fieldsByName.set(field.getName(), field);
1244
+ }
1245
+ }
1246
+ /**
1247
+ * Build a PdfForm from a parsed /AcroForm dictionary.
1248
+ *
1249
+ * Traverses the /Fields array and resolves indirect references to
1250
+ * construct the field tree, then flattens it into a list of concrete
1251
+ * field instances.
1252
+ *
1253
+ * @param acroFormDict The /AcroForm dictionary from the document catalog.
1254
+ * @param resolver Function to resolve PdfRef to PdfObject.
1255
+ */
1256
+ static fromDict(acroFormDict, resolver) {
1257
+ const fieldsObj = resolveIfRef(acroFormDict.get("/Fields"), resolver);
1258
+ if (fieldsObj === void 0 || fieldsObj.kind !== "array") return new PdfForm([], acroFormDict);
1259
+ const fieldsArray = fieldsObj;
1260
+ const fields = [];
1261
+ for (const item of fieldsArray.items) {
1262
+ const fieldDict = resolveObj(item, resolver);
1263
+ if (fieldDict.kind !== "dict") continue;
1264
+ PdfForm.traverseFieldTree(fieldDict, resolver, [], fields);
1265
+ }
1266
+ return new PdfForm(fields, acroFormDict);
1267
+ }
1268
+ /**
1269
+ * Recursively traverse the field tree rooted at `dict`.
1270
+ *
1271
+ * The AcroForm field tree uses /Kids for both child fields and
1272
+ * widget annotations. A node is a field if it has /FT; it is a
1273
+ * widget annotation if it has /Subtype /Widget.
1274
+ */
1275
+ static traverseFieldTree(dict, resolver, parentNames, result) {
1276
+ const name = strVal(dict.get("/T")) ?? "";
1277
+ const type = classifyField(dict, resolver);
1278
+ const kidsObj = resolveIfRef(dict.get("/Kids"), resolver);
1279
+ if (type !== void 0) if (kidsObj !== void 0 && kidsObj.kind === "array") {
1280
+ const kidsArr = kidsObj;
1281
+ const widgets = [];
1282
+ for (const kid of kidsArr.items) {
1283
+ const kidDict = resolveObj(kid, resolver);
1284
+ if (kidDict.kind === "dict") {
1285
+ const kidPdfDict = kidDict;
1286
+ if (nameVal(kidPdfDict.get("/Subtype")) === "Widget") widgets.push(kidPdfDict);
1287
+ else if (classifyField(kidPdfDict, resolver) !== void 0) {
1288
+ PdfForm.traverseFieldTree(kidPdfDict, resolver, [...parentNames, name], result);
1289
+ continue;
1290
+ } else widgets.push(kidPdfDict);
1291
+ }
1292
+ }
1293
+ const field = createFieldInstance(type, name, dict, widgets[0] ?? dict, parentNames, widgets);
1294
+ result.push(field);
1295
+ } else {
1296
+ const field = createFieldInstance(type, name, dict, dict, parentNames, []);
1297
+ result.push(field);
1298
+ }
1299
+ else if (kidsObj !== void 0 && kidsObj.kind === "array") {
1300
+ const kidsArr = kidsObj;
1301
+ for (const kid of kidsArr.items) {
1302
+ const kidDict = resolveObj(kid, resolver);
1303
+ if (kidDict.kind === "dict") PdfForm.traverseFieldTree(kidDict, resolver, name !== "" ? [...parentNames, name] : parentNames, result);
1304
+ }
1305
+ }
1306
+ }
1307
+ /** Get all fields in the form. */
1308
+ getFields() {
1309
+ return [...this.fields];
1310
+ }
1311
+ /**
1312
+ * Get a field by name (partial or fully-qualified).
1313
+ * Returns undefined if not found.
1314
+ */
1315
+ getField(name) {
1316
+ return this.fieldsByName.get(name);
1317
+ }
1318
+ /**
1319
+ * Get a text field by name.
1320
+ * Throws if the field is not found or is not a text field.
1321
+ */
1322
+ getTextField(name) {
1323
+ const field = this.getField(name);
1324
+ if (field === void 0) throw new Error(`Form field "${name}" not found.`);
1325
+ if (field.fieldType !== "text") throw new Error(`Form field "${name}" is a ${field.fieldType} field, not a text field.`);
1326
+ return field;
1327
+ }
1328
+ /**
1329
+ * Get a checkbox field by name.
1330
+ * Throws if the field is not found or is not a checkbox.
1331
+ */
1332
+ getCheckbox(name) {
1333
+ const field = this.getField(name);
1334
+ if (field === void 0) throw new Error(`Form field "${name}" not found.`);
1335
+ if (field.fieldType !== "checkbox") throw new Error(`Form field "${name}" is a ${field.fieldType} field, not a checkbox.`);
1336
+ return field;
1337
+ }
1338
+ /**
1339
+ * Get a radio group by name.
1340
+ * Throws if the field is not found or is not a radio group.
1341
+ */
1342
+ getRadioGroup(name) {
1343
+ const field = this.getField(name);
1344
+ if (field === void 0) throw new Error(`Form field "${name}" not found.`);
1345
+ if (field.fieldType !== "radio") throw new Error(`Form field "${name}" is a ${field.fieldType} field, not a radio group.`);
1346
+ return field;
1347
+ }
1348
+ /**
1349
+ * Get a dropdown field by name.
1350
+ * Throws if the field is not found or is not a dropdown.
1351
+ */
1352
+ getDropdown(name) {
1353
+ const field = this.getField(name);
1354
+ if (field === void 0) throw new Error(`Form field "${name}" not found.`);
1355
+ if (field.fieldType !== "dropdown") throw new Error(`Form field "${name}" is a ${field.fieldType} field, not a dropdown.`);
1356
+ return field;
1357
+ }
1358
+ /**
1359
+ * Get a listbox field by name.
1360
+ * Throws if the field is not found or is not a listbox.
1361
+ */
1362
+ getListbox(name) {
1363
+ const field = this.getField(name);
1364
+ if (field === void 0) throw new Error(`Form field "${name}" not found.`);
1365
+ if (field.fieldType !== "listbox") throw new Error(`Form field "${name}" is a ${field.fieldType} field, not a listbox.`);
1366
+ return field;
1367
+ }
1368
+ /**
1369
+ * Get a button field by name.
1370
+ * Throws if the field is not found or is not a button.
1371
+ */
1372
+ getButton(name) {
1373
+ const field = this.getField(name);
1374
+ if (field === void 0) throw new Error(`Form field "${name}" not found.`);
1375
+ if (field.fieldType !== "button") throw new Error(`Form field "${name}" is a ${field.fieldType} field, not a button.`);
1376
+ return field;
1377
+ }
1378
+ /**
1379
+ * Get a signature field by name.
1380
+ * Throws if the field is not found or is not a signature field.
1381
+ */
1382
+ getSignatureField(name) {
1383
+ const field = this.getField(name);
1384
+ if (field === void 0) throw new Error(`Form field "${name}" not found.`);
1385
+ if (field.fieldType !== "signature") throw new Error(`Form field "${name}" is a ${field.fieldType} field, not a signature field.`);
1386
+ return field;
1387
+ }
1388
+ /**
1389
+ * Fill multiple fields at once.
1390
+ *
1391
+ * Accepts a record where keys are field names and values are the
1392
+ * field values to set. Strings map to text/dropdown/listbox values;
1393
+ * booleans map to checkbox checked states.
1394
+ *
1395
+ * @param values A mapping of field name to value.
1396
+ * @throws If a field name is not found.
1397
+ */
1398
+ fill(values) {
1399
+ for (const [name, value] of Object.entries(values)) {
1400
+ const field = this.getField(name);
1401
+ if (field === void 0) throw new Error(`Form field "${name}" not found.`);
1402
+ field.setValue(value);
1403
+ }
1404
+ }
1405
+ /**
1406
+ * Flatten the form: burn field values into the page content streams
1407
+ * and remove the interactive form structure.
1408
+ *
1409
+ * After flattening, the document is no longer interactive — field
1410
+ * values become static page content. This is done by:
1411
+ *
1412
+ * 1. Generating appearance streams for all fields that lack them
1413
+ * 2. Removing the /AcroForm entry from the catalog
1414
+ * 3. Removing /Widget annotations from page /Annots arrays
1415
+ *
1416
+ * Note: In this implementation, we mark the form as flattened by
1417
+ * setting a flag and clearing the /Fields array. The appearance
1418
+ * streams remain as page annotations will reference them.
1419
+ */
1420
+ flatten() {
1421
+ for (const field of this.fields) field.generateAppearance();
1422
+ this.acroFormDict.set("/Fields", new require_pdfObjects.PdfArray());
1423
+ this.acroFormDict.delete("/NeedAppearances");
1424
+ }
1425
+ /**
1426
+ * Check whether the AcroForm dictionary contains XFA data.
1427
+ *
1428
+ * XFA (XML Forms Architecture) data causes PDF viewers to use the
1429
+ * XFA renderer instead of the standard AcroForm renderer. Use
1430
+ * {@link deleteXFA} to remove it.
1431
+ *
1432
+ * @returns `true` if the form has an /XFA entry.
1433
+ */
1434
+ hasXFA() {
1435
+ return this.acroFormDict.has("/XFA");
1436
+ }
1437
+ /**
1438
+ * Remove the /XFA entry from the AcroForm dictionary, if present.
1439
+ *
1440
+ * XFA (XML Forms Architecture) data can cause PDF viewers to use the
1441
+ * XFA renderer instead of the standard AcroForm renderer, which is
1442
+ * often undesirable. Removing /XFA forces viewers to fall back to
1443
+ * the AcroForm fields.
1444
+ *
1445
+ * After removing /XFA, `/NeedAppearances` is set to `true` so that
1446
+ * the viewer knows it must generate appearances for the AcroForm
1447
+ * fields (since XFA appearances are no longer available).
1448
+ *
1449
+ * This method is a no-op if the AcroForm dictionary does not contain
1450
+ * an /XFA entry.
1451
+ */
1452
+ deleteXFA() {
1453
+ if (!this.acroFormDict.has("/XFA")) return;
1454
+ this.acroFormDict.delete("/XFA");
1455
+ this.acroFormDict.set("/NeedAppearances", require_pdfObjects.PdfBool.TRUE);
1456
+ }
1457
+ /**
1458
+ * Create a new text field and add it to the form.
1459
+ *
1460
+ * @param name Field name.
1461
+ * @param page Page index (zero-based) where the widget appears.
1462
+ * @param rect Widget rectangle [x1, y1, x2, y2].
1463
+ * @returns The newly created text field.
1464
+ */
1465
+ createTextField(name, page, rect) {
1466
+ const dict = this.createFieldDict(name, "Tx", rect);
1467
+ dict.set("/DA", require_pdfObjects.PdfString.literal("/Helv 0 Tf 0 g"));
1468
+ const field = new PdfTextField(name, dict, dict);
1469
+ this.fields.push(field);
1470
+ this.fieldsByName.set(name, field);
1471
+ this.addFieldToAcroForm(dict);
1472
+ return field;
1473
+ }
1474
+ /**
1475
+ * Create a new checkbox and add it to the form.
1476
+ *
1477
+ * @param name Field name.
1478
+ * @param page Page index (zero-based).
1479
+ * @param rect Widget rectangle [x1, y1, x2, y2].
1480
+ * @returns The newly created checkbox field.
1481
+ */
1482
+ createCheckbox(name, page, rect) {
1483
+ const dict = this.createFieldDict(name, "Btn", rect);
1484
+ dict.set("/V", require_pdfObjects.PdfName.of("Off"));
1485
+ dict.set("/AS", require_pdfObjects.PdfName.of("Off"));
1486
+ const field = new PdfCheckboxField(name, dict, dict);
1487
+ this.fields.push(field);
1488
+ this.fieldsByName.set(name, field);
1489
+ this.addFieldToAcroForm(dict);
1490
+ return field;
1491
+ }
1492
+ /**
1493
+ * Create a new dropdown and add it to the form.
1494
+ *
1495
+ * @param name Field name.
1496
+ * @param page Page index (zero-based).
1497
+ * @param rect Widget rectangle [x1, y1, x2, y2].
1498
+ * @param options The list of option strings.
1499
+ * @returns The newly created dropdown field.
1500
+ */
1501
+ createDropdown(name, page, rect, options) {
1502
+ const dict = this.createFieldDict(name, "Ch", rect);
1503
+ dict.set("/Ff", require_pdfObjects.PdfNumber.of(FieldFlags.Combo));
1504
+ dict.set("/Opt", require_pdfObjects.PdfArray.of(options.map((o) => require_pdfObjects.PdfString.literal(o))));
1505
+ dict.set("/DA", require_pdfObjects.PdfString.literal("/Helv 0 Tf 0 g"));
1506
+ const field = new PdfDropdownField(name, dict, dict);
1507
+ this.fields.push(field);
1508
+ this.fieldsByName.set(name, field);
1509
+ this.addFieldToAcroForm(dict);
1510
+ return field;
1511
+ }
1512
+ /**
1513
+ * Create a new radio button group and add it to the form.
1514
+ *
1515
+ * A radio group is a single field with multiple widget annotations,
1516
+ * one per rectangle in `rects`. Each widget corresponds to an
1517
+ * option; if `options` is supplied the n-th option labels the n-th
1518
+ * widget, otherwise options default to `"Option0"`, `"Option1"`, etc.
1519
+ *
1520
+ * @param name Field name.
1521
+ * @param page The PdfPage where the widgets appear (unused for
1522
+ * positioning in the low-level dict, but reserved
1523
+ * for future page-level annotation linking).
1524
+ * @param rects Array of widget rectangles `{x, y, width, height}`.
1525
+ * @param options Optional option labels (one per rect).
1526
+ * @returns The newly created radio group.
1527
+ */
1528
+ createRadioGroup(name, page, rects, options) {
1529
+ const fieldDict = new require_pdfObjects.PdfDict();
1530
+ fieldDict.set("/FT", require_pdfObjects.PdfName.of("Btn"));
1531
+ fieldDict.set("/Ff", require_pdfObjects.PdfNumber.of(FieldFlags.Radio | FieldFlags.NoToggleToOff));
1532
+ fieldDict.set("/T", require_pdfObjects.PdfString.literal(name));
1533
+ fieldDict.set("/V", require_pdfObjects.PdfName.of("Off"));
1534
+ const widgets = [];
1535
+ const kidsArr = new require_pdfObjects.PdfArray();
1536
+ for (let i = 0; i < rects.length; i++) {
1537
+ const r = rects[i];
1538
+ const optName = options?.[i] ?? `Option${i}`;
1539
+ const rect = [
1540
+ r.x,
1541
+ r.y,
1542
+ r.x + r.width,
1543
+ r.y + r.height
1544
+ ];
1545
+ const widgetDict = new require_pdfObjects.PdfDict();
1546
+ widgetDict.set("/Type", require_pdfObjects.PdfName.of("Annot"));
1547
+ widgetDict.set("/Subtype", require_pdfObjects.PdfName.of("Widget"));
1548
+ widgetDict.set("/Rect", require_pdfObjects.PdfArray.fromNumbers(rect));
1549
+ widgetDict.set("/AS", require_pdfObjects.PdfName.of("Off"));
1550
+ widgetDict.set("/Parent", fieldDict);
1551
+ const nDict = new require_pdfObjects.PdfDict();
1552
+ nDict.set(`/${optName}`, new require_pdfObjects.PdfStream(new require_pdfObjects.PdfDict(), new Uint8Array(0)));
1553
+ nDict.set("/Off", new require_pdfObjects.PdfStream(new require_pdfObjects.PdfDict(), new Uint8Array(0)));
1554
+ const apDict = new require_pdfObjects.PdfDict();
1555
+ apDict.set("/N", nDict);
1556
+ widgetDict.set("/AP", apDict);
1557
+ widgets.push(widgetDict);
1558
+ kidsArr.push(widgetDict);
1559
+ }
1560
+ fieldDict.set("/Kids", kidsArr);
1561
+ const field = new PdfRadioGroup(name, fieldDict, widgets[0] ?? fieldDict, [], widgets);
1562
+ this.fields.push(field);
1563
+ this.fieldsByName.set(name, field);
1564
+ this.addFieldToAcroForm(fieldDict);
1565
+ return field;
1566
+ }
1567
+ /**
1568
+ * Create a new push button and add it to the form.
1569
+ *
1570
+ * @param name Field name.
1571
+ * @param page The PdfPage where the widget appears.
1572
+ * @param rect Widget rectangle `{x, y, width, height}`.
1573
+ * @param label Optional button caption.
1574
+ * @returns The newly created button field.
1575
+ */
1576
+ createButton(name, page, rect, label) {
1577
+ const pdfRect = [
1578
+ rect.x,
1579
+ rect.y,
1580
+ rect.x + rect.width,
1581
+ rect.y + rect.height
1582
+ ];
1583
+ const dict = this.createFieldDict(name, "Btn", pdfRect);
1584
+ dict.set("/Ff", require_pdfObjects.PdfNumber.of(FieldFlags.Pushbutton));
1585
+ if (label !== void 0) {
1586
+ const mk = new require_pdfObjects.PdfDict();
1587
+ mk.set("/CA", require_pdfObjects.PdfString.literal(label));
1588
+ dict.set("/MK", mk);
1589
+ }
1590
+ const field = new PdfButtonField(name, dict, dict);
1591
+ this.fields.push(field);
1592
+ this.fieldsByName.set(name, field);
1593
+ this.addFieldToAcroForm(dict);
1594
+ return field;
1595
+ }
1596
+ /**
1597
+ * Create a new listbox and add it to the form.
1598
+ *
1599
+ * A listbox is a choice field (/FT /Ch) without the Combo flag,
1600
+ * displaying a scrollable list of options.
1601
+ *
1602
+ * @param name Field name.
1603
+ * @param page The PdfPage where the widget appears.
1604
+ * @param rect Widget rectangle `{x, y, width, height}`.
1605
+ * @param options The list of option strings.
1606
+ * @returns The newly created listbox field.
1607
+ */
1608
+ createListbox(name, page, rect, options) {
1609
+ const pdfRect = [
1610
+ rect.x,
1611
+ rect.y,
1612
+ rect.x + rect.width,
1613
+ rect.y + rect.height
1614
+ ];
1615
+ const dict = this.createFieldDict(name, "Ch", pdfRect);
1616
+ dict.set("/Opt", require_pdfObjects.PdfArray.of(options.map((o) => require_pdfObjects.PdfString.literal(o))));
1617
+ dict.set("/DA", require_pdfObjects.PdfString.literal("/Helv 0 Tf 0 g"));
1618
+ const field = new PdfListboxField(name, dict, dict);
1619
+ this.fields.push(field);
1620
+ this.fieldsByName.set(name, field);
1621
+ this.addFieldToAcroForm(dict);
1622
+ return field;
1623
+ }
1624
+ /**
1625
+ * Remove a field from the form by name.
1626
+ *
1627
+ * Removes the field from the internal field list, the name index,
1628
+ * and the /Fields array in the AcroForm dictionary.
1629
+ *
1630
+ * @param name The field name (partial or fully-qualified).
1631
+ * @throws If no field with the given name exists.
1632
+ */
1633
+ removeField(name) {
1634
+ const field = this.fieldsByName.get(name);
1635
+ if (field === void 0) throw new Error(`Form field "${name}" not found.`);
1636
+ const idx = this.fields.indexOf(field);
1637
+ if (idx !== -1) this.fields.splice(idx, 1);
1638
+ this.fieldsByName.delete(field.getFullName());
1639
+ if (field.getName() !== field.getFullName()) this.fieldsByName.delete(field.getName());
1640
+ const fieldsObj = this.acroFormDict.get("/Fields");
1641
+ if (fieldsObj !== void 0 && fieldsObj.kind === "array") {
1642
+ const fieldsArr = fieldsObj;
1643
+ const fieldDict = field.getDict();
1644
+ const newArr = new require_pdfObjects.PdfArray(fieldsArr.items.filter((item) => item !== fieldDict));
1645
+ this.acroFormDict.set("/Fields", newArr);
1646
+ }
1647
+ }
1648
+ /**
1649
+ * Serialize the form back to a PdfDict.
1650
+ *
1651
+ * Updates /NeedAppearances if appearances need to be generated
1652
+ * by the viewer.
1653
+ */
1654
+ toDict(registry) {
1655
+ if (this.acroFormDict.get("/DR") === void 0) {
1656
+ const resources = new require_pdfObjects.PdfDict();
1657
+ const fontDict = new require_pdfObjects.PdfDict();
1658
+ const helvetica = new require_pdfObjects.PdfDict();
1659
+ helvetica.set("/Type", require_pdfObjects.PdfName.of("Font"));
1660
+ helvetica.set("/Subtype", require_pdfObjects.PdfName.of("Type1"));
1661
+ helvetica.set("/BaseFont", require_pdfObjects.PdfName.of("Helvetica"));
1662
+ fontDict.set("/Helv", helvetica);
1663
+ resources.set("/Font", fontDict);
1664
+ this.acroFormDict.set("/DR", resources);
1665
+ }
1666
+ return this.acroFormDict;
1667
+ }
1668
+ /**
1669
+ * Create a basic field dictionary with common entries.
1670
+ */
1671
+ createFieldDict(name, fieldType, rect) {
1672
+ const dict = new require_pdfObjects.PdfDict();
1673
+ dict.set("/Type", require_pdfObjects.PdfName.of("Annot"));
1674
+ dict.set("/Subtype", require_pdfObjects.PdfName.of("Widget"));
1675
+ dict.set("/FT", require_pdfObjects.PdfName.of(fieldType));
1676
+ dict.set("/T", require_pdfObjects.PdfString.literal(name));
1677
+ dict.set("/Rect", require_pdfObjects.PdfArray.fromNumbers(rect));
1678
+ return dict;
1679
+ }
1680
+ /**
1681
+ * Add a field dictionary to the /Fields array in the AcroForm.
1682
+ */
1683
+ addFieldToAcroForm(fieldDict) {
1684
+ let fieldsObj = this.acroFormDict.get("/Fields");
1685
+ if (fieldsObj === void 0 || fieldsObj.kind !== "array") {
1686
+ fieldsObj = new require_pdfObjects.PdfArray();
1687
+ this.acroFormDict.set("/Fields", fieldsObj);
1688
+ }
1689
+ fieldsObj.push(fieldDict);
1690
+ }
1691
+ };
1692
+
1693
+ //#endregion
1694
+ Object.defineProperty(exports, 'FieldFlags', {
1695
+ enumerable: true,
1696
+ get: function () {
1697
+ return FieldFlags;
1698
+ }
1699
+ });
1700
+ Object.defineProperty(exports, 'PdfButtonField', {
1701
+ enumerable: true,
1702
+ get: function () {
1703
+ return PdfButtonField;
1704
+ }
1705
+ });
1706
+ Object.defineProperty(exports, 'PdfCheckboxField', {
1707
+ enumerable: true,
1708
+ get: function () {
1709
+ return PdfCheckboxField;
1710
+ }
1711
+ });
1712
+ Object.defineProperty(exports, 'PdfDropdownField', {
1713
+ enumerable: true,
1714
+ get: function () {
1715
+ return PdfDropdownField;
1716
+ }
1717
+ });
1718
+ Object.defineProperty(exports, 'PdfField', {
1719
+ enumerable: true,
1720
+ get: function () {
1721
+ return PdfField;
1722
+ }
1723
+ });
1724
+ Object.defineProperty(exports, 'PdfForm', {
1725
+ enumerable: true,
1726
+ get: function () {
1727
+ return PdfForm;
1728
+ }
1729
+ });
1730
+ Object.defineProperty(exports, 'PdfListboxField', {
1731
+ enumerable: true,
1732
+ get: function () {
1733
+ return PdfListboxField;
1734
+ }
1735
+ });
1736
+ Object.defineProperty(exports, 'PdfRadioGroup', {
1737
+ enumerable: true,
1738
+ get: function () {
1739
+ return PdfRadioGroup;
1740
+ }
1741
+ });
1742
+ Object.defineProperty(exports, 'PdfSignatureField', {
1743
+ enumerable: true,
1744
+ get: function () {
1745
+ return PdfSignatureField;
1746
+ }
1747
+ });
1748
+ Object.defineProperty(exports, 'PdfTextField', {
1749
+ enumerable: true,
1750
+ get: function () {
1751
+ return PdfTextField;
1752
+ }
1753
+ });
1754
+ Object.defineProperty(exports, 'generateButtonAppearance', {
1755
+ enumerable: true,
1756
+ get: function () {
1757
+ return generateButtonAppearance;
1758
+ }
1759
+ });
1760
+ Object.defineProperty(exports, 'generateCheckboxAppearance', {
1761
+ enumerable: true,
1762
+ get: function () {
1763
+ return generateCheckboxAppearance;
1764
+ }
1765
+ });
1766
+ Object.defineProperty(exports, 'generateDropdownAppearance', {
1767
+ enumerable: true,
1768
+ get: function () {
1769
+ return generateDropdownAppearance;
1770
+ }
1771
+ });
1772
+ Object.defineProperty(exports, 'generateListboxAppearance', {
1773
+ enumerable: true,
1774
+ get: function () {
1775
+ return generateListboxAppearance;
1776
+ }
1777
+ });
1778
+ Object.defineProperty(exports, 'generateRadioAppearance', {
1779
+ enumerable: true,
1780
+ get: function () {
1781
+ return generateRadioAppearance;
1782
+ }
1783
+ });
1784
+ Object.defineProperty(exports, 'generateSignatureAppearance', {
1785
+ enumerable: true,
1786
+ get: function () {
1787
+ return generateSignatureAppearance;
1788
+ }
1789
+ });
1790
+ Object.defineProperty(exports, 'generateTextAppearance', {
1791
+ enumerable: true,
1792
+ get: function () {
1793
+ return generateTextAppearance;
1794
+ }
1795
+ });
1796
+ //# sourceMappingURL=pdfForm-9gd40uz9.cjs.map