pdf-lite 1.6.2 → 1.6.4

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.
package/EXAMPLES.md CHANGED
@@ -1989,3 +1989,292 @@ async function main() {
1989
1989
 
1990
1990
  main().catch(console.error)
1991
1991
  ```
1992
+
1993
+ ## JavaScript Actions example - Executing JS actions in PDF form fields
1994
+
1995
+ ```typescript
1996
+ //
1997
+ // PDF forms generated by Adobe Acrobat and LiveCycle often include JavaScript
1998
+ // actions for formatting, validation, and field calculations. The
1999
+ // PdfJavaScriptEngine executes these automatically when setting field values,
2000
+ // with built-in support for common Acrobat JS functions.
2001
+
2002
+ import { PdfArray } from 'pdf-lite/core/objects/pdf-array'
2003
+ import { PdfBoolean } from 'pdf-lite/core/objects/pdf-boolean'
2004
+ import { PdfDictionary } from 'pdf-lite/core/objects/pdf-dictionary'
2005
+ import { PdfIndirectObject } from 'pdf-lite/core/objects/pdf-indirect-object'
2006
+ import { PdfName } from 'pdf-lite/core/objects/pdf-name'
2007
+ import { PdfNumber } from 'pdf-lite/core/objects/pdf-number'
2008
+ import { PdfObjectReference } from 'pdf-lite/core/objects/pdf-object-reference'
2009
+ import { PdfStream } from 'pdf-lite/core/objects/pdf-stream'
2010
+ import { PdfString } from 'pdf-lite/core/objects/pdf-string'
2011
+ import { PdfDocument } from 'pdf-lite/pdf/pdf-document'
2012
+ import { PdfJavaScriptEngine } from 'pdf-lite/acroform/js/pdf-js-engine-impl'
2013
+ import fs from 'fs/promises'
2014
+
2015
+ const tmpFolder = `${import.meta.dirname}/tmp`
2016
+ await fs.mkdir(tmpFolder, { recursive: true })
2017
+
2018
+ // ============================================
2019
+ // Helpers
2020
+ // ============================================
2021
+
2022
+ function createPage(
2023
+ contentStreamRef: PdfObjectReference,
2024
+ ): PdfIndirectObject<PdfDictionary> {
2025
+ const d = new PdfDictionary()
2026
+ d.set('Type', new PdfName('Page'))
2027
+ d.set(
2028
+ 'MediaBox',
2029
+ new PdfArray([
2030
+ new PdfNumber(0),
2031
+ new PdfNumber(0),
2032
+ new PdfNumber(612),
2033
+ new PdfNumber(792),
2034
+ ]),
2035
+ )
2036
+ d.set('Contents', contentStreamRef)
2037
+ return new PdfIndirectObject({ content: d })
2038
+ }
2039
+
2040
+ function createPages(
2041
+ pages: PdfIndirectObject<PdfDictionary>[],
2042
+ ): PdfIndirectObject<PdfDictionary> {
2043
+ const d = new PdfDictionary()
2044
+ d.set('Type', new PdfName('Pages'))
2045
+ d.set('Kids', new PdfArray(pages.map((x) => x.reference)))
2046
+ d.set('Count', new PdfNumber(pages.length))
2047
+ return new PdfIndirectObject({ content: d })
2048
+ }
2049
+
2050
+ function createCatalog(
2051
+ pagesRef: PdfObjectReference,
2052
+ ): PdfIndirectObject<PdfDictionary> {
2053
+ const d = new PdfDictionary()
2054
+ d.set('Type', new PdfName('Catalog'))
2055
+ d.set('Pages', pagesRef)
2056
+ return new PdfIndirectObject({ content: d })
2057
+ }
2058
+
2059
+ /** Create a text field with an optional JavaScript format action. */
2060
+ function createTextField(
2061
+ fieldName: string,
2062
+ pageRef: PdfObjectReference,
2063
+ rect: [number, number, number, number],
2064
+ jsFormatCode?: string,
2065
+ jsCalcCode?: string,
2066
+ ): PdfIndirectObject<PdfDictionary> {
2067
+ const d = new PdfDictionary()
2068
+ d.set('Type', new PdfName('Annot'))
2069
+ d.set('Subtype', new PdfName('Widget'))
2070
+ d.set('FT', new PdfName('Tx'))
2071
+ d.set('T', new PdfString(fieldName))
2072
+ d.set(
2073
+ 'Rect',
2074
+ new PdfArray([
2075
+ new PdfNumber(rect[0]),
2076
+ new PdfNumber(rect[1]),
2077
+ new PdfNumber(rect[2]),
2078
+ new PdfNumber(rect[3]),
2079
+ ]),
2080
+ )
2081
+ d.set('F', new PdfNumber(4))
2082
+ d.set('P', pageRef)
2083
+ d.set('DA', new PdfString('/Helv 12 Tf 0 g'))
2084
+
2085
+ // Add /AA (additional actions) dictionary with JS format/calculate actions
2086
+ if (jsFormatCode || jsCalcCode) {
2087
+ const aa = new PdfDictionary()
2088
+ if (jsFormatCode) {
2089
+ const fmtAction = new PdfDictionary()
2090
+ fmtAction.set('S', new PdfName('JavaScript'))
2091
+ fmtAction.set('JS', new PdfString(jsFormatCode))
2092
+ aa.set('F', fmtAction)
2093
+ }
2094
+ if (jsCalcCode) {
2095
+ const calcAction = new PdfDictionary()
2096
+ calcAction.set('S', new PdfName('JavaScript'))
2097
+ calcAction.set('JS', new PdfString(jsCalcCode))
2098
+ aa.set('C', calcAction)
2099
+ }
2100
+ d.set('AA', aa)
2101
+ }
2102
+
2103
+ return new PdfIndirectObject({ content: d })
2104
+ }
2105
+
2106
+ // ============================================
2107
+ // Build a PDF with JS-powered form fields
2108
+ // ============================================
2109
+
2110
+ const document = new PdfDocument()
2111
+
2112
+ // Font
2113
+ const font = new PdfDictionary()
2114
+ font.set('Type', new PdfName('Font'))
2115
+ font.set('Subtype', new PdfName('Type1'))
2116
+ font.set('BaseFont', new PdfName('Helvetica'))
2117
+ const fontObj = new PdfIndirectObject({ content: font })
2118
+ document.add(fontObj)
2119
+
2120
+ // Resources
2121
+ const resources = new PdfDictionary()
2122
+ const fontDict = new PdfDictionary()
2123
+ fontDict.set('F1', fontObj.reference)
2124
+ resources.set('Font', fontDict)
2125
+ const resourcesObj = new PdfIndirectObject({ content: resources })
2126
+ document.add(resourcesObj)
2127
+
2128
+ // Content stream with labels
2129
+ const contentStream = new PdfIndirectObject({
2130
+ content: new PdfStream({
2131
+ header: new PdfDictionary(),
2132
+ original: `BT
2133
+ /F1 18 Tf 72 720 Td (Invoice - JS Actions Demo) Tj
2134
+ /F1 12 Tf 0 -50 Td (Price:) Tj
2135
+ 0 -30 Td (Quantity:) Tj
2136
+ 0 -30 Td (Total:) Tj
2137
+ 0 -40 Td (Phone:) Tj
2138
+ ET `,
2139
+ }),
2140
+ })
2141
+ document.add(contentStream)
2142
+
2143
+ // Page
2144
+ const page = createPage(contentStream.reference)
2145
+ page.content.set('Resources', resourcesObj.reference)
2146
+ document.add(page)
2147
+
2148
+ // Form fields with JavaScript actions:
2149
+
2150
+ // Price field — formats as currency via AFNumber_Format
2151
+ const priceField = createTextField(
2152
+ 'Price',
2153
+ page.reference,
2154
+ [150, 655, 350, 675],
2155
+ 'AFNumber_Format(2, 0, 0, 0, "$", true)',
2156
+ )
2157
+ document.add(priceField)
2158
+
2159
+ // Quantity field — plain number format
2160
+ const qtyField = createTextField(
2161
+ 'Quantity',
2162
+ page.reference,
2163
+ [150, 625, 350, 645],
2164
+ 'AFNumber_Format(0, 0, 0, 0, "", false)',
2165
+ )
2166
+ document.add(qtyField)
2167
+
2168
+ // Total field — calculated as Price * Quantity via AFSimple_Calculate
2169
+ const totalField = createTextField(
2170
+ 'Total',
2171
+ page.reference,
2172
+ [150, 595, 350, 615],
2173
+ 'AFNumber_Format(2, 0, 0, 0, "$", true)',
2174
+ 'AFSimple_Calculate("PRD", ["Price", "Quantity"])',
2175
+ )
2176
+ document.add(totalField)
2177
+
2178
+ // Phone field — formatted via AFSpecial_Format (phone)
2179
+ const phoneField = createTextField(
2180
+ 'Phone',
2181
+ page.reference,
2182
+ [150, 555, 350, 575],
2183
+ 'AFSpecial_Format(2)',
2184
+ )
2185
+ document.add(phoneField)
2186
+
2187
+ // Annotations on page
2188
+ page.content.set(
2189
+ 'Annots',
2190
+ new PdfArray([
2191
+ priceField.reference,
2192
+ qtyField.reference,
2193
+ totalField.reference,
2194
+ phoneField.reference,
2195
+ ]),
2196
+ )
2197
+
2198
+ // Pages / catalog
2199
+ const pages = createPages([page])
2200
+ page.content.set('Parent', pages.reference)
2201
+ document.add(pages)
2202
+
2203
+ const catalog = createCatalog(pages.reference)
2204
+
2205
+ // AcroForm with fields and calculation order
2206
+ const acroForm = new PdfDictionary()
2207
+ acroForm.set(
2208
+ 'Fields',
2209
+ new PdfArray([
2210
+ priceField.reference,
2211
+ qtyField.reference,
2212
+ totalField.reference,
2213
+ phoneField.reference,
2214
+ ]),
2215
+ )
2216
+ // Calculation order — Total depends on Price and Quantity
2217
+ acroForm.set('CO', new PdfArray([totalField.reference]))
2218
+ acroForm.set('NeedAppearances', new PdfBoolean(true))
2219
+
2220
+ // Form default resources
2221
+ const formResources = new PdfDictionary()
2222
+ const formFontDict = new PdfDictionary()
2223
+ const helvetica = new PdfDictionary()
2224
+ helvetica.set('Type', new PdfName('Font'))
2225
+ helvetica.set('Subtype', new PdfName('Type1'))
2226
+ helvetica.set('BaseFont', new PdfName('Helvetica'))
2227
+ const helveticaObj = new PdfIndirectObject({ content: helvetica })
2228
+ document.add(helveticaObj)
2229
+ formFontDict.set('Helv', helveticaObj.reference)
2230
+ formResources.set('Font', formFontDict)
2231
+ acroForm.set('DR', formResources)
2232
+ acroForm.set('DA', new PdfString('/Helv 12 Tf 0 g'))
2233
+
2234
+ const acroFormObj = new PdfIndirectObject({ content: acroForm })
2235
+ document.add(acroFormObj)
2236
+ catalog.content.set('AcroForm', acroFormObj.reference)
2237
+ document.add(catalog)
2238
+ document.trailerDict.set('Root', catalog.reference)
2239
+
2240
+ await document.finalize()
2241
+ await fs.writeFile(`${tmpFolder}/js-actions-form.pdf`, document.toBytes())
2242
+ console.log('Created js-actions-form.pdf with JavaScript action fields')
2243
+
2244
+ // ============================================
2245
+ // Fill the form with the JS engine enabled
2246
+ // ============================================
2247
+
2248
+ const formBytes = await fs.readFile(`${tmpFolder}/js-actions-form.pdf`)
2249
+ const filledDoc = await PdfDocument.fromBytes([formBytes])
2250
+ const form = filledDoc.acroform!
2251
+
2252
+ // Attach the JS engine with a field value resolver for AFSimple_Calculate
2253
+ form.jsEngine = new PdfJavaScriptEngine({
2254
+ getFieldValue: (name) => {
2255
+ const field = form.fields.find((f) => f.name === name)
2256
+ return field?.value ?? ''
2257
+ },
2258
+ })
2259
+
2260
+ // Set values — JS format actions fire automatically
2261
+ form.setValues({
2262
+ Price: '49.99',
2263
+ Quantity: '3',
2264
+ Phone: '5551234567',
2265
+ })
2266
+
2267
+ // Print resulting values (after JS actions have run)
2268
+ console.log('\nField values after JS actions:')
2269
+ for (const field of form.fields) {
2270
+ console.log(` ${field.name}: "${field.value}"`)
2271
+ }
2272
+ // Expected output:
2273
+ // Price: "$49.99"
2274
+ // Quantity: "3"
2275
+ // Total: "$149.97" (calculated via AFSimple_Calculate PRD)
2276
+ // Phone: "(555) 123-4567" (formatted via AFSpecial_Format)
2277
+
2278
+ await fs.writeFile(`${tmpFolder}/js-actions-filled.pdf`, filledDoc.toBytes())
2279
+ console.log('\nCreated js-actions-filled.pdf with JS-formatted values')
2280
+ ```
package/README.md CHANGED
@@ -52,7 +52,7 @@ import { PdfArray } from 'pdf-lite/core/objects/pdf-array'
52
52
  import { PdfNumber } from 'pdf-lite/core/objects/pdf-number'
53
53
 
54
54
  // Create the document
55
- const document = new PdfDocument()
55
+ const doc = new PdfDocument()
56
56
 
57
57
  // Create content stream
58
58
  const contentStream = new PdfIndirectObject({
@@ -62,12 +62,12 @@ const contentStream = new PdfIndirectObject({
62
62
  }),
63
63
  })
64
64
 
65
- // Create and commit objects
66
- document.commit(contentStream)
65
+ // Create and add objects
66
+ doc.add(contentStream)
67
67
  // ... create pages, catalog, etc.
68
68
 
69
69
  // Output the PDF
70
- console.log(document.toString())
70
+ console.log(doc.toString())
71
71
  ```
72
72
 
73
73
  ### Working with Encryption
@@ -113,7 +113,7 @@ form.setValues({
113
113
 
114
114
  // Or work with individual fields
115
115
  const field = form.fields.find((f) => f.name === 'name')
116
- field.value = 'Jane Doe'
116
+ if (field) field.value = 'Jane Doe'
117
117
 
118
118
  // Export all current values
119
119
  const values = form.exportData()
@@ -127,6 +127,14 @@ await writeFile('filled.pdf', doc.toBytes())
127
127
  Appearance streams control how form fields render visually. The library can automatically generate them when field values are set, or you can generate them manually.
128
128
 
129
129
  ```typescript
130
+ import { PdfButtonFormField } from 'pdf-lite/acroform/fields/pdf-button-form-field'
131
+ import { PdfChoiceFormField } from 'pdf-lite/acroform/fields/pdf-choice-form-field'
132
+ import { PdfAcroForm } from 'pdf-lite/acroform/pdf-acro-form'
133
+ import { PdfTextFormField } from 'pdf-lite/acroform/fields/pdf-text-form-field'
134
+
135
+ declare const form: PdfAcroForm
136
+ declare const field: PdfTextFormField
137
+
130
138
  // Auto-generate appearances when setting values (default behavior)
131
139
  field.value = 'Hello' // appearance is generated automatically
132
140
 
@@ -138,12 +146,16 @@ field.fontSize = 14
138
146
  field.fontName = 'Helv'
139
147
 
140
148
  // For checkbox fields
141
- const checkbox = form.fields.find((f) => f.name === 'agree')
149
+ const checkbox = form.fields.find(
150
+ (f) => f.name === 'agree',
151
+ ) as PdfButtonFormField
142
152
  checkbox.checked = true
143
153
  checkbox.generateAppearance()
144
154
 
145
155
  // For choice fields (dropdowns/listboxes)
146
- const dropdown = form.fields.find((f) => f.name === 'country')
156
+ const dropdown = form.fields.find(
157
+ (f) => f.name === 'country',
158
+ ) as PdfChoiceFormField
147
159
  dropdown.value = 'US'
148
160
  dropdown.generateAppearance()
149
161
  ```
@@ -152,6 +164,8 @@ dropdown.generateAppearance()
152
164
 
153
165
  ```typescript
154
166
  import { PdfFont } from 'pdf-lite'
167
+ import { PdfDocument } from 'pdf-lite/pdf/pdf-document'
168
+ import { readFileSync } from 'fs'
155
169
 
156
170
  // Standard PDF fonts (built into all PDF readers)
157
171
  const helvetica = PdfFont.fromStandardFont('Helvetica')
@@ -159,7 +173,6 @@ const timesBold = PdfFont.fromStandardFont('Times-Bold')
159
173
  const courier = PdfFont.fromStandardFont('Courier')
160
174
 
161
175
  // Embed custom fonts from file bytes (auto-detects TTF, OTF, WOFF)
162
- import { readFileSync } from 'fs'
163
176
  const fontData = readFileSync('MyFont.ttf')
164
177
  const customFont = PdfFont.fromBytes(fontData)
165
178
 
@@ -170,7 +183,8 @@ const font = PdfFont.HELVETICA_BOLD
170
183
  customFont.resourceName = 'F1'
171
184
 
172
185
  // Add to document
173
- document.add(customFont)
186
+ const doc = new PdfDocument()
187
+ doc.add(customFont)
174
188
  ```
175
189
 
176
190
  **Standard font names:** Helvetica, Helvetica-Bold, Helvetica-Oblique, Helvetica-BoldOblique, Times-Roman, Times-Bold, Times-Italic, Times-BoldItalic, Courier, Courier-Bold, Courier-Oblique, Courier-BoldOblique, Symbol, ZapfDingbats
@@ -289,6 +303,16 @@ Supports reading, filling, and creating AcroForm fields within PDF documents.
289
303
  - [x] Read individual field properties (name, value, type, flags)
290
304
  - [x] Hierarchical field support (parent/child/sibling fields)
291
305
 
306
+ **JavaScript actions:**
307
+
308
+ - [x] JavaScript action execution via `PdfJavaScriptEngine`
309
+ - [x] Validate, keystroke, calculate, and format action triggers
310
+ - [x] Built-in Acrobat JS functions: `util.printd`, `util.scand`, `util.printf`
311
+ - [x] `AFNumber_Format` / `AFNumber_Keystroke` — number formatting and validation
312
+ - [x] `AFDate_FormatEx` / `AFDate_KeystrokeEx` — date formatting and validation
313
+ - [x] `AFSimple_Calculate` — SUM, AVG, PRD, MIN, MAX across fields
314
+ - [x] `AFSpecial_Format` / `AFSpecial_Keystroke` — zip, SSN, phone formatting
315
+
292
316
  ### Appearance Streams
293
317
 
294
318
  Automatic generation of visual appearance streams for form fields, so filled forms render correctly in all PDF viewers without relying on `NeedAppearances`.
@@ -32,7 +32,7 @@ export class PdfButtonFormField extends PdfFormField {
32
32
  resolved = 'Off';
33
33
  }
34
34
  else {
35
- resolved = states.find((s) => s !== 'Off') ?? 'Yes';
35
+ resolved = states.find((s) => s !== 'Off') ?? strVal;
36
36
  }
37
37
  this.content.set('V', new PdfName(resolved));
38
38
  fieldParent?.content.set('V', new PdfName(resolved));
@@ -10,6 +10,8 @@ import type { PdfFieldType } from './types.js';
10
10
  import { PdfFormFieldFlags } from './pdf-form-field-flags.js';
11
11
  import { PdfDefaultResourcesDictionary } from '../../annotations/pdf-default-resources.js';
12
12
  import type { PdfAcroForm } from '../pdf-acro-form.js';
13
+ import { PdfFieldActions } from '../js/pdf-field-actions.js';
14
+ import { PdfJavaScriptAction } from '../js/pdf-javascript-action.js';
13
15
  /**
14
16
  * Abstract base form field class. Extends PdfWidgetAnnotation with form-specific properties:
15
17
  * FT, V, DA, Ff, T (name), field hierarchy (parent/children/siblings).
@@ -100,6 +102,9 @@ export declare abstract class PdfFormField extends PdfWidgetAnnotation {
100
102
  set maxLen(maxLen: number | null);
101
103
  get kids(): PdfArray<PdfObjectReference> | undefined;
102
104
  set kids(kids: PdfObjectReference[]);
105
+ private _resolveActionDict;
106
+ get actions(): PdfFieldActions | null;
107
+ get activateAction(): PdfJavaScriptAction | null;
103
108
  abstract generateAppearance(options?: {
104
109
  makeReadOnly?: boolean;
105
110
  textYOffset?: number;
@@ -12,6 +12,8 @@ import { PdfWidgetAnnotation } from '../../annotations/pdf-widget-annotation.js'
12
12
  import { PdfDefaultAppearance } from './pdf-default-appearance.js';
13
13
  import { PdfFieldType as PdfFieldTypeConst } from './types.js';
14
14
  import { PdfFormFieldFlags } from './pdf-form-field-flags.js';
15
+ import { PdfFieldActions } from '../js/pdf-field-actions.js';
16
+ import { PdfJavaScriptAction } from '../js/pdf-javascript-action.js';
15
17
  /**
16
18
  * Abstract base form field class. Extends PdfWidgetAnnotation with form-specific properties:
17
19
  * FT, V, DA, Ff, T (name), field hierarchy (parent/children/siblings).
@@ -467,6 +469,36 @@ export class PdfFormField extends PdfWidgetAnnotation {
467
469
  const kidsArray = new PdfArray(kids);
468
470
  this.content.set('Kids', kidsArray);
469
471
  }
472
+ _resolveActionDict(key) {
473
+ const entry = this.content.get(key);
474
+ if (entry instanceof PdfObjectReference) {
475
+ const resolved = entry.resolve();
476
+ if (resolved?.content instanceof PdfDictionary) {
477
+ return resolved.content;
478
+ }
479
+ }
480
+ else if (entry instanceof PdfDictionary) {
481
+ return entry;
482
+ }
483
+ return undefined;
484
+ }
485
+ get actions() {
486
+ const aaDict = this._resolveActionDict('AA');
487
+ if (!aaDict)
488
+ return null;
489
+ return aaDict.becomes(PdfFieldActions, {
490
+ activateDict: this._resolveActionDict('A'),
491
+ engine: this._form?.jsEngine,
492
+ });
493
+ }
494
+ get activateAction() {
495
+ const aDict = this._resolveActionDict('A');
496
+ if (!aDict)
497
+ return null;
498
+ return aDict.becomes(PdfJavaScriptAction, {
499
+ engine: this._form?.jsEngine,
500
+ });
501
+ }
470
502
  setAppearanceStream(stream) {
471
503
  this.appearanceStreamDict ||= new PdfDictionary();
472
504
  if (stream instanceof PdfIndirectObject) {
@@ -487,7 +519,7 @@ export class PdfFormField extends PdfWidgetAnnotation {
487
519
  get appearanceStates() {
488
520
  const n = this.appearanceStreamDict?.get('N');
489
521
  if (n instanceof PdfDictionary) {
490
- return Array.from(n.entries(), ([key]) => key);
522
+ return n.keys().map((k) => k.value);
491
523
  }
492
524
  return [];
493
525
  }
@@ -2,3 +2,4 @@ export * from './pdf-acro-form.js';
2
2
  export * from './fields/index.js';
3
3
  export * from './appearance/index.js';
4
4
  export * from './xfa/index.js';
5
+ export * from './js/index.js';
@@ -2,3 +2,4 @@ export * from './pdf-acro-form.js';
2
2
  export * from './fields/index.js';
3
3
  export * from './appearance/index.js';
4
4
  export * from './xfa/index.js';
5
+ export * from './js/index.js';
@@ -0,0 +1,5 @@
1
+ export * from './pdf-js-engine.js';
2
+ export * from './pdf-js-engine-impl.js';
3
+ export * from './pdf-js-builtins.js';
4
+ export * from './pdf-javascript-action.js';
5
+ export * from './pdf-field-actions.js';
@@ -0,0 +1,5 @@
1
+ export * from './pdf-js-engine.js';
2
+ export * from './pdf-js-engine-impl.js';
3
+ export * from './pdf-js-builtins.js';
4
+ export * from './pdf-javascript-action.js';
5
+ export * from './pdf-field-actions.js';
@@ -0,0 +1,17 @@
1
+ import { PdfDictionary } from '../../core/objects/pdf-dictionary.js';
2
+ import { PdfJavaScriptAction } from './pdf-javascript-action.js';
3
+ import type { PdfJsEngine } from './pdf-js-engine.js';
4
+ export declare class PdfFieldActions extends PdfDictionary {
5
+ private readonly activateDict?;
6
+ readonly engine?: PdfJsEngine;
7
+ constructor(dict: PdfDictionary, options?: {
8
+ activateDict?: PdfDictionary;
9
+ engine?: PdfJsEngine;
10
+ });
11
+ private _resolve;
12
+ get keystroke(): PdfJavaScriptAction | null;
13
+ get validate(): PdfJavaScriptAction | null;
14
+ get calculate(): PdfJavaScriptAction | null;
15
+ get format(): PdfJavaScriptAction | null;
16
+ get activate(): PdfJavaScriptAction | null;
17
+ }
@@ -0,0 +1,52 @@
1
+ import { PdfDictionary } from '../../core/objects/pdf-dictionary.js';
2
+ import { PdfObjectReference } from '../../core/objects/pdf-object-reference.js';
3
+ import { PdfJavaScriptAction } from './pdf-javascript-action.js';
4
+ export class PdfFieldActions extends PdfDictionary {
5
+ activateDict;
6
+ engine;
7
+ constructor(dict, options) {
8
+ super();
9
+ this.copyFrom(dict);
10
+ this.activateDict = options?.activateDict;
11
+ this.engine = options?.engine;
12
+ }
13
+ _resolve(key) {
14
+ const entry = this.get(key);
15
+ if (!entry)
16
+ return null;
17
+ let actionDict;
18
+ if (entry instanceof PdfObjectReference) {
19
+ const resolved = entry.resolve();
20
+ if (resolved?.content instanceof PdfDictionary) {
21
+ actionDict = resolved.content;
22
+ }
23
+ }
24
+ else if (entry instanceof PdfDictionary) {
25
+ actionDict = entry;
26
+ }
27
+ if (!actionDict)
28
+ return null;
29
+ return actionDict.becomes(PdfJavaScriptAction, {
30
+ engine: this.engine,
31
+ });
32
+ }
33
+ get keystroke() {
34
+ return this._resolve('K');
35
+ }
36
+ get validate() {
37
+ return this._resolve('V');
38
+ }
39
+ get calculate() {
40
+ return this._resolve('C');
41
+ }
42
+ get format() {
43
+ return this._resolve('F');
44
+ }
45
+ get activate() {
46
+ if (!this.activateDict)
47
+ return null;
48
+ return this.activateDict.becomes(PdfJavaScriptAction, {
49
+ engine: this.engine,
50
+ });
51
+ }
52
+ }
@@ -0,0 +1,17 @@
1
+ import { PdfDictionary } from '../../core/objects/pdf-dictionary.js';
2
+ import { PdfString } from '../../core/objects/pdf-string.js';
3
+ import { PdfStream } from '../../core/objects/pdf-stream.js';
4
+ import { PdfObjectReference } from '../../core/objects/pdf-object-reference.js';
5
+ import { PdfName } from '../../core/objects/pdf-name.js';
6
+ import type { PdfJsEngine, PdfJsEvent } from './pdf-js-engine.js';
7
+ export declare class PdfJavaScriptAction extends PdfDictionary<{
8
+ S?: PdfName;
9
+ JS?: PdfString | PdfStream | PdfObjectReference;
10
+ }> {
11
+ engine?: PdfJsEngine;
12
+ constructor(dict: PdfDictionary, options?: {
13
+ engine?: PdfJsEngine;
14
+ });
15
+ get code(): string | null;
16
+ execute(event: PdfJsEvent): void;
17
+ }
@@ -0,0 +1,38 @@
1
+ import { PdfDictionary } from '../../core/objects/pdf-dictionary.js';
2
+ import { PdfString } from '../../core/objects/pdf-string.js';
3
+ import { PdfStream } from '../../core/objects/pdf-stream.js';
4
+ import { PdfObjectReference } from '../../core/objects/pdf-object-reference.js';
5
+ import { bytesToString } from '../../utils/bytesToString.js';
6
+ export class PdfJavaScriptAction extends PdfDictionary {
7
+ engine;
8
+ constructor(dict, options) {
9
+ super();
10
+ this.copyFrom(dict);
11
+ this.engine = options?.engine;
12
+ }
13
+ get code() {
14
+ const js = this.get('JS');
15
+ if (js instanceof PdfString) {
16
+ return js.value;
17
+ }
18
+ if (js instanceof PdfObjectReference) {
19
+ const resolved = js.resolve();
20
+ if (resolved?.content instanceof PdfStream) {
21
+ return bytesToString(resolved.content.data);
22
+ }
23
+ if (resolved?.content instanceof PdfString) {
24
+ return resolved.content.value;
25
+ }
26
+ }
27
+ if (js instanceof PdfStream) {
28
+ return bytesToString(js.data);
29
+ }
30
+ return null;
31
+ }
32
+ execute(event) {
33
+ const code = this.code;
34
+ if (code && this.engine) {
35
+ this.engine.execute(code, event);
36
+ }
37
+ }
38
+ }
@@ -0,0 +1,12 @@
1
+ import type { PdfJsEvent } from './pdf-js-engine.js';
2
+ export declare function printd(fmt: string, date: Date): string;
3
+ export declare function scand(fmt: string, str: string): Date | null;
4
+ export declare function printf(fmt: string, ...args: unknown[]): string;
5
+ export declare const util: {
6
+ printd: typeof printd;
7
+ scand: typeof scand;
8
+ printf: typeof printf;
9
+ };
10
+ type GetFieldValue = (name: string) => string;
11
+ export declare function createBuiltins(event: PdfJsEvent, getFieldValue?: GetFieldValue): Record<string, unknown>;
12
+ export {};