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.
Files changed (62) hide show
  1. package/README.md +218 -0
  2. package/binding.gyp +35 -0
  3. package/package.json +78 -0
  4. package/src/builders/annotation-builder.ts +367 -0
  5. package/src/builders/conversion-options-builder.ts +257 -0
  6. package/src/builders/index.ts +12 -0
  7. package/src/builders/metadata-builder.ts +317 -0
  8. package/src/builders/pdf-builder.ts +386 -0
  9. package/src/builders/search-options-builder.ts +151 -0
  10. package/src/document-editor-manager.ts +318 -0
  11. package/src/errors.ts +1629 -0
  12. package/src/form-field-manager.ts +666 -0
  13. package/src/hybrid-ml-manager.ts +283 -0
  14. package/src/index.ts +453 -0
  15. package/src/managers/accessibility-manager.ts +338 -0
  16. package/src/managers/annotation-manager.ts +439 -0
  17. package/src/managers/barcode-manager.ts +235 -0
  18. package/src/managers/batch-manager.ts +533 -0
  19. package/src/managers/cache-manager.ts +486 -0
  20. package/src/managers/compliance-manager.ts +375 -0
  21. package/src/managers/content-manager.ts +339 -0
  22. package/src/managers/document-utility-manager.ts +922 -0
  23. package/src/managers/dom-pdf-creator.ts +365 -0
  24. package/src/managers/editing-manager.ts +514 -0
  25. package/src/managers/enterprise-manager.ts +478 -0
  26. package/src/managers/extended-managers.ts +437 -0
  27. package/src/managers/extraction-manager.ts +583 -0
  28. package/src/managers/final-utilities.ts +429 -0
  29. package/src/managers/hybrid-ml-advanced.ts +479 -0
  30. package/src/managers/index.ts +239 -0
  31. package/src/managers/layer-manager.ts +500 -0
  32. package/src/managers/metadata-manager.ts +303 -0
  33. package/src/managers/ocr-manager.ts +756 -0
  34. package/src/managers/optimization-manager.ts +262 -0
  35. package/src/managers/outline-manager.ts +196 -0
  36. package/src/managers/page-manager.ts +289 -0
  37. package/src/managers/pattern-detection.ts +440 -0
  38. package/src/managers/rendering-manager.ts +863 -0
  39. package/src/managers/search-manager.ts +385 -0
  40. package/src/managers/security-manager.ts +345 -0
  41. package/src/managers/signature-manager.ts +1664 -0
  42. package/src/managers/streams.ts +618 -0
  43. package/src/managers/xfa-manager.ts +500 -0
  44. package/src/pdf-creator-manager.ts +494 -0
  45. package/src/properties.ts +522 -0
  46. package/src/result-accessors-manager.ts +867 -0
  47. package/src/tests/advanced-features.test.ts +414 -0
  48. package/src/tests/advanced.test.ts +266 -0
  49. package/src/tests/extended-managers.test.ts +316 -0
  50. package/src/tests/final-utilities.test.ts +455 -0
  51. package/src/tests/foundation.test.ts +315 -0
  52. package/src/tests/high-demand.test.ts +257 -0
  53. package/src/tests/specialized.test.ts +97 -0
  54. package/src/thumbnail-manager.ts +272 -0
  55. package/src/types/common.ts +142 -0
  56. package/src/types/document-types.ts +457 -0
  57. package/src/types/index.ts +6 -0
  58. package/src/types/manager-types.ts +284 -0
  59. package/src/types/native-bindings.ts +517 -0
  60. package/src/workers/index.ts +7 -0
  61. package/src/workers/pool.ts +274 -0
  62. package/src/workers/worker.ts +131 -0
@@ -0,0 +1,478 @@
1
+ /**
2
+ * EnterpriseManager - Enterprise PDF Operations
3
+ *
4
+ * Provides enterprise-level PDF operations including:
5
+ * - Bates numbering (standard and advanced)
6
+ * - Page-level and document-level comparison
7
+ * - Header and footer stamping
8
+ *
9
+ * @since 1.0.0
10
+ */
11
+
12
+ import { EventEmitter } from 'events';
13
+ import { mapFfiErrorCode, PdfException } from '../errors';
14
+
15
+ // =============================================================================
16
+ // Enums
17
+ // =============================================================================
18
+
19
+ /**
20
+ * Position for Bates number placement.
21
+ */
22
+ export enum BatesPosition {
23
+ TOP_LEFT = 0,
24
+ TOP_CENTER = 1,
25
+ TOP_RIGHT = 2,
26
+ BOTTOM_LEFT = 3,
27
+ BOTTOM_CENTER = 4,
28
+ BOTTOM_RIGHT = 5,
29
+ }
30
+
31
+ /**
32
+ * Text alignment for header/footer stamps.
33
+ */
34
+ export enum StampAlignment {
35
+ LEFT = 0,
36
+ CENTER = 1,
37
+ RIGHT = 2,
38
+ }
39
+
40
+ /**
41
+ * Types of differences found in page comparison.
42
+ */
43
+ export enum DifferenceType {
44
+ TEXT_ADDED = 0,
45
+ TEXT_REMOVED = 1,
46
+ TEXT_CHANGED = 2,
47
+ IMAGE_ADDED = 3,
48
+ IMAGE_REMOVED = 4,
49
+ IMAGE_CHANGED = 5,
50
+ LAYOUT_CHANGED = 6,
51
+ ANNOTATION_CHANGED = 7,
52
+ }
53
+
54
+ // =============================================================================
55
+ // Interfaces
56
+ // =============================================================================
57
+
58
+ /**
59
+ * A single difference found between two pages.
60
+ */
61
+ export interface Difference {
62
+ /** Type of difference */
63
+ readonly type: DifferenceType;
64
+ /** Description of the difference */
65
+ readonly description: string;
66
+ /** Page region where the difference was found (x, y, width, height) */
67
+ readonly bounds?: { x: number; y: number; width: number; height: number };
68
+ }
69
+
70
+ /**
71
+ * Result of comparing two pages.
72
+ */
73
+ export interface PageComparisonResult {
74
+ /** Similarity score (0.0 - 1.0, where 1.0 means identical) */
75
+ readonly similarity: number;
76
+ /** Number of differences found */
77
+ readonly diffCount: number;
78
+ /** List of differences */
79
+ readonly differences: readonly Difference[];
80
+ }
81
+
82
+ /**
83
+ * Result of comparing two documents.
84
+ */
85
+ export interface DocumentComparisonResult {
86
+ /** Overall similarity score (0.0 - 1.0) */
87
+ readonly similarity: number;
88
+ /** Per-page comparison results */
89
+ readonly pageResults: readonly PageComparisonResult[];
90
+ /** Number of pages in document A */
91
+ readonly pagesA: number;
92
+ /** Number of pages in document B */
93
+ readonly pagesB: number;
94
+ /** Total differences found across all pages */
95
+ readonly totalDifferences: number;
96
+ }
97
+
98
+ // =============================================================================
99
+ // EnterpriseManager
100
+ // =============================================================================
101
+
102
+ /**
103
+ * Manager for enterprise PDF operations.
104
+ *
105
+ * Provides methods for Bates numbering, document comparison,
106
+ * and header/footer stamping.
107
+ *
108
+ * @example
109
+ * ```typescript
110
+ * const enterprise = new EnterpriseManager(document);
111
+ *
112
+ * // Apply Bates numbering
113
+ * await enterprise.applyBates('DOC', 1, 6, BatesPosition.BOTTOM_RIGHT);
114
+ *
115
+ * // Compare pages
116
+ * const result = await enterprise.comparePages(docA, 0, docB, 0);
117
+ * console.log(`Pages are ${(result.similarity * 100).toFixed(1)}% similar`);
118
+ *
119
+ * // Stamp headers and footers
120
+ * await enterprise.stampHeader('CONFIDENTIAL', StampAlignment.CENTER, 12, 36);
121
+ * ```
122
+ */
123
+ export class EnterpriseManager extends EventEmitter {
124
+ private document: any;
125
+ private native: any;
126
+
127
+ constructor(document: any) {
128
+ super();
129
+ if (!document) {
130
+ throw new Error('Document cannot be null or undefined');
131
+ }
132
+ this.document = document;
133
+ try {
134
+ this.native = require('../../index.node');
135
+ } catch {
136
+ this.native = null;
137
+ }
138
+ }
139
+
140
+ // ===========================================================================
141
+ // Bates Numbering
142
+ // ===========================================================================
143
+
144
+ /**
145
+ * Applies Bates numbering to the document.
146
+ *
147
+ * @param prefix - Text prefix before the number (e.g., 'DOC')
148
+ * @param startNumber - Starting number
149
+ * @param numDigits - Number of digits (zero-padded)
150
+ * @param position - Position on the page
151
+ * @throws PdfException if the operation fails
152
+ */
153
+ async applyBates(
154
+ prefix: string,
155
+ startNumber: number,
156
+ numDigits: number,
157
+ position: BatesPosition,
158
+ ): Promise<void> {
159
+ if (!this.native?.pdf_bates_apply) {
160
+ throw new PdfException('9900', 'Native enterprise not available: pdf_bates_apply not found');
161
+ }
162
+
163
+ const errorCode = Buffer.alloc(4);
164
+ this.native.pdf_bates_apply(
165
+ this.document._handle ?? this.document,
166
+ prefix,
167
+ startNumber,
168
+ numDigits,
169
+ position,
170
+ errorCode,
171
+ );
172
+ const code = errorCode.readInt32LE(0);
173
+
174
+ if (code !== 0) {
175
+ throw mapFfiErrorCode(code, 'Failed to apply Bates numbering');
176
+ }
177
+
178
+ this.emit('bates-applied', { prefix, startNumber, numDigits, position });
179
+ }
180
+
181
+ /**
182
+ * Applies advanced Bates numbering with full configuration.
183
+ *
184
+ * @param prefix - Text prefix before the number
185
+ * @param suffix - Text suffix after the number
186
+ * @param startNumber - Starting number
187
+ * @param numDigits - Number of digits (zero-padded)
188
+ * @param position - Position on the page
189
+ * @param fontSize - Font size in points
190
+ * @param margin - Margin from page edge in points
191
+ * @param startPage - Starting page index (0-based)
192
+ * @param endPage - Ending page index (0-based, -1 for last page)
193
+ * @throws PdfException if the operation fails
194
+ */
195
+ async applyBatesAdvanced(
196
+ prefix: string,
197
+ suffix: string,
198
+ startNumber: number,
199
+ numDigits: number,
200
+ position: BatesPosition,
201
+ fontSize: number,
202
+ margin: number,
203
+ startPage: number,
204
+ endPage: number,
205
+ ): Promise<void> {
206
+ if (!this.native?.pdf_bates_apply_advanced) {
207
+ throw new PdfException('9900', 'Native enterprise not available: pdf_bates_apply_advanced not found');
208
+ }
209
+
210
+ const errorCode = Buffer.alloc(4);
211
+ this.native.pdf_bates_apply_advanced(
212
+ this.document._handle ?? this.document,
213
+ prefix,
214
+ suffix,
215
+ startNumber,
216
+ numDigits,
217
+ position,
218
+ fontSize,
219
+ margin,
220
+ startPage,
221
+ endPage,
222
+ errorCode,
223
+ );
224
+ const code = errorCode.readInt32LE(0);
225
+
226
+ if (code !== 0) {
227
+ throw mapFfiErrorCode(code, 'Failed to apply advanced Bates numbering');
228
+ }
229
+
230
+ this.emit('bates-applied-advanced', { prefix, suffix, startNumber, numDigits, position });
231
+ }
232
+
233
+ // ===========================================================================
234
+ // Document Comparison
235
+ // ===========================================================================
236
+
237
+ /**
238
+ * Compares two pages from potentially different documents.
239
+ *
240
+ * @param docA - First document handle
241
+ * @param pageA - Page index in first document (0-based)
242
+ * @param docB - Second document handle
243
+ * @param pageB - Page index in second document (0-based)
244
+ * @returns Comparison result with similarity score and differences
245
+ * @throws PdfException if the comparison fails
246
+ */
247
+ async comparePages(
248
+ docA: any,
249
+ pageA: number,
250
+ docB: any,
251
+ pageB: number,
252
+ ): Promise<PageComparisonResult> {
253
+ if (!this.native?.pdf_compare_pages) {
254
+ throw new PdfException('9900', 'Native enterprise not available: pdf_compare_pages not found');
255
+ }
256
+
257
+ const errorCode = Buffer.alloc(4);
258
+ const comparisonPtr = this.native.pdf_compare_pages(
259
+ docA._handle ?? docA,
260
+ pageA,
261
+ docB._handle ?? docB,
262
+ pageB,
263
+ errorCode,
264
+ );
265
+ const code = errorCode.readInt32LE(0);
266
+
267
+ if (code !== 0) {
268
+ throw mapFfiErrorCode(code, 'Failed to compare pages');
269
+ }
270
+
271
+ try {
272
+ const similarity = this.native.pdf_comparison_get_similarity?.(comparisonPtr) ?? 0;
273
+ const diffCount = this.native.pdf_comparison_get_diff_count?.(comparisonPtr) ?? 0;
274
+
275
+ const differences: Difference[] = [];
276
+ for (let i = 0; i < diffCount; i++) {
277
+ const diffPtr = this.native.pdf_comparison_get_diff?.(comparisonPtr, i);
278
+ if (diffPtr) {
279
+ const diffType = this.native.pdf_comparison_get_diff_type?.(diffPtr) ?? 0;
280
+ differences.push({
281
+ type: diffType as DifferenceType,
282
+ description: `Difference ${i + 1}`,
283
+ });
284
+ }
285
+ }
286
+
287
+ const result: PageComparisonResult = { similarity, diffCount, differences };
288
+ this.emit('pages-compared', { pageA, pageB, similarity });
289
+ return result;
290
+ } finally {
291
+ if (this.native.pdf_comparison_free) {
292
+ this.native.pdf_comparison_free(comparisonPtr);
293
+ }
294
+ }
295
+ }
296
+
297
+ /**
298
+ * Compares two entire documents page by page.
299
+ *
300
+ * @param docA - First document handle
301
+ * @param docB - Second document handle
302
+ * @returns Document-level comparison result
303
+ * @throws PdfException if the comparison fails
304
+ */
305
+ async compareDocuments(
306
+ docA: any,
307
+ docB: any,
308
+ ): Promise<DocumentComparisonResult> {
309
+ if (!this.native?.pdf_compare_documents) {
310
+ throw new PdfException('9900', 'Native enterprise not available: pdf_compare_documents not found');
311
+ }
312
+
313
+ const errorCode = Buffer.alloc(4);
314
+ const resultPtr = this.native.pdf_compare_documents(
315
+ docA._handle ?? docA,
316
+ docB._handle ?? docB,
317
+ errorCode,
318
+ );
319
+ const code = errorCode.readInt32LE(0);
320
+
321
+ if (code !== 0) {
322
+ throw mapFfiErrorCode(code, 'Failed to compare documents');
323
+ }
324
+
325
+ try {
326
+ let result: DocumentComparisonResult;
327
+ if (typeof resultPtr === 'string') {
328
+ result = JSON.parse(resultPtr);
329
+ } else {
330
+ result = resultPtr ?? {
331
+ similarity: 0,
332
+ pageResults: [],
333
+ pagesA: 0,
334
+ pagesB: 0,
335
+ totalDifferences: 0,
336
+ };
337
+ }
338
+
339
+ this.emit('documents-compared', { similarity: result.similarity, totalDifferences: result.totalDifferences });
340
+ return result;
341
+ } finally {
342
+ if (this.native.pdf_document_comparison_free && typeof resultPtr !== 'string') {
343
+ this.native.pdf_document_comparison_free(resultPtr);
344
+ }
345
+ }
346
+ }
347
+
348
+ // ===========================================================================
349
+ // Header / Footer Stamping
350
+ // ===========================================================================
351
+
352
+ /**
353
+ * Stamps a header on all pages of the document.
354
+ *
355
+ * @param text - Header text (supports placeholders: {page}, {pages}, {date})
356
+ * @param align - Text alignment
357
+ * @param size - Font size in points
358
+ * @param margin - Top margin in points
359
+ * @throws PdfException if the operation fails
360
+ */
361
+ async stampHeader(
362
+ text: string,
363
+ align: StampAlignment,
364
+ size: number,
365
+ margin: number,
366
+ ): Promise<void> {
367
+ if (!this.native?.pdf_stamp_header) {
368
+ throw new PdfException('9900', 'Native enterprise not available: pdf_stamp_header not found');
369
+ }
370
+
371
+ const errorCode = Buffer.alloc(4);
372
+ this.native.pdf_stamp_header(
373
+ this.document._handle ?? this.document,
374
+ text,
375
+ align,
376
+ size,
377
+ margin,
378
+ errorCode,
379
+ );
380
+ const code = errorCode.readInt32LE(0);
381
+
382
+ if (code !== 0) {
383
+ throw mapFfiErrorCode(code, 'Failed to stamp header');
384
+ }
385
+
386
+ this.emit('header-stamped', { text, align, size, margin });
387
+ }
388
+
389
+ /**
390
+ * Stamps a footer on all pages of the document.
391
+ *
392
+ * @param text - Footer text (supports placeholders: {page}, {pages}, {date})
393
+ * @param align - Text alignment
394
+ * @param size - Font size in points
395
+ * @param margin - Bottom margin in points
396
+ * @throws PdfException if the operation fails
397
+ */
398
+ async stampFooter(
399
+ text: string,
400
+ align: StampAlignment,
401
+ size: number,
402
+ margin: number,
403
+ ): Promise<void> {
404
+ if (!this.native?.pdf_stamp_footer) {
405
+ throw new PdfException('9900', 'Native enterprise not available: pdf_stamp_footer not found');
406
+ }
407
+
408
+ const errorCode = Buffer.alloc(4);
409
+ this.native.pdf_stamp_footer(
410
+ this.document._handle ?? this.document,
411
+ text,
412
+ align,
413
+ size,
414
+ margin,
415
+ errorCode,
416
+ );
417
+ const code = errorCode.readInt32LE(0);
418
+
419
+ if (code !== 0) {
420
+ throw mapFfiErrorCode(code, 'Failed to stamp footer');
421
+ }
422
+
423
+ this.emit('footer-stamped', { text, align, size, margin });
424
+ }
425
+
426
+ /**
427
+ * Stamps both header and footer on all pages of the document.
428
+ *
429
+ * @param headerText - Header text
430
+ * @param footerText - Footer text
431
+ * @param align - Text alignment for both
432
+ * @param size - Font size in points
433
+ * @param margin - Margin from page edge in points
434
+ * @throws PdfException if the operation fails
435
+ */
436
+ async stampHeaderFooter(
437
+ headerText: string,
438
+ footerText: string,
439
+ align: StampAlignment,
440
+ size: number,
441
+ margin: number,
442
+ ): Promise<void> {
443
+ if (!this.native?.pdf_stamp_header_footer) {
444
+ throw new PdfException('9900', 'Native enterprise not available: pdf_stamp_header_footer not found');
445
+ }
446
+
447
+ const errorCode = Buffer.alloc(4);
448
+ this.native.pdf_stamp_header_footer(
449
+ this.document._handle ?? this.document,
450
+ headerText,
451
+ footerText,
452
+ align,
453
+ size,
454
+ margin,
455
+ errorCode,
456
+ );
457
+ const code = errorCode.readInt32LE(0);
458
+
459
+ if (code !== 0) {
460
+ throw mapFfiErrorCode(code, 'Failed to stamp header and footer');
461
+ }
462
+
463
+ this.emit('header-footer-stamped', { headerText, footerText, align, size, margin });
464
+ }
465
+
466
+ // ===========================================================================
467
+ // Cleanup
468
+ // ===========================================================================
469
+
470
+ /**
471
+ * Releases resources held by this manager.
472
+ */
473
+ destroy(): void {
474
+ this.removeAllListeners();
475
+ }
476
+ }
477
+
478
+ export default EnterpriseManager;