pdf-oxide 0.3.24
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/README.md +218 -0
- package/binding.gyp +35 -0
- package/package.json +78 -0
- package/src/builders/annotation-builder.ts +367 -0
- package/src/builders/conversion-options-builder.ts +257 -0
- package/src/builders/index.ts +12 -0
- package/src/builders/metadata-builder.ts +317 -0
- package/src/builders/pdf-builder.ts +386 -0
- package/src/builders/search-options-builder.ts +151 -0
- package/src/document-editor-manager.ts +318 -0
- package/src/errors.ts +1629 -0
- package/src/form-field-manager.ts +666 -0
- package/src/hybrid-ml-manager.ts +283 -0
- package/src/index.ts +453 -0
- package/src/managers/accessibility-manager.ts +338 -0
- package/src/managers/annotation-manager.ts +439 -0
- package/src/managers/barcode-manager.ts +235 -0
- package/src/managers/batch-manager.ts +533 -0
- package/src/managers/cache-manager.ts +486 -0
- package/src/managers/compliance-manager.ts +375 -0
- package/src/managers/content-manager.ts +339 -0
- package/src/managers/document-utility-manager.ts +922 -0
- package/src/managers/dom-pdf-creator.ts +365 -0
- package/src/managers/editing-manager.ts +514 -0
- package/src/managers/enterprise-manager.ts +478 -0
- package/src/managers/extended-managers.ts +437 -0
- package/src/managers/extraction-manager.ts +583 -0
- package/src/managers/final-utilities.ts +429 -0
- package/src/managers/hybrid-ml-advanced.ts +479 -0
- package/src/managers/index.ts +239 -0
- package/src/managers/layer-manager.ts +500 -0
- package/src/managers/metadata-manager.ts +303 -0
- package/src/managers/ocr-manager.ts +756 -0
- package/src/managers/optimization-manager.ts +262 -0
- package/src/managers/outline-manager.ts +196 -0
- package/src/managers/page-manager.ts +289 -0
- package/src/managers/pattern-detection.ts +440 -0
- package/src/managers/rendering-manager.ts +863 -0
- package/src/managers/search-manager.ts +385 -0
- package/src/managers/security-manager.ts +345 -0
- package/src/managers/signature-manager.ts +1664 -0
- package/src/managers/streams.ts +618 -0
- package/src/managers/xfa-manager.ts +500 -0
- package/src/pdf-creator-manager.ts +494 -0
- package/src/properties.ts +522 -0
- package/src/result-accessors-manager.ts +867 -0
- package/src/tests/advanced-features.test.ts +414 -0
- package/src/tests/advanced.test.ts +266 -0
- package/src/tests/extended-managers.test.ts +316 -0
- package/src/tests/final-utilities.test.ts +455 -0
- package/src/tests/foundation.test.ts +315 -0
- package/src/tests/high-demand.test.ts +257 -0
- package/src/tests/specialized.test.ts +97 -0
- package/src/thumbnail-manager.ts +272 -0
- package/src/types/common.ts +142 -0
- package/src/types/document-types.ts +457 -0
- package/src/types/index.ts +6 -0
- package/src/types/manager-types.ts +284 -0
- package/src/types/native-bindings.ts +517 -0
- package/src/workers/index.ts +7 -0
- package/src/workers/pool.ts +274 -0
- package/src/workers/worker.ts +131 -0
|
@@ -0,0 +1,514 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EditingManager - Document Editing Manager for redaction and flattening operations
|
|
3
|
+
*
|
|
4
|
+
* Provides PDF document editing capabilities:
|
|
5
|
+
* - Content redaction (add, apply, count redaction areas)
|
|
6
|
+
* - Metadata scrubbing (remove Info, XMP, JavaScript)
|
|
7
|
+
* - Form flattening (all pages or single page)
|
|
8
|
+
* - Annotation flattening (all pages or single page)
|
|
9
|
+
*
|
|
10
|
+
* Uses native FFI functions:
|
|
11
|
+
* - pdf_redaction_add, pdf_redaction_apply, pdf_redaction_scrub_metadata, pdf_redaction_count
|
|
12
|
+
* - pdf_document_editor_flatten_forms, pdf_document_editor_flatten_forms_page
|
|
13
|
+
* - pdf_document_editor_flatten_annotations, pdf_document_editor_flatten_annotations_page
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { EventEmitter } from 'events';
|
|
17
|
+
import { mapFfiErrorCode } from '../errors';
|
|
18
|
+
|
|
19
|
+
// =============================================================================
|
|
20
|
+
// Type Definitions
|
|
21
|
+
// =============================================================================
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Rectangle coordinates for a redaction area.
|
|
25
|
+
*/
|
|
26
|
+
export interface RedactionRect {
|
|
27
|
+
x1: number;
|
|
28
|
+
y1: number;
|
|
29
|
+
x2: number;
|
|
30
|
+
y2: number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* RGB color specification (values 0.0-1.0).
|
|
35
|
+
*/
|
|
36
|
+
export interface RgbColor {
|
|
37
|
+
r: number;
|
|
38
|
+
g: number;
|
|
39
|
+
b: number;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Options for applying redactions.
|
|
44
|
+
*/
|
|
45
|
+
export interface ApplyRedactionsOptions {
|
|
46
|
+
/** Whether to also scrub document metadata when applying redactions. */
|
|
47
|
+
scrubMetadata?: boolean;
|
|
48
|
+
/** Default fill color for redacted areas. Defaults to black (0, 0, 0). */
|
|
49
|
+
fillColor?: RgbColor;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Options for scrubbing document metadata.
|
|
54
|
+
*/
|
|
55
|
+
export interface ScrubMetadataOptions {
|
|
56
|
+
/** Remove /Info dictionary entries (Title, Author, etc.). Default: true */
|
|
57
|
+
removeInfo?: boolean;
|
|
58
|
+
/** Remove XMP metadata stream. Default: true */
|
|
59
|
+
removeXmp?: boolean;
|
|
60
|
+
/** Remove JavaScript actions. Default: true */
|
|
61
|
+
removeJs?: boolean;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// =============================================================================
|
|
65
|
+
// Canonical EditingManager
|
|
66
|
+
// =============================================================================
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Manages document editing operations including redaction and flattening.
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```typescript
|
|
73
|
+
* import { EditingManager } from 'pdf_oxide';
|
|
74
|
+
*
|
|
75
|
+
* const editor = new EditingManager(document);
|
|
76
|
+
*
|
|
77
|
+
* // Add redaction areas
|
|
78
|
+
* editor.addRedaction(0, { x1: 100, y1: 200, x2: 300, y2: 250 });
|
|
79
|
+
* editor.addRedaction(0, { x1: 50, y1: 400, x2: 200, y2: 450 }, { r: 0, g: 0, b: 0 });
|
|
80
|
+
*
|
|
81
|
+
* // Apply all queued redactions
|
|
82
|
+
* const count = editor.applyRedactions({ scrubMetadata: true });
|
|
83
|
+
* console.log(`Applied ${count} redactions`);
|
|
84
|
+
*
|
|
85
|
+
* // Flatten forms and annotations
|
|
86
|
+
* editor.flattenForms();
|
|
87
|
+
* editor.flattenAnnotations();
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
export class EditingManager extends EventEmitter {
|
|
91
|
+
private document: any;
|
|
92
|
+
private native: any;
|
|
93
|
+
|
|
94
|
+
constructor(document: any) {
|
|
95
|
+
super();
|
|
96
|
+
this.document = document;
|
|
97
|
+
try {
|
|
98
|
+
this.native = require('../../index.node');
|
|
99
|
+
} catch {
|
|
100
|
+
this.native = null;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// ===========================================================================
|
|
105
|
+
// Redaction Operations
|
|
106
|
+
// ===========================================================================
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Adds a redaction area to the document.
|
|
110
|
+
*
|
|
111
|
+
* Queues a rectangular region on a page for redaction. The content within
|
|
112
|
+
* the rectangle will be permanently removed when {@link applyRedactions}
|
|
113
|
+
* is called.
|
|
114
|
+
*
|
|
115
|
+
* @param page - Zero-based page index
|
|
116
|
+
* @param rect - Rectangle coordinates defining the redaction area
|
|
117
|
+
* @param color - Optional fill color for the redacted area (defaults to black)
|
|
118
|
+
* @throws {PdfException} If the document handle is invalid or page is out of range
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* ```typescript
|
|
122
|
+
* // Redact a region with default black fill
|
|
123
|
+
* editor.addRedaction(0, { x1: 100, y1: 200, x2: 300, y2: 250 });
|
|
124
|
+
*
|
|
125
|
+
* // Redact with a custom gray fill
|
|
126
|
+
* editor.addRedaction(1, { x1: 50, y1: 100, x2: 200, y2: 150 }, { r: 0.5, g: 0.5, b: 0.5 });
|
|
127
|
+
* ```
|
|
128
|
+
*/
|
|
129
|
+
addRedaction(
|
|
130
|
+
page: number,
|
|
131
|
+
rect: RedactionRect,
|
|
132
|
+
color?: RgbColor
|
|
133
|
+
): void {
|
|
134
|
+
const fillColor = color ?? { r: 0, g: 0, b: 0 };
|
|
135
|
+
|
|
136
|
+
if (this.native?.pdf_redaction_add) {
|
|
137
|
+
const errorCode = { value: 0 };
|
|
138
|
+
const result = this.native.pdf_redaction_add(
|
|
139
|
+
this.document?.handle ?? this.document,
|
|
140
|
+
page,
|
|
141
|
+
rect.x1,
|
|
142
|
+
rect.y1,
|
|
143
|
+
rect.x2,
|
|
144
|
+
rect.y2,
|
|
145
|
+
fillColor.r,
|
|
146
|
+
fillColor.g,
|
|
147
|
+
fillColor.b,
|
|
148
|
+
errorCode
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
if (result < 0 && errorCode.value !== 0) {
|
|
152
|
+
throw mapFfiErrorCode(errorCode.value, 'Failed to add redaction area');
|
|
153
|
+
}
|
|
154
|
+
} else if (this.document?.addRedaction) {
|
|
155
|
+
this.document.addRedaction(page, rect, fillColor);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
this.emit('redactionAdded', { page, rect, color: fillColor });
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Applies all queued redactions to the document.
|
|
163
|
+
*
|
|
164
|
+
* Permanently removes content within all previously added redaction
|
|
165
|
+
* rectangles. Optionally scrubs document metadata and applies a
|
|
166
|
+
* fill color overlay.
|
|
167
|
+
*
|
|
168
|
+
* @param options - Options controlling redaction behavior
|
|
169
|
+
* @returns Number of redactions applied
|
|
170
|
+
* @throws {PdfException} If redaction application fails
|
|
171
|
+
*
|
|
172
|
+
* @example
|
|
173
|
+
* ```typescript
|
|
174
|
+
* // Apply with metadata scrubbing
|
|
175
|
+
* const count = editor.applyRedactions({ scrubMetadata: true });
|
|
176
|
+
*
|
|
177
|
+
* // Apply with custom fill color
|
|
178
|
+
* const count = editor.applyRedactions({
|
|
179
|
+
* fillColor: { r: 1.0, g: 1.0, b: 1.0 }
|
|
180
|
+
* });
|
|
181
|
+
* ```
|
|
182
|
+
*/
|
|
183
|
+
applyRedactions(options?: ApplyRedactionsOptions): number {
|
|
184
|
+
const scrubMetadata = options?.scrubMetadata ?? false;
|
|
185
|
+
const fillColor = options?.fillColor ?? { r: 0, g: 0, b: 0 };
|
|
186
|
+
|
|
187
|
+
if (this.native?.pdf_redaction_apply) {
|
|
188
|
+
const errorCode = { value: 0 };
|
|
189
|
+
const result = this.native.pdf_redaction_apply(
|
|
190
|
+
this.document?.handle ?? this.document,
|
|
191
|
+
scrubMetadata,
|
|
192
|
+
fillColor.r,
|
|
193
|
+
fillColor.g,
|
|
194
|
+
fillColor.b,
|
|
195
|
+
errorCode
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
if (result < 0 && errorCode.value !== 0) {
|
|
199
|
+
throw mapFfiErrorCode(errorCode.value, 'Failed to apply redactions');
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
this.emit('redactionsApplied', { count: result, scrubMetadata });
|
|
203
|
+
return result;
|
|
204
|
+
} else if (this.document?.applyRedactions) {
|
|
205
|
+
const count = this.document.applyRedactions(options);
|
|
206
|
+
this.emit('redactionsApplied', { count, scrubMetadata });
|
|
207
|
+
return count ?? 0;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return 0;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Scrubs sensitive metadata from the document.
|
|
215
|
+
*
|
|
216
|
+
* Removes document metadata fields that may contain sensitive information,
|
|
217
|
+
* such as author names, creation tools, and JavaScript.
|
|
218
|
+
*
|
|
219
|
+
* @param options - Options controlling which metadata to remove
|
|
220
|
+
* @throws {PdfException} If metadata scrubbing fails
|
|
221
|
+
*
|
|
222
|
+
* @example
|
|
223
|
+
* ```typescript
|
|
224
|
+
* // Remove all metadata
|
|
225
|
+
* editor.scrubMetadata();
|
|
226
|
+
*
|
|
227
|
+
* // Remove only Info dictionary and JavaScript
|
|
228
|
+
* editor.scrubMetadata({ removeInfo: true, removeXmp: false, removeJs: true });
|
|
229
|
+
* ```
|
|
230
|
+
*/
|
|
231
|
+
scrubMetadata(options?: ScrubMetadataOptions): void {
|
|
232
|
+
const removeInfo = options?.removeInfo ?? true;
|
|
233
|
+
const removeXmp = options?.removeXmp ?? true;
|
|
234
|
+
const removeJs = options?.removeJs ?? true;
|
|
235
|
+
|
|
236
|
+
if (this.native?.pdf_redaction_scrub_metadata) {
|
|
237
|
+
const errorCode = { value: 0 };
|
|
238
|
+
const result = this.native.pdf_redaction_scrub_metadata(
|
|
239
|
+
this.document?.handle ?? this.document,
|
|
240
|
+
removeInfo,
|
|
241
|
+
removeXmp,
|
|
242
|
+
removeJs,
|
|
243
|
+
errorCode
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
if (result < 0 && errorCode.value !== 0) {
|
|
247
|
+
throw mapFfiErrorCode(errorCode.value, 'Failed to scrub metadata');
|
|
248
|
+
}
|
|
249
|
+
} else if (this.document?.scrubMetadata) {
|
|
250
|
+
this.document.scrubMetadata(options);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
this.emit('metadataScrubbed', { removeInfo, removeXmp, removeJs });
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Gets the number of queued (pending) redaction areas.
|
|
258
|
+
*
|
|
259
|
+
* @returns Number of redaction areas queued for application
|
|
260
|
+
* @throws {PdfException} If the document handle is invalid
|
|
261
|
+
*
|
|
262
|
+
* @example
|
|
263
|
+
* ```typescript
|
|
264
|
+
* editor.addRedaction(0, { x1: 10, y1: 20, x2: 100, y2: 50 });
|
|
265
|
+
* editor.addRedaction(1, { x1: 30, y1: 40, x2: 200, y2: 80 });
|
|
266
|
+
* console.log(editor.getRedactionCount()); // 2
|
|
267
|
+
* ```
|
|
268
|
+
*/
|
|
269
|
+
getRedactionCount(): number {
|
|
270
|
+
if (this.native?.pdf_redaction_count) {
|
|
271
|
+
const errorCode = { value: 0 };
|
|
272
|
+
const result = this.native.pdf_redaction_count(
|
|
273
|
+
this.document?.handle ?? this.document,
|
|
274
|
+
errorCode
|
|
275
|
+
);
|
|
276
|
+
|
|
277
|
+
if (result < 0 && errorCode.value !== 0) {
|
|
278
|
+
throw mapFfiErrorCode(errorCode.value, 'Failed to get redaction count');
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return result;
|
|
282
|
+
} else if (this.document?.getRedactionCount) {
|
|
283
|
+
return this.document.getRedactionCount() ?? 0;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
return 0;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// ===========================================================================
|
|
290
|
+
// Form Flattening Operations
|
|
291
|
+
// ===========================================================================
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Flattens all form fields in the document.
|
|
295
|
+
*
|
|
296
|
+
* Renders form field widgets into page content and removes the AcroForm
|
|
297
|
+
* dictionary. After flattening, form fields become static content and
|
|
298
|
+
* can no longer be edited interactively.
|
|
299
|
+
*
|
|
300
|
+
* @throws {PdfException} If flattening fails
|
|
301
|
+
*
|
|
302
|
+
* @example
|
|
303
|
+
* ```typescript
|
|
304
|
+
* editor.flattenForms();
|
|
305
|
+
* ```
|
|
306
|
+
*/
|
|
307
|
+
flattenForms(): void {
|
|
308
|
+
if (this.native?.pdf_document_editor_flatten_forms) {
|
|
309
|
+
const errorCode = { value: 0 };
|
|
310
|
+
const result = this.native.pdf_document_editor_flatten_forms(
|
|
311
|
+
this.document?.handle ?? this.document,
|
|
312
|
+
errorCode
|
|
313
|
+
);
|
|
314
|
+
|
|
315
|
+
if (result < 0 && errorCode.value !== 0) {
|
|
316
|
+
throw mapFfiErrorCode(errorCode.value, 'Failed to flatten forms');
|
|
317
|
+
}
|
|
318
|
+
} else if (this.document?.flattenForms) {
|
|
319
|
+
this.document.flattenForms();
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
this.emit('formsFlattened');
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Flattens form fields on a specific page.
|
|
327
|
+
*
|
|
328
|
+
* Only flattens form field widgets located on the specified page,
|
|
329
|
+
* leaving form fields on other pages editable.
|
|
330
|
+
*
|
|
331
|
+
* @param page - Zero-based page index
|
|
332
|
+
* @throws {PdfException} If flattening fails or page is out of range
|
|
333
|
+
*
|
|
334
|
+
* @example
|
|
335
|
+
* ```typescript
|
|
336
|
+
* // Flatten forms on first page only
|
|
337
|
+
* editor.flattenFormsPage(0);
|
|
338
|
+
* ```
|
|
339
|
+
*/
|
|
340
|
+
flattenFormsPage(page: number): void {
|
|
341
|
+
if (this.native?.pdf_document_editor_flatten_forms_page) {
|
|
342
|
+
const errorCode = { value: 0 };
|
|
343
|
+
const result = this.native.pdf_document_editor_flatten_forms_page(
|
|
344
|
+
this.document?.handle ?? this.document,
|
|
345
|
+
page,
|
|
346
|
+
errorCode
|
|
347
|
+
);
|
|
348
|
+
|
|
349
|
+
if (result < 0 && errorCode.value !== 0) {
|
|
350
|
+
throw mapFfiErrorCode(errorCode.value, `Failed to flatten forms on page ${page}`);
|
|
351
|
+
}
|
|
352
|
+
} else if (this.document?.flattenFormsPage) {
|
|
353
|
+
this.document.flattenFormsPage(page);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
this.emit('formsPageFlattened', { page });
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// ===========================================================================
|
|
360
|
+
// Annotation Flattening Operations
|
|
361
|
+
// ===========================================================================
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Flattens all annotations in the document.
|
|
365
|
+
*
|
|
366
|
+
* Renders annotations into page content and removes them from
|
|
367
|
+
* annotation arrays. After flattening, annotations become static
|
|
368
|
+
* content and can no longer be edited or deleted.
|
|
369
|
+
*
|
|
370
|
+
* @throws {PdfException} If flattening fails
|
|
371
|
+
*
|
|
372
|
+
* @example
|
|
373
|
+
* ```typescript
|
|
374
|
+
* editor.flattenAnnotations();
|
|
375
|
+
* ```
|
|
376
|
+
*/
|
|
377
|
+
flattenAnnotations(): void {
|
|
378
|
+
if (this.native?.pdf_document_editor_flatten_annotations) {
|
|
379
|
+
const errorCode = { value: 0 };
|
|
380
|
+
const result = this.native.pdf_document_editor_flatten_annotations(
|
|
381
|
+
this.document?.handle ?? this.document,
|
|
382
|
+
errorCode
|
|
383
|
+
);
|
|
384
|
+
|
|
385
|
+
if (result < 0 && errorCode.value !== 0) {
|
|
386
|
+
throw mapFfiErrorCode(errorCode.value, 'Failed to flatten annotations');
|
|
387
|
+
}
|
|
388
|
+
} else if (this.document?.flattenAnnotations) {
|
|
389
|
+
this.document.flattenAnnotations();
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
this.emit('annotationsFlattened');
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Flattens annotations on a specific page.
|
|
397
|
+
*
|
|
398
|
+
* Only flattens annotations located on the specified page,
|
|
399
|
+
* leaving annotations on other pages editable.
|
|
400
|
+
*
|
|
401
|
+
* @param page - Zero-based page index
|
|
402
|
+
* @throws {PdfException} If flattening fails or page is out of range
|
|
403
|
+
*
|
|
404
|
+
* @example
|
|
405
|
+
* ```typescript
|
|
406
|
+
* // Flatten annotations on page 2
|
|
407
|
+
* editor.flattenAnnotationsPage(1);
|
|
408
|
+
* ```
|
|
409
|
+
*/
|
|
410
|
+
flattenAnnotationsPage(page: number): void {
|
|
411
|
+
if (this.native?.pdf_document_editor_flatten_annotations_page) {
|
|
412
|
+
const errorCode = { value: 0 };
|
|
413
|
+
const result = this.native.pdf_document_editor_flatten_annotations_page(
|
|
414
|
+
this.document?.handle ?? this.document,
|
|
415
|
+
page,
|
|
416
|
+
errorCode
|
|
417
|
+
);
|
|
418
|
+
|
|
419
|
+
if (result < 0 && errorCode.value !== 0) {
|
|
420
|
+
throw mapFfiErrorCode(errorCode.value, `Failed to flatten annotations on page ${page}`);
|
|
421
|
+
}
|
|
422
|
+
} else if (this.document?.flattenAnnotationsPage) {
|
|
423
|
+
this.document.flattenAnnotationsPage(page);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
this.emit('annotationsPageFlattened', { page });
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// ===========================================================================
|
|
430
|
+
// Form Data Import/Export
|
|
431
|
+
// ===========================================================================
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Import form data from a file (FDF or XFDF, auto-detected by extension).
|
|
435
|
+
* @param filePath Path to the FDF or XFDF file
|
|
436
|
+
* @returns Number of fields imported
|
|
437
|
+
*/
|
|
438
|
+
importFormDataFromFile(filePath: string): number {
|
|
439
|
+
if (this.native?.pdf_document_import_form_data) {
|
|
440
|
+
const errorCode = { value: 0 };
|
|
441
|
+
const count = this.native.pdf_document_import_form_data(this.document?.handle ?? this.document, filePath, errorCode);
|
|
442
|
+
if (errorCode.value !== 0) {
|
|
443
|
+
throw mapFfiErrorCode(errorCode.value, `Failed to import form data from ${filePath}`);
|
|
444
|
+
}
|
|
445
|
+
return count;
|
|
446
|
+
}
|
|
447
|
+
throw new Error('Form data import not available');
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Import FDF form data from in-memory bytes.
|
|
452
|
+
* @param data FDF data bytes
|
|
453
|
+
* @returns Number of fields imported
|
|
454
|
+
*/
|
|
455
|
+
importFdfBytes(data: Buffer): number {
|
|
456
|
+
if (this.native?.pdf_editor_import_fdf_bytes) {
|
|
457
|
+
const errorCode = { value: 0 };
|
|
458
|
+
const count = this.native.pdf_editor_import_fdf_bytes(this.document?.handle ?? this.document, data, data.length, errorCode);
|
|
459
|
+
if (errorCode.value !== 0) {
|
|
460
|
+
throw mapFfiErrorCode(errorCode.value, 'Failed to import FDF bytes');
|
|
461
|
+
}
|
|
462
|
+
return count;
|
|
463
|
+
}
|
|
464
|
+
throw new Error('FDF byte import not available');
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Import XFDF form data from in-memory bytes.
|
|
469
|
+
* @param data XFDF data bytes
|
|
470
|
+
* @returns Number of fields imported
|
|
471
|
+
*/
|
|
472
|
+
importXfdfBytes(data: Buffer): number {
|
|
473
|
+
if (this.native?.pdf_editor_import_xfdf_bytes) {
|
|
474
|
+
const errorCode = { value: 0 };
|
|
475
|
+
const count = this.native.pdf_editor_import_xfdf_bytes(this.document?.handle ?? this.document, data, data.length, errorCode);
|
|
476
|
+
if (errorCode.value !== 0) {
|
|
477
|
+
throw mapFfiErrorCode(errorCode.value, 'Failed to import XFDF bytes');
|
|
478
|
+
}
|
|
479
|
+
return count;
|
|
480
|
+
}
|
|
481
|
+
throw new Error('XFDF byte import not available');
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* Export form data to in-memory bytes.
|
|
486
|
+
* @param format 0 for FDF, 1 for XFDF
|
|
487
|
+
* @returns Exported form data bytes
|
|
488
|
+
*/
|
|
489
|
+
exportFormDataToBytes(format: 0 | 1 = 0): Buffer {
|
|
490
|
+
if (this.native?.pdf_document_export_form_data_to_bytes) {
|
|
491
|
+
const errorCode = { value: 0 };
|
|
492
|
+
const outLen = { value: 0 };
|
|
493
|
+
const ptr = this.native.pdf_document_export_form_data_to_bytes(this.document?.handle ?? this.document, format, outLen, errorCode);
|
|
494
|
+
if (errorCode.value !== 0 || !ptr) {
|
|
495
|
+
throw mapFfiErrorCode(errorCode.value, 'Failed to export form data');
|
|
496
|
+
}
|
|
497
|
+
return Buffer.from(ptr, 0, outLen.value);
|
|
498
|
+
}
|
|
499
|
+
throw new Error('Form data export not available');
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
// ===========================================================================
|
|
503
|
+
// Lifecycle
|
|
504
|
+
// ===========================================================================
|
|
505
|
+
|
|
506
|
+
/**
|
|
507
|
+
* Releases resources held by this manager.
|
|
508
|
+
*/
|
|
509
|
+
destroy(): void {
|
|
510
|
+
this.removeAllListeners();
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
export default EditingManager;
|