pdf-oxide-fips 0.3.47

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 (127) hide show
  1. package/LICENSE-APACHE +176 -0
  2. package/LICENSE-MIT +25 -0
  3. package/README.md +218 -0
  4. package/lib/builders/annotation-builder.d.ts +198 -0
  5. package/lib/builders/annotation-builder.js +317 -0
  6. package/lib/builders/conversion-options-builder.d.ts +106 -0
  7. package/lib/builders/conversion-options-builder.js +214 -0
  8. package/lib/builders/document-builder.d.ts +381 -0
  9. package/lib/builders/document-builder.js +770 -0
  10. package/lib/builders/index.d.ts +13 -0
  11. package/lib/builders/index.js +13 -0
  12. package/lib/builders/metadata-builder.d.ts +201 -0
  13. package/lib/builders/metadata-builder.js +285 -0
  14. package/lib/builders/pdf-builder.d.ts +216 -0
  15. package/lib/builders/pdf-builder.js +350 -0
  16. package/lib/builders/search-options-builder.d.ts +73 -0
  17. package/lib/builders/search-options-builder.js +129 -0
  18. package/lib/builders/streaming-table.d.ts +64 -0
  19. package/lib/builders/streaming-table.js +140 -0
  20. package/lib/document-editor-manager.d.ts +139 -0
  21. package/lib/document-editor-manager.js +256 -0
  22. package/lib/document-editor.d.ts +124 -0
  23. package/lib/document-editor.js +318 -0
  24. package/lib/errors.d.ts +382 -0
  25. package/lib/errors.js +1115 -0
  26. package/lib/form-field-manager.d.ts +299 -0
  27. package/lib/form-field-manager.js +568 -0
  28. package/lib/hybrid-ml-manager.d.ts +142 -0
  29. package/lib/hybrid-ml-manager.js +208 -0
  30. package/lib/index.d.ts +205 -0
  31. package/lib/index.js +693 -0
  32. package/lib/managers/accessibility-manager.d.ts +148 -0
  33. package/lib/managers/accessibility-manager.js +234 -0
  34. package/lib/managers/annotation-manager.d.ts +219 -0
  35. package/lib/managers/annotation-manager.js +359 -0
  36. package/lib/managers/barcode-manager.d.ts +82 -0
  37. package/lib/managers/barcode-manager.js +263 -0
  38. package/lib/managers/batch-manager.d.ts +185 -0
  39. package/lib/managers/batch-manager.js +385 -0
  40. package/lib/managers/cache-manager.d.ts +181 -0
  41. package/lib/managers/cache-manager.js +384 -0
  42. package/lib/managers/compliance-manager.d.ts +103 -0
  43. package/lib/managers/compliance-manager.js +453 -0
  44. package/lib/managers/content-manager.d.ts +120 -0
  45. package/lib/managers/content-manager.js +294 -0
  46. package/lib/managers/document-utility-manager.d.ts +369 -0
  47. package/lib/managers/document-utility-manager.js +730 -0
  48. package/lib/managers/dom-pdf-creator.d.ts +104 -0
  49. package/lib/managers/dom-pdf-creator.js +299 -0
  50. package/lib/managers/editing-manager.d.ts +248 -0
  51. package/lib/managers/editing-manager.js +387 -0
  52. package/lib/managers/enterprise-manager.d.ts +192 -0
  53. package/lib/managers/enterprise-manager.js +307 -0
  54. package/lib/managers/extended-managers.d.ts +122 -0
  55. package/lib/managers/extended-managers.js +664 -0
  56. package/lib/managers/extraction-manager.d.ts +246 -0
  57. package/lib/managers/extraction-manager.js +482 -0
  58. package/lib/managers/final-utilities.d.ts +127 -0
  59. package/lib/managers/final-utilities.js +657 -0
  60. package/lib/managers/hybrid-ml-advanced.d.ts +136 -0
  61. package/lib/managers/hybrid-ml-advanced.js +722 -0
  62. package/lib/managers/index.d.ts +64 -0
  63. package/lib/managers/index.js +69 -0
  64. package/lib/managers/layer-manager.d.ts +203 -0
  65. package/lib/managers/layer-manager.js +401 -0
  66. package/lib/managers/metadata-manager.d.ts +148 -0
  67. package/lib/managers/metadata-manager.js +280 -0
  68. package/lib/managers/ocr-manager.d.ts +194 -0
  69. package/lib/managers/ocr-manager.js +582 -0
  70. package/lib/managers/optimization-manager.d.ts +102 -0
  71. package/lib/managers/optimization-manager.js +213 -0
  72. package/lib/managers/outline-manager.d.ts +101 -0
  73. package/lib/managers/outline-manager.js +169 -0
  74. package/lib/managers/page-manager.d.ts +142 -0
  75. package/lib/managers/page-manager.js +235 -0
  76. package/lib/managers/pattern-detection.d.ts +169 -0
  77. package/lib/managers/pattern-detection.js +322 -0
  78. package/lib/managers/rendering-manager.d.ts +353 -0
  79. package/lib/managers/rendering-manager.js +679 -0
  80. package/lib/managers/search-manager.d.ts +235 -0
  81. package/lib/managers/search-manager.js +329 -0
  82. package/lib/managers/security-manager.d.ts +161 -0
  83. package/lib/managers/security-manager.js +292 -0
  84. package/lib/managers/signature-manager.d.ts +738 -0
  85. package/lib/managers/signature-manager.js +1509 -0
  86. package/lib/managers/streams.d.ts +262 -0
  87. package/lib/managers/streams.js +477 -0
  88. package/lib/managers/xfa-manager.d.ts +227 -0
  89. package/lib/managers/xfa-manager.js +539 -0
  90. package/lib/native-loader.d.ts +7 -0
  91. package/lib/native-loader.js +62 -0
  92. package/lib/native.d.ts +16 -0
  93. package/lib/native.js +69 -0
  94. package/lib/pdf-creator-manager.d.ts +200 -0
  95. package/lib/pdf-creator-manager.js +381 -0
  96. package/lib/properties.d.ts +79 -0
  97. package/lib/properties.js +454 -0
  98. package/lib/result-accessors-manager.d.ts +346 -0
  99. package/lib/result-accessors-manager.js +706 -0
  100. package/lib/thumbnail-manager.d.ts +121 -0
  101. package/lib/thumbnail-manager.js +205 -0
  102. package/lib/timestamp.d.ts +54 -0
  103. package/lib/timestamp.js +115 -0
  104. package/lib/tsa-client.d.ts +44 -0
  105. package/lib/tsa-client.js +67 -0
  106. package/lib/types/common.d.ts +189 -0
  107. package/lib/types/common.js +17 -0
  108. package/lib/types/document-types.d.ts +352 -0
  109. package/lib/types/document-types.js +82 -0
  110. package/lib/types/index.d.ts +5 -0
  111. package/lib/types/index.js +5 -0
  112. package/lib/types/manager-types.d.ts +179 -0
  113. package/lib/types/manager-types.js +100 -0
  114. package/lib/types/native-bindings.d.ts +439 -0
  115. package/lib/types/native-bindings.js +7 -0
  116. package/lib/workers/index.d.ts +6 -0
  117. package/lib/workers/index.js +5 -0
  118. package/lib/workers/pool.d.ts +64 -0
  119. package/lib/workers/pool.js +192 -0
  120. package/lib/workers/worker.d.ts +5 -0
  121. package/lib/workers/worker.js +99 -0
  122. package/package.json +79 -0
  123. package/prebuilds/darwin-arm64/pdf_oxide.node +0 -0
  124. package/prebuilds/darwin-x64/pdf_oxide.node +0 -0
  125. package/prebuilds/linux-arm64/pdf_oxide.node +0 -0
  126. package/prebuilds/linux-x64/pdf_oxide.node +0 -0
  127. package/prebuilds/win32-x64/pdf_oxide.node +0 -0
@@ -0,0 +1,359 @@
1
+ /**
2
+ * Manager for PDF page annotations (comments, highlights, etc.)
3
+ *
4
+ * Provides methods to work with annotations on PDF pages including
5
+ * comments, highlights, underlines, and other markup.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { AnnotationManager } from 'pdf_oxide';
10
+ *
11
+ * const doc = PdfDocument.open('document.pdf');
12
+ * const page = doc.getPage(0);
13
+ * const annotationManager = new AnnotationManager(page);
14
+ *
15
+ * // Get annotations on the page
16
+ * const annotations = annotationManager.getAnnotations();
17
+ * console.log(`Page has ${annotations.length} annotations`);
18
+ * ```
19
+ */
20
+ export class AnnotationManager {
21
+ /**
22
+ * Creates a new AnnotationManager for the given page
23
+ * @param page - The PDF page
24
+ * @throws Error if page is null or undefined
25
+ */
26
+ constructor(page) {
27
+ if (!page) {
28
+ throw new Error('Page is required');
29
+ }
30
+ this._page = page;
31
+ // Performance optimization: cache annotations to avoid redundant fetches
32
+ this._annotationCache = null;
33
+ this._statisticsCache = null;
34
+ }
35
+ /**
36
+ * Clears the annotation cache
37
+ * Useful when page content might have changed
38
+ */
39
+ clearCache() {
40
+ this._annotationCache = null;
41
+ this._statisticsCache = null;
42
+ }
43
+ /**
44
+ * Gets all annotations on the page
45
+ * Performance optimization: caches results to avoid redundant fetches
46
+ * @returns Array of annotations
47
+ *
48
+ * @example
49
+ * ```typescript
50
+ * const annotations = manager.getAnnotations();
51
+ * annotations.forEach(ann => {
52
+ * console.log(`${ann.type}: ${ann.content}`);
53
+ * });
54
+ * ```
55
+ */
56
+ getAnnotations() {
57
+ // Performance optimization: return cached annotations if available
58
+ if (this._annotationCache !== null) {
59
+ return this._annotationCache;
60
+ }
61
+ try {
62
+ // This would require native API support for getting annotations
63
+ const annotations = [];
64
+ // Cache the result
65
+ this._annotationCache = annotations;
66
+ return annotations;
67
+ }
68
+ catch (error) {
69
+ return [];
70
+ }
71
+ }
72
+ /**
73
+ * Gets annotations by type
74
+ * @param type - Annotation type ('text', 'highlight', 'underline', 'strikeout', 'squiggly')
75
+ * @returns Matching annotations
76
+ *
77
+ * @example
78
+ * ```typescript
79
+ * const highlights = manager.getAnnotationsByType('highlight');
80
+ * console.log(`Page has ${highlights.length} highlights`);
81
+ * ```
82
+ */
83
+ getAnnotationsByType(type) {
84
+ if (!type || typeof type !== 'string') {
85
+ throw new Error('Type must be a non-empty string');
86
+ }
87
+ const validTypes = ['text', 'highlight', 'underline', 'strikeout', 'squiggly', 'link', 'ink'];
88
+ if (!validTypes.includes(type.toLowerCase())) {
89
+ throw new Error(`Invalid annotation type: ${type}`);
90
+ }
91
+ const annotations = this.getAnnotations();
92
+ return annotations.filter((ann) => ann.type === type.toLowerCase());
93
+ }
94
+ /**
95
+ * Gets number of annotations on page
96
+ * @returns Annotation count
97
+ */
98
+ getAnnotationCount() {
99
+ return this.getAnnotations().length;
100
+ }
101
+ /**
102
+ * Gets annotations by author
103
+ * @param author - Author name to filter
104
+ * @returns Annotations by specified author
105
+ *
106
+ * @example
107
+ * ```typescript
108
+ * const johnDoeAnnotations = manager.getAnnotationsByAuthor('John Doe');
109
+ * ```
110
+ */
111
+ getAnnotationsByAuthor(author) {
112
+ if (!author || typeof author !== 'string') {
113
+ throw new Error('Author must be a non-empty string');
114
+ }
115
+ const annotations = this.getAnnotations();
116
+ return annotations.filter((ann) => ann.author === author);
117
+ }
118
+ /**
119
+ * Gets unique authors of annotations
120
+ * @returns Array of author names
121
+ */
122
+ getAnnotationAuthors() {
123
+ const annotations = this.getAnnotations();
124
+ const authors = new Set();
125
+ annotations.forEach((ann) => {
126
+ if (ann.author) {
127
+ authors.add(ann.author);
128
+ }
129
+ });
130
+ return Array.from(authors).sort();
131
+ }
132
+ /**
133
+ * Gets annotations modified after a date
134
+ * @param date - Filter date
135
+ * @returns Annotations modified after date
136
+ *
137
+ * @example
138
+ * ```typescript
139
+ * const recentAnnotations = manager.getAnnotationsAfter(new Date('2024-01-01'));
140
+ * ```
141
+ */
142
+ getAnnotationsAfter(date) {
143
+ if (!(date instanceof Date)) {
144
+ throw new Error('Date must be a Date object');
145
+ }
146
+ const annotations = this.getAnnotations();
147
+ return annotations.filter((ann) => ann.modificationDate && new Date(ann.modificationDate) > date);
148
+ }
149
+ /**
150
+ * Gets annotations modified before a date
151
+ * @param date - Filter date
152
+ * @returns Annotations modified before date
153
+ */
154
+ getAnnotationsBefore(date) {
155
+ if (!(date instanceof Date)) {
156
+ throw new Error('Date must be a Date object');
157
+ }
158
+ const annotations = this.getAnnotations();
159
+ return annotations.filter((ann) => ann.modificationDate && new Date(ann.modificationDate) < date);
160
+ }
161
+ /**
162
+ * Gets annotations with specific content
163
+ * @param contentFragment - Text fragment to search for
164
+ * @returns Matching annotations
165
+ *
166
+ * @example
167
+ * ```typescript
168
+ * const reviewComments = manager.getAnnotationsWithContent('review');
169
+ * ```
170
+ */
171
+ getAnnotationsWithContent(contentFragment) {
172
+ if (!contentFragment || typeof contentFragment !== 'string') {
173
+ throw new Error('Content fragment must be a non-empty string');
174
+ }
175
+ const annotations = this.getAnnotations();
176
+ const fragment = contentFragment.toLowerCase();
177
+ return annotations.filter((ann) => ann.content && ann.content.toLowerCase().includes(fragment));
178
+ }
179
+ /**
180
+ * Gets highlights (most common annotation type)
181
+ * @returns Array of highlight annotations
182
+ */
183
+ getHighlights() {
184
+ return this.getAnnotationsByType('highlight');
185
+ }
186
+ /**
187
+ * Gets text comments/notes
188
+ * @returns Array of text annotations
189
+ */
190
+ getComments() {
191
+ return this.getAnnotationsByType('text');
192
+ }
193
+ /**
194
+ * Gets underlines
195
+ * @returns Array of underline annotations
196
+ */
197
+ getUnderlines() {
198
+ return this.getAnnotationsByType('underline');
199
+ }
200
+ /**
201
+ * Gets strikeouts
202
+ * @returns Array of strikeout annotations
203
+ */
204
+ getStrikeouts() {
205
+ return this.getAnnotationsByType('strikeout');
206
+ }
207
+ /**
208
+ * Gets squiggly underlines
209
+ * @returns Array of squiggly annotations
210
+ */
211
+ getSquigglies() {
212
+ return this.getAnnotationsByType('squiggly');
213
+ }
214
+ /**
215
+ * Gets annotations statistics
216
+ * Performance optimization: caches computed statistics
217
+ * @returns Statistics about annotations
218
+ *
219
+ * @example
220
+ * ```typescript
221
+ * const stats = manager.getAnnotationStatistics();
222
+ * console.log(`Total: ${stats.total}, Highlights: ${stats.byType.highlight}`);
223
+ * ```
224
+ */
225
+ getAnnotationStatistics() {
226
+ // Performance optimization: return cached statistics if available
227
+ if (this._statisticsCache !== null) {
228
+ return this._statisticsCache;
229
+ }
230
+ const annotations = this.getAnnotations();
231
+ const byType = {};
232
+ const byAuthor = {};
233
+ annotations.forEach((ann) => {
234
+ // Count by type
235
+ byType[ann.type] = (byType[ann.type] || 0) + 1;
236
+ // Count by author
237
+ if (ann.author) {
238
+ byAuthor[ann.author] = (byAuthor[ann.author] || 0) + 1;
239
+ }
240
+ });
241
+ const stats = {
242
+ total: annotations.length,
243
+ byType,
244
+ byAuthor,
245
+ authors: Object.keys(byAuthor),
246
+ types: Object.keys(byType),
247
+ hasComments: annotations.some((ann) => ann.type === 'text'),
248
+ hasHighlights: annotations.some((ann) => ann.type === 'highlight'),
249
+ averageOpacity: this.getAverageOpacity(),
250
+ recentModifications: this.getRecentAnnotations(7).length,
251
+ };
252
+ // Cache the results
253
+ this._statisticsCache = stats;
254
+ return stats;
255
+ }
256
+ /**
257
+ * Gets average opacity of annotations
258
+ * @returns Average opacity value (0-1)
259
+ * @private
260
+ */
261
+ getAverageOpacity() {
262
+ const annotations = this.getAnnotations();
263
+ if (annotations.length === 0)
264
+ return 1;
265
+ const sum = annotations.reduce((acc, ann) => acc + (ann.opacity || 1), 0);
266
+ return sum / annotations.length;
267
+ }
268
+ /**
269
+ * Gets annotations modified within last N days
270
+ * @param days - Number of days to look back
271
+ * @returns Recent annotations
272
+ *
273
+ * @example
274
+ * ```typescript
275
+ * const lastWeek = manager.getRecentAnnotations(7);
276
+ * console.log(`${lastWeek.length} annotations modified in last 7 days`);
277
+ * ```
278
+ */
279
+ getRecentAnnotations(days) {
280
+ if (typeof days !== 'number' || days < 0) {
281
+ throw new Error('Days must be a non-negative number');
282
+ }
283
+ const cutoffDate = new Date();
284
+ cutoffDate.setDate(cutoffDate.getDate() - days);
285
+ return this.getAnnotationsAfter(cutoffDate);
286
+ }
287
+ /**
288
+ * Generates annotation summary
289
+ * @returns Human-readable annotation summary
290
+ *
291
+ * @example
292
+ * ```typescript
293
+ * console.log(manager.generateAnnotationSummary());
294
+ * ```
295
+ */
296
+ generateAnnotationSummary() {
297
+ const stats = this.getAnnotationStatistics();
298
+ const lines = [];
299
+ lines.push(`Annotation Summary (Page ${this._page.pageIndex + 1}):`);
300
+ lines.push(`Total Annotations: ${stats.total}`);
301
+ if (stats.total > 0) {
302
+ lines.push('\nBy Type:');
303
+ Object.entries(stats.byType).forEach(([type, count]) => {
304
+ lines.push(` ${type}: ${count}`);
305
+ });
306
+ if (stats.authors.length > 0) {
307
+ lines.push('\nBy Author:');
308
+ Object.entries(stats.byAuthor).forEach(([author, count]) => {
309
+ lines.push(` ${author}: ${count}`);
310
+ });
311
+ }
312
+ }
313
+ return lines.join('\n');
314
+ }
315
+ /**
316
+ * Validates annotation bounds
317
+ * @param annotation - Annotation to validate
318
+ * @returns Validation result
319
+ *
320
+ * @example
321
+ * ```typescript
322
+ * const annotation = manager.getAnnotations()[0];
323
+ * const validation = manager.validateAnnotation(annotation);
324
+ * if (!validation.isValid) {
325
+ * console.log('Invalid:', validation.issues);
326
+ * }
327
+ * ```
328
+ */
329
+ validateAnnotation(annotation) {
330
+ const issues = [];
331
+ if (!annotation) {
332
+ issues.push('Annotation is null or undefined');
333
+ }
334
+ else {
335
+ if (!annotation.type)
336
+ issues.push('Missing annotation type');
337
+ if (!['text', 'highlight', 'underline', 'strikeout', 'squiggly'].includes(annotation.type)) {
338
+ issues.push(`Unknown annotation type: ${annotation.type}`);
339
+ }
340
+ if (annotation.bounds) {
341
+ if (annotation.bounds.x < 0)
342
+ issues.push('Invalid bounds: x must be non-negative');
343
+ if (annotation.bounds.y < 0)
344
+ issues.push('Invalid bounds: y must be non-negative');
345
+ if (annotation.bounds.width < 0)
346
+ issues.push('Invalid bounds: width must be non-negative');
347
+ if (annotation.bounds.height < 0)
348
+ issues.push('Invalid bounds: height must be non-negative');
349
+ }
350
+ if (annotation.opacity && (annotation.opacity < 0 || annotation.opacity > 1)) {
351
+ issues.push('Invalid opacity: must be between 0 and 1');
352
+ }
353
+ }
354
+ return {
355
+ isValid: issues.length === 0,
356
+ issues,
357
+ };
358
+ }
359
+ }
@@ -0,0 +1,82 @@
1
+ /**
2
+ * BarcodeManager - Canonical Barcode Manager (merged from 2 implementations)
3
+ *
4
+ * Consolidates:
5
+ * - src/barcode-manager.ts BarcodeManager (detection + counting + format-based query)
6
+ * - src/managers/barcode-signature-rendering.ts BarcodesManager (generation + conversion + page embedding)
7
+ *
8
+ * Provides complete barcode operations.
9
+ */
10
+ import { EventEmitter } from 'events';
11
+ export declare enum BarcodeFormat {
12
+ CODE128 = "CODE128",
13
+ CODE39 = "CODE39",
14
+ EAN13 = "EAN13",
15
+ EAN8 = "EAN8",
16
+ UPCA = "UPCA",
17
+ UPCE = "UPCE",
18
+ QR = "QR",
19
+ PDF417 = "PDF417",
20
+ DATAMATRIX = "DATAMATRIX",
21
+ AZTEC = "AZTEC",
22
+ QR_CODE = "QR_CODE",
23
+ DATA_MATRIX = "DATA_MATRIX",
24
+ CODE_93 = "CODE_93"
25
+ }
26
+ export declare enum BarcodeErrorCorrection {
27
+ L = "L",
28
+ M = "M",
29
+ Q = "Q",
30
+ H = "H"
31
+ }
32
+ export declare enum QrErrorCorrection {
33
+ L = 0,
34
+ M = 1,
35
+ Q = 2,
36
+ H = 3
37
+ }
38
+ export interface DetectedBarcode {
39
+ format: BarcodeFormat;
40
+ rawValue: string;
41
+ decodedValue: string;
42
+ confidence: number;
43
+ x: number;
44
+ y: number;
45
+ width: number;
46
+ height: number;
47
+ }
48
+ export interface BarcodeGenerationConfig {
49
+ format?: BarcodeFormat;
50
+ width?: number;
51
+ height?: number;
52
+ sizePx?: number;
53
+ errorCorrection?: BarcodeErrorCorrection;
54
+ margin?: number;
55
+ }
56
+ export declare class BarcodeManager extends EventEmitter {
57
+ private document;
58
+ private resultCache;
59
+ private maxCacheSize;
60
+ private native;
61
+ constructor(document: any);
62
+ detectBarcodes(pageIndex: number): Promise<DetectedBarcode[]>;
63
+ detectAllBarcodes(): Promise<Map<number, DetectedBarcode[]>>;
64
+ getBarcodesOfFormat(format: BarcodeFormat, pageIndex?: number): Promise<DetectedBarcode[]>;
65
+ getBarcodeCount(): Promise<number>;
66
+ getCountByFormat(format: BarcodeFormat): Promise<number>;
67
+ hasBarcode(pageIndex: number): Promise<boolean>;
68
+ generateBarcode(data: string, config?: BarcodeGenerationConfig): Promise<Buffer>;
69
+ generateQrCode(data: string, errorCorrection?: QrErrorCorrection, sizePx?: number): Promise<Buffer>;
70
+ barcodeToPng(barcodeData: Buffer, sizePx?: number): Promise<Buffer>;
71
+ barcodeToSvg(barcodeData: Buffer, sizePx?: number): Promise<string>;
72
+ generateSvg(data: string, config?: BarcodeGenerationConfig): Promise<string>;
73
+ generateQrSvg(data: string, errorCorrection?: QrErrorCorrection, sizePx?: number): Promise<string>;
74
+ addBarcodeToPage(pageIndex: number, barcodeData: Buffer, x: number, y: number, width: number, height: number): Promise<boolean>;
75
+ detectBarcodeFormat(barcodeData: Buffer): BarcodeFormat;
76
+ decodeBarcodeData(barcodeData: Buffer): string;
77
+ getDetectionConfidence(barcodeData: Buffer): number;
78
+ clearCache(): void;
79
+ getCacheStats(): Record<string, any>;
80
+ private setCached;
81
+ }
82
+ export default BarcodeManager;
@@ -0,0 +1,263 @@
1
+ /**
2
+ * BarcodeManager - Canonical Barcode Manager (merged from 2 implementations)
3
+ *
4
+ * Consolidates:
5
+ * - src/barcode-manager.ts BarcodeManager (detection + counting + format-based query)
6
+ * - src/managers/barcode-signature-rendering.ts BarcodesManager (generation + conversion + page embedding)
7
+ *
8
+ * Provides complete barcode operations.
9
+ */
10
+ import { EventEmitter } from 'events';
11
+ // =============================================================================
12
+ // Type Definitions
13
+ // =============================================================================
14
+ export var BarcodeFormat;
15
+ (function (BarcodeFormat) {
16
+ BarcodeFormat["CODE128"] = "CODE128";
17
+ BarcodeFormat["CODE39"] = "CODE39";
18
+ BarcodeFormat["EAN13"] = "EAN13";
19
+ BarcodeFormat["EAN8"] = "EAN8";
20
+ BarcodeFormat["UPCA"] = "UPCA";
21
+ BarcodeFormat["UPCE"] = "UPCE";
22
+ BarcodeFormat["QR"] = "QR";
23
+ BarcodeFormat["PDF417"] = "PDF417";
24
+ BarcodeFormat["DATAMATRIX"] = "DATAMATRIX";
25
+ BarcodeFormat["AZTEC"] = "AZTEC";
26
+ // Numeric format codes from BarcodesManager
27
+ BarcodeFormat["QR_CODE"] = "QR_CODE";
28
+ BarcodeFormat["DATA_MATRIX"] = "DATA_MATRIX";
29
+ BarcodeFormat["CODE_93"] = "CODE_93";
30
+ })(BarcodeFormat || (BarcodeFormat = {}));
31
+ export var BarcodeErrorCorrection;
32
+ (function (BarcodeErrorCorrection) {
33
+ BarcodeErrorCorrection["L"] = "L";
34
+ BarcodeErrorCorrection["M"] = "M";
35
+ BarcodeErrorCorrection["Q"] = "Q";
36
+ BarcodeErrorCorrection["H"] = "H";
37
+ })(BarcodeErrorCorrection || (BarcodeErrorCorrection = {}));
38
+ export var QrErrorCorrection;
39
+ (function (QrErrorCorrection) {
40
+ QrErrorCorrection[QrErrorCorrection["L"] = 0] = "L";
41
+ QrErrorCorrection[QrErrorCorrection["M"] = 1] = "M";
42
+ QrErrorCorrection[QrErrorCorrection["Q"] = 2] = "Q";
43
+ QrErrorCorrection[QrErrorCorrection["H"] = 3] = "H";
44
+ })(QrErrorCorrection || (QrErrorCorrection = {}));
45
+ // =============================================================================
46
+ // Canonical BarcodeManager
47
+ // =============================================================================
48
+ export class BarcodeManager extends EventEmitter {
49
+ constructor(document) {
50
+ super();
51
+ this.resultCache = new Map();
52
+ this.maxCacheSize = 100;
53
+ this.document = document;
54
+ try {
55
+ this.native = require('../../index.node');
56
+ }
57
+ catch {
58
+ this.native = null;
59
+ }
60
+ }
61
+ // ===========================================================================
62
+ // Detection (from root BarcodeManager)
63
+ // ===========================================================================
64
+ async detectBarcodes(pageIndex) {
65
+ const cacheKey = `barcodes:detect:${pageIndex}`;
66
+ if (this.resultCache.has(cacheKey))
67
+ return this.resultCache.get(cacheKey);
68
+ let barcodes = [];
69
+ if (this.native?.detect_barcodes) {
70
+ try {
71
+ const barcodesJson = this.native.detect_barcodes(pageIndex) ?? [];
72
+ barcodes =
73
+ barcodesJson.length > 0 ? barcodesJson.map((json) => JSON.parse(json)) : [];
74
+ }
75
+ catch {
76
+ barcodes = [];
77
+ }
78
+ }
79
+ this.setCached(cacheKey, barcodes);
80
+ this.emit('barcodesDetected', { page: pageIndex, count: barcodes.length });
81
+ return barcodes;
82
+ }
83
+ async detectAllBarcodes() {
84
+ const cacheKey = 'barcodes:detect_all';
85
+ if (this.resultCache.has(cacheKey))
86
+ return this.resultCache.get(cacheKey);
87
+ let barcodes = new Map();
88
+ if (this.native?.detect_all_barcodes) {
89
+ try {
90
+ const barcodesJson = this.native.detect_all_barcodes();
91
+ const parsed = JSON.parse(barcodesJson);
92
+ for (const [page, barcodesArray] of Object.entries(parsed)) {
93
+ barcodes.set(parseInt(page), barcodesArray.map((b) => JSON.parse(typeof b === 'string' ? b : JSON.stringify(b))));
94
+ }
95
+ }
96
+ catch {
97
+ barcodes = new Map();
98
+ }
99
+ }
100
+ this.setCached(cacheKey, barcodes);
101
+ this.emit('allBarcodesDetected', { pages: barcodes.size });
102
+ return barcodes;
103
+ }
104
+ async getBarcodesOfFormat(format, pageIndex) {
105
+ const cacheKey = pageIndex
106
+ ? `barcodes:format:${format}:${pageIndex}`
107
+ : `barcodes:format:${format}:all`;
108
+ if (this.resultCache.has(cacheKey))
109
+ return this.resultCache.get(cacheKey);
110
+ let barcodes = [];
111
+ if (this.native?.get_barcodes_of_format) {
112
+ try {
113
+ const page = pageIndex ?? -1;
114
+ const barcodesJson = this.native.get_barcodes_of_format(format, page) ?? [];
115
+ barcodes =
116
+ barcodesJson.length > 0 ? barcodesJson.map((json) => JSON.parse(json)) : [];
117
+ }
118
+ catch {
119
+ barcodes = [];
120
+ }
121
+ }
122
+ this.setCached(cacheKey, barcodes);
123
+ return barcodes;
124
+ }
125
+ async getBarcodeCount() {
126
+ const cacheKey = 'barcodes:count';
127
+ if (this.resultCache.has(cacheKey))
128
+ return this.resultCache.get(cacheKey);
129
+ const count = this.native?.get_barcode_count?.() ?? 0;
130
+ this.setCached(cacheKey, count);
131
+ return count;
132
+ }
133
+ async getCountByFormat(format) {
134
+ const cacheKey = `barcodes:count:${format}`;
135
+ if (this.resultCache.has(cacheKey))
136
+ return this.resultCache.get(cacheKey);
137
+ const count = this.native?.get_count_by_format?.(format) ?? 0;
138
+ this.setCached(cacheKey, count);
139
+ return count;
140
+ }
141
+ async hasBarcode(pageIndex) {
142
+ const barcodes = await this.detectBarcodes(pageIndex);
143
+ return barcodes.length > 0;
144
+ }
145
+ // ===========================================================================
146
+ // Generation (from root BarcodeManager + BarcodesManager)
147
+ // ===========================================================================
148
+ async generateBarcode(data, config) {
149
+ const format = config?.format ?? BarcodeFormat.QR;
150
+ const cacheKey = `barcodes:generate:${data}:${format}`;
151
+ if (this.resultCache.has(cacheKey))
152
+ return this.resultCache.get(cacheKey);
153
+ let imageData = Buffer.alloc(0);
154
+ if (this.native?.generate_barcode) {
155
+ try {
156
+ const configJson = config ? JSON.stringify(config) : '{}';
157
+ const result = this.native.generate_barcode(data, configJson);
158
+ imageData = Buffer.from(result);
159
+ }
160
+ catch {
161
+ imageData = Buffer.alloc(0);
162
+ }
163
+ }
164
+ this.setCached(cacheKey, imageData);
165
+ this.emit('barcodeGenerated', { format, dataLength: data.length });
166
+ return imageData;
167
+ }
168
+ async generateQrCode(data, errorCorrection = QrErrorCorrection.M, sizePx = 256) {
169
+ try {
170
+ if (!data || typeof data !== 'string')
171
+ throw new Error('Data must be a non-empty string');
172
+ if (sizePx < 1 || sizePx > 10000)
173
+ throw new Error('Size must be between 1 and 10000 pixels');
174
+ const barcodeData = await this.document?.generateQrCode?.(data, errorCorrection, sizePx);
175
+ this.emit('barcodeGenerated', { format: 'qr', size: sizePx });
176
+ return barcodeData || Buffer.alloc(0);
177
+ }
178
+ catch (error) {
179
+ this.emit('error', error);
180
+ throw error;
181
+ }
182
+ }
183
+ // ===========================================================================
184
+ // Conversion (from BarcodesManager)
185
+ // ===========================================================================
186
+ async barcodeToPng(barcodeData, sizePx = 256) {
187
+ return barcodeData;
188
+ }
189
+ async barcodeToSvg(barcodeData, sizePx = 256) {
190
+ // Legacy: wraps existing PNG bytes in an SVG <image> element.
191
+ // For real vector SVG use generateBarcodeSvg() / generateQrCodeSvg() from the top-level API.
192
+ const encoded = barcodeData.toString('base64');
193
+ return `<svg xmlns="http://www.w3.org/2000/svg"><image href="data:image/png;base64,${encoded}"/></svg>`;
194
+ }
195
+ async generateSvg(data, config) {
196
+ const format = config?.format ?? BarcodeFormat.CODE128;
197
+ if (this.native?.generateBarcode && this.native?.barcodeGetSVG && this.native?.freeBarcode) {
198
+ const handle = this.native.generateBarcode(format, data);
199
+ try {
200
+ return this.native.barcodeGetSVG(handle, config?.sizePx ?? 300);
201
+ }
202
+ finally {
203
+ this.native.freeBarcode(handle);
204
+ }
205
+ }
206
+ return '';
207
+ }
208
+ async generateQrSvg(data, errorCorrection = QrErrorCorrection.M, sizePx = 300) {
209
+ if (this.native?.generateQRCode && this.native?.barcodeGetSVG && this.native?.freeBarcode) {
210
+ const handle = this.native.generateQRCode(data, errorCorrection);
211
+ try {
212
+ return this.native.barcodeGetSVG(handle, sizePx);
213
+ }
214
+ finally {
215
+ this.native.freeBarcode(handle);
216
+ }
217
+ }
218
+ return '';
219
+ }
220
+ async addBarcodeToPage(pageIndex, barcodeData, x, y, width, height) {
221
+ try {
222
+ if (!this.document)
223
+ throw new Error('Document required for adding barcode to page');
224
+ return false;
225
+ }
226
+ catch (error) {
227
+ this.emit('error', error);
228
+ throw error;
229
+ }
230
+ }
231
+ detectBarcodeFormat(barcodeData) {
232
+ return BarcodeFormat.QR;
233
+ }
234
+ decodeBarcodeData(barcodeData) {
235
+ return '';
236
+ }
237
+ getDetectionConfidence(barcodeData) {
238
+ return 1.0;
239
+ }
240
+ // ===========================================================================
241
+ // Cache
242
+ // ===========================================================================
243
+ clearCache() {
244
+ this.resultCache.clear();
245
+ this.emit('cacheCleared');
246
+ }
247
+ getCacheStats() {
248
+ return {
249
+ cacheSize: this.resultCache.size,
250
+ maxCacheSize: this.maxCacheSize,
251
+ entries: Array.from(this.resultCache.keys()),
252
+ };
253
+ }
254
+ setCached(key, value) {
255
+ this.resultCache.set(key, value);
256
+ if (this.resultCache.size > this.maxCacheSize) {
257
+ const firstKey = this.resultCache.keys().next().value;
258
+ if (firstKey !== undefined)
259
+ this.resultCache.delete(firstKey);
260
+ }
261
+ }
262
+ }
263
+ export default BarcodeManager;