web-annotation-renderer 0.1.4 → 0.3.0

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 (51) hide show
  1. package/README.md +176 -6
  2. package/ai-tools.js +11 -0
  3. package/dist/index.cjs +1 -1
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.js +41 -25
  6. package/dist/index.js.map +1 -1
  7. package/dist/index12.cjs +1 -1
  8. package/dist/index12.cjs.map +1 -1
  9. package/dist/index12.js +118 -189
  10. package/dist/index12.js.map +1 -1
  11. package/dist/index13.cjs +1 -1
  12. package/dist/index13.cjs.map +1 -1
  13. package/dist/index13.js +200 -15
  14. package/dist/index13.js.map +1 -1
  15. package/dist/index14.cjs +1 -1
  16. package/dist/index14.cjs.map +1 -1
  17. package/dist/index14.js +15 -123
  18. package/dist/index14.js.map +1 -1
  19. package/dist/index15.cjs +1 -1
  20. package/dist/index15.cjs.map +1 -1
  21. package/dist/index15.js +123 -32
  22. package/dist/index15.js.map +1 -1
  23. package/dist/index16.cjs +2 -0
  24. package/dist/index16.cjs.map +1 -0
  25. package/dist/index16.js +219 -0
  26. package/dist/index16.js.map +1 -0
  27. package/dist/index17.cjs +2 -0
  28. package/dist/index17.cjs.map +1 -0
  29. package/dist/index17.js +44 -0
  30. package/dist/index17.js.map +1 -0
  31. package/dist/index18.cjs +2 -0
  32. package/dist/index18.cjs.map +1 -0
  33. package/dist/index18.js +40 -0
  34. package/dist/index18.js.map +1 -0
  35. package/dist/index19.cjs +2 -0
  36. package/dist/index19.cjs.map +1 -0
  37. package/dist/index19.js +41 -0
  38. package/dist/index19.js.map +1 -0
  39. package/dist/index20.cjs +2 -0
  40. package/dist/index20.cjs.map +1 -0
  41. package/dist/index20.js +50 -0
  42. package/dist/index20.js.map +1 -0
  43. package/dist/index21.cjs +2 -0
  44. package/dist/index21.cjs.map +1 -0
  45. package/dist/index21.js +35 -0
  46. package/dist/index21.js.map +1 -0
  47. package/dist/index22.cjs +2 -0
  48. package/dist/index22.cjs.map +1 -0
  49. package/dist/index22.js +8 -0
  50. package/dist/index22.js.map +1 -0
  51. package/package.json +10 -1
package/README.md CHANGED
@@ -10,13 +10,15 @@ This library renders structured annotation data (highlights, text boxes, drawing
10
10
  ## Features
11
11
 
12
12
  - 📄 **PDF Rendering** - Built on pdf.js for reliable PDF display
13
- - ⏱️ **Timeline Synchronization** - Sync annotations with audio/video playback
13
+ - ⏱️ **Timeline Synchronization** - Sync annotations with audio/video playback or manual controls
14
14
  - 🎨 **Multiple Annotation Types** - Highlights, text boxes, and ink drawings
15
15
  - ⚛️ **Framework Agnostic** - Core engine works with any framework
16
16
  - ⚛️ **React Adapter** - Ready-to-use React component included
17
17
  - 🎯 **Progressive Animations** - Smooth reveal animations based on timeline
18
+ - 🎬 **Continuous Sync** - Built-in support for real-time audio/video synchronization
18
19
  - 📦 **Simple Setup** - One-line worker configuration
19
20
  - 🌲 **Tree-shakeable** - Import only what you need
21
+ - ⚡ **Performance Optimized** - Efficient rendering without unnecessary re-draws
20
22
 
21
23
  ## Installation
22
24
 
@@ -145,6 +147,104 @@ function App() {
145
147
  }
146
148
  ```
147
149
 
150
+ ## Audio/Video Synchronization
151
+
152
+ For smooth, real-time synchronization with audio or video playback, use the continuous sync feature:
153
+
154
+ ### Vanilla JavaScript
155
+
156
+ ```javascript
157
+ const renderer = new AnnotationRenderer({
158
+ container: document.getElementById("annotation-container"),
159
+ canvasElement: document.getElementById("pdf-canvas"),
160
+ });
161
+
162
+ await renderer.loadPDF("/document.pdf");
163
+ await renderer.setPage(1);
164
+
165
+ // Get reference to audio/video element
166
+ const audioElement = document.getElementById("lecture-audio");
167
+
168
+ // Start continuous sync when playback begins
169
+ audioElement.addEventListener("play", () => {
170
+ renderer.timelineSync.startContinuousSync(() => audioElement.currentTime);
171
+ });
172
+
173
+ // Stop continuous sync when playback pauses
174
+ audioElement.addEventListener("pause", () => {
175
+ renderer.timelineSync.stopContinuousSync();
176
+ });
177
+
178
+ // Clean up on page unload
179
+ window.addEventListener("beforeunload", () => {
180
+ renderer.timelineSync.stopContinuousSync();
181
+ renderer.destroy();
182
+ });
183
+ ```
184
+
185
+ ### React
186
+
187
+ ```javascript
188
+ import { useRef, useEffect } from "react";
189
+ import { AnnotPdf } from "web-annotation-renderer";
190
+
191
+ function VideoSyncViewer() {
192
+ const audioRef = useRef(null);
193
+ const engineRef = useRef(null);
194
+
195
+ // Access the internal engine through the component
196
+ useEffect(() => {
197
+ const audio = audioRef.current;
198
+ if (!audio) return;
199
+
200
+ const handlePlay = () => {
201
+ // Start continuous sync at 60fps
202
+ if (engineRef.current) {
203
+ engineRef.current.timelineSync.startContinuousSync(
204
+ () => audio.currentTime
205
+ );
206
+ }
207
+ };
208
+
209
+ const handlePause = () => {
210
+ // Stop continuous sync
211
+ if (engineRef.current) {
212
+ engineRef.current.timelineSync.stopContinuousSync();
213
+ }
214
+ };
215
+
216
+ audio.addEventListener("play", handlePlay);
217
+ audio.addEventListener("pause", handlePause);
218
+
219
+ return () => {
220
+ audio.removeEventListener("play", handlePlay);
221
+ audio.removeEventListener("pause", handlePause);
222
+ engineRef.current?.timelineSync.stopContinuousSync();
223
+ };
224
+ }, []);
225
+
226
+ return (
227
+ <div>
228
+ <AnnotPdf
229
+ ref={engineRef}
230
+ pdfUrl="/lecture.pdf"
231
+ annotations={annotations}
232
+ onLoad={(doc) => console.log("PDF loaded")}
233
+ />
234
+ <audio ref={audioRef} src="/lecture.mp3" controls />
235
+ </div>
236
+ );
237
+ }
238
+ ```
239
+
240
+ **How it works:**
241
+ - `startContinuousSync()` creates a 60fps requestAnimationFrame loop
242
+ - Each frame reads the current time from your callback function
243
+ - Annotations update smoothly in sync with playback
244
+ - `stopContinuousSync()` stops the loop to save resources when paused
245
+
246
+ **For manual controls** (sliders, buttons), simply use `renderer.setTime()` or the `currentTime` prop - continuous sync is not needed.
247
+
148
248
  ## API Reference
149
249
 
150
250
  ### AnnotationRenderer Class
@@ -303,6 +403,69 @@ renderer.destroy();
303
403
 
304
404
  ---
305
405
 
406
+ ### TimelineSync API
407
+
408
+ The `AnnotationRenderer` exposes a `timelineSync` property for advanced timeline control.
409
+
410
+ #### `timelineSync.startContinuousSync(getTimeFunction)`
411
+
412
+ Start continuous timeline synchronization with audio/video.
413
+
414
+ ```javascript
415
+ renderer.timelineSync.startContinuousSync(() => audioElement.currentTime);
416
+ ```
417
+
418
+ **Parameters:**
419
+
420
+ - `getTimeFunction` (Function): Callback that returns current time in seconds
421
+
422
+ **Returns:** `void`
423
+
424
+ **Details:** Creates a 60fps requestAnimationFrame loop that continuously reads time from the callback and updates annotations. Use this for smooth audio/video synchronization.
425
+
426
+ #### `timelineSync.stopContinuousSync()`
427
+
428
+ Stop continuous timeline synchronization.
429
+
430
+ ```javascript
431
+ renderer.timelineSync.stopContinuousSync();
432
+ ```
433
+
434
+ **Returns:** `void`
435
+
436
+ **Important:** Always call this when audio/video pauses or when cleaning up to prevent unnecessary rendering.
437
+
438
+ #### `timelineSync.getCurrentTime()`
439
+
440
+ Get the current timeline position.
441
+
442
+ ```javascript
443
+ const currentTime = renderer.timelineSync.getCurrentTime();
444
+ ```
445
+
446
+ **Returns:** `number` - Current timeline position in seconds
447
+
448
+ #### `timelineSync.subscribe(callback)`
449
+
450
+ Subscribe to timeline updates.
451
+
452
+ ```javascript
453
+ const unsubscribe = renderer.timelineSync.subscribe((time) => {
454
+ console.log("Timeline updated:", time);
455
+ });
456
+
457
+ // Later: unsubscribe
458
+ unsubscribe();
459
+ ```
460
+
461
+ **Parameters:**
462
+
463
+ - `callback` (Function): Called when timeline updates with current time
464
+
465
+ **Returns:** `Function` - Unsubscribe function
466
+
467
+ ---
468
+
306
469
  ### AnnotPdf Component (React)
307
470
 
308
471
  #### Props
@@ -713,11 +876,13 @@ pdfjsLib.GlobalWorkerOptions.workerSrc = new URL(
713
876
  npm install --save-dev @types/react @types/react-dom
714
877
  ```
715
878
 
716
- ### Canvas rendering issues in React StrictMode
879
+ ### Timeline updates feel sluggish
717
880
 
718
- **Symptoms:** Double rendering or canvas errors in development
881
+ **Symptoms:** Annotations don't update smoothly when dragging timeline slider
719
882
 
720
- **Solution:** Consider removing `<React.StrictMode>` wrapper during development (it's safe to keep in production).
883
+ **Solution:**
884
+ - For manual controls (sliders, buttons): Use `renderer.setTime()` or the `currentTime` prop directly - the system is optimized for discrete updates
885
+ - For audio/video: Use `timelineSync.startContinuousSync()` for smooth 60fps synchronization
721
886
 
722
887
  ## Migration Guide
723
888
 
@@ -753,8 +918,8 @@ renderer.setTime(5.0);
753
918
 
754
919
  Check out working examples in the test projects:
755
920
 
756
- - **Vanilla JavaScript:** See `test-vanilla/` for a complete implementation
757
- - **React:** See `test-react/` for React component usage
921
+ - **Vanilla JavaScript:** See `examples/vanilla-js/` for a complete implementation with manual timeline control
922
+ - **React:** See `examples/react-basic/` for React component usage with slider controls
758
923
 
759
924
  Both examples include:
760
925
 
@@ -762,6 +927,11 @@ Both examples include:
762
927
  - Page navigation and zoom controls
763
928
  - Timeline slider with annotation synchronization
764
929
  - All three annotation types (highlight, text, ink)
930
+ - Optimized rendering for smooth, flicker-free updates
931
+
932
+ **Use Cases:**
933
+ - **Manual timeline control** (sliders, buttons): Use `setTime()` for discrete updates
934
+ - **Audio/video sync**: Use `timelineSync.startContinuousSync()` for continuous 60fps updates
765
935
 
766
936
  ## License
767
937
 
package/ai-tools.js ADDED
@@ -0,0 +1,11 @@
1
+ /**
2
+ * AI Tools Entry Point
3
+ *
4
+ * Provides AI annotation tools without PDF renderer dependencies.
5
+ * This file only re-exports the tools modules to avoid DOMMatrix issues in Node.js.
6
+ */
7
+
8
+ export { annotationTools, getAnnotationTools } from './dist/index16.js';
9
+ export { createHighlight } from './dist/index18.js';
10
+ export { createText } from './dist/index19.js';
11
+ export { createInk } from './dist/index20.js';
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./index2.cjs"),r=require("./index3.cjs"),n=require("./index4.cjs"),t=require("./index5.cjs"),i=require("./index6.cjs"),a=require("./index7.cjs"),o=require("./index8.cjs"),s=require("./index9.cjs"),c=require("./index10.cjs"),d=require("./index11.cjs"),l=require("./index12.cjs"),u=require("./index13.cjs"),y=require("./index14.cjs"),q="0.1.0",L="web-annotation-renderer";exports.AnnotationRenderer=e.AnnotationRenderer;exports.PDFRenderer=r.PDFRenderer;exports.LayerManager=n.LayerManager;exports.TimelineSync=t.TimelineSync;exports.BaseLayer=i.default;exports.HighlightLayer=a.default;exports.TextLayer=o.default;exports.DrawingLayer=s.default;exports.coordinateUtils=c;exports.viewportUtils=d;exports.normalizeAnnotationArray=l.normalizeAnnotationArray;exports.TypeValidators=u;exports.AnnotPdf=y.default;exports.LIB_NAME=L;exports.VERSION=q;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const n=require("./index2.cjs"),a=require("./index3.cjs"),o=require("./index4.cjs"),i=require("./index5.cjs"),l=require("./index6.cjs"),c=require("./index7.cjs"),s=require("./index8.cjs"),u=require("./index9.cjs"),d=require("./index10.cjs"),g=require("./index11.cjs"),e=require("./index12.cjs"),q=require("./index13.cjs"),y=require("./index14.cjs"),T=require("./index15.cjs"),r=require("./index16.cjs"),t=require("./index17.cjs"),h=require("./index18.cjs"),A=require("./index19.cjs"),x=require("./index20.cjs"),L="0.3.0",f="web-annotation-renderer";exports.AnnotationRenderer=n.AnnotationRenderer;exports.PDFRenderer=a.PDFRenderer;exports.LayerManager=o.LayerManager;exports.TimelineSync=i.TimelineSync;exports.BaseLayer=l.default;exports.HighlightLayer=c.default;exports.TextLayer=s.default;exports.DrawingLayer=u.default;exports.coordinateUtils=d;exports.viewportUtils=g;exports.extractAllBlocks=e.extractAllBlocks;exports.extractMultiplePages=e.extractMultiplePages;exports.extractPDFBlocks=e.extractAllBlocks;exports.normalizeAnnotationArray=q.normalizeAnnotationArray;exports.TypeValidators=y;exports.AnnotPdf=T.default;exports.annotationTools=r.annotationTools;exports.getAnnotationTools=r.getAnnotationTools;exports.handleToolCall=t.handleToolCall;exports.handleToolCalls=t.handleToolCalls;exports.createHighlight=h.createHighlight;exports.createText=A.createText;exports.createInk=x.createInk;exports.LIB_NAME=f;exports.VERSION=L;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../src/index.js"],"sourcesContent":["/**\n * @ai-annotator/renderer - Public API\n *\n * Single entry point for the Dynamic PDF Annotation Renderer library.\n * Exports all core subsystems, layers, utilities, and types.\n *\n * @module @ai-annotator/renderer\n */\n\n// ============================================================================\n// Core Rendering Engine\n// ============================================================================\n\n// Import statements\nimport { AnnotationRenderer } from './core/AnnotationRenderer.js';\nimport { PDFRenderer } from './core/PDFRenderer.js';\nimport { LayerManager } from './core/LayerManager.js';\nimport { TimelineSync } from './core/TimelineSync.js';\n\n// Export statements\nexport { AnnotationRenderer };\nexport { PDFRenderer };\nexport { LayerManager };\nexport { TimelineSync };\n\n// ============================================================================\n// Annotation Layers\n// ============================================================================\n\n// Framework-agnostic layer classes\n// BaseLayer: Abstract base class for creating custom layers\n// HighlightLayer, TextLayer, DrawingLayer: Built-in layer implementations\n\nimport BaseLayer from './layers/BaseLayer.js';\nimport HighlightLayer from './layers/HighlightLayer.js';\nimport TextLayer from './layers/TextLayer.js';\nimport DrawingLayer from './layers/DrawingLayer.js';\n\nexport { BaseLayer };\nexport { HighlightLayer };\nexport { TextLayer };\nexport { DrawingLayer };\n\n// ============================================================================\n// Utilities\n// ============================================================================\n\nimport * as coordinateUtils from './utils/coordinateUtils.js';\nimport * as viewportUtils from './utils/viewportUtils.js';\n\nexport { coordinateUtils };\nexport { viewportUtils };\n\n// Future: colorUtils, validators\n// import * as colorUtils from './utils/colorUtils.js';\n// export { colorUtils };\n\n// ============================================================================\n// Type Definitions & Validators\n// ============================================================================\n\n// Type definitions in src/types/annotations.js\n\n/**\n * Type Validators - Optional data normalization\n *\n * Import separately to use defensive normalization for annotation data.\n * These validators are standalone utilities that do not modify the core system.\n */\nexport { normalizeAnnotationArray } from './types/validators.js';\n\n// Namespace export for all validator utilities\nexport * as TypeValidators from './types/index.js';\n\n// ============================================================================\n// Framework Adapters\n// ============================================================================\n// Declarative framework-specific wrappers for AnnotationRenderer\n// These provide idiomatic APIs for React, Vue, and other frameworks\n\n/**\n * React adapter component for declarative PDF annotation rendering\n * @see {@link AnnotPdf}\n */\nexport { AnnotPdf } from './adapters/index.js';\n\n// Future framework adapters will be exported here:\n// export { VuePdfViewer } from './adapters/index.js';\n// export { SveltePdfViewer } from './adapters/index.js';\n\n// ============================================================================\n// Package Metadata\n// ============================================================================\n\n/**\n * Library version\n * @constant {string}\n */\nexport const VERSION = '0.1.0';\n\n/**\n * Library name\n * @constant {string}\n */\nexport const LIB_NAME = 'web-annotation-renderer';\n"],"names":["VERSION","LIB_NAME"],"mappings":"6aAkGaA,EAAU,QAMVC,EAAW"}
1
+ {"version":3,"file":"index.cjs","sources":["../src/index.js"],"sourcesContent":["/**\n * @ai-annotator/renderer - Public API\n *\n * Single entry point for the Dynamic PDF Annotation Renderer library.\n * Exports all core subsystems, layers, utilities, and types.\n *\n * @module @ai-annotator/renderer\n */\n\n// ============================================================================\n// Core Rendering Engine\n// ============================================================================\n\n// Import statements\nimport { AnnotationRenderer } from './core/AnnotationRenderer.js';\nimport { PDFRenderer } from './core/PDFRenderer.js';\nimport { LayerManager } from './core/LayerManager.js';\nimport { TimelineSync } from './core/TimelineSync.js';\n\n// Export statements\nexport { AnnotationRenderer };\nexport { PDFRenderer };\nexport { LayerManager };\nexport { TimelineSync };\n\n// ============================================================================\n// Annotation Layers\n// ============================================================================\n\n// Framework-agnostic layer classes\n// BaseLayer: Abstract base class for creating custom layers\n// HighlightLayer, TextLayer, DrawingLayer: Built-in layer implementations\n\nimport BaseLayer from './layers/BaseLayer.js';\nimport HighlightLayer from './layers/HighlightLayer.js';\nimport TextLayer from './layers/TextLayer.js';\nimport DrawingLayer from './layers/DrawingLayer.js';\n\nexport { BaseLayer };\nexport { HighlightLayer };\nexport { TextLayer };\nexport { DrawingLayer };\n\n// ============================================================================\n// Utilities\n// ============================================================================\n\nimport * as coordinateUtils from './utils/coordinateUtils.js';\nimport * as viewportUtils from './utils/viewportUtils.js';\n\nexport { coordinateUtils };\nexport { viewportUtils };\n\n// Future: colorUtils, validators\n// import * as colorUtils from './utils/colorUtils.js';\n// export { colorUtils };\n\n// ============================================================================\n// PDF Extraction Utilities\n// ============================================================================\n\n/**\n * PDF data extraction utilities for text and image blocks\n * Uses PDF.js getOperatorList() for efficient metadata extraction without rendering\n */\nimport { extractAllBlocks, extractMultiplePages } from './utils/pdfExtractor.js';\n\nexport { extractAllBlocks };\nexport { extractMultiplePages };\n\n// Alias for backwards compatibility and API consistency\nexport { extractAllBlocks as extractPDFBlocks };\n\n// ============================================================================\n// Type Definitions & Validators\n// ============================================================================\n\n// Type definitions in src/types/annotations.js\n\n/**\n * Type Validators - Optional data normalization\n *\n * Import separately to use defensive normalization for annotation data.\n * These validators are standalone utilities that do not modify the core system.\n */\nexport { normalizeAnnotationArray } from './types/validators.js';\n\n// Namespace export for all validator utilities\nexport * as TypeValidators from './types/index.js';\n\n// ============================================================================\n// Framework Adapters\n// ============================================================================\n// Declarative framework-specific wrappers for AnnotationRenderer\n// These provide idiomatic APIs for React, Vue, and other frameworks\n\n/**\n * React adapter component for declarative PDF annotation rendering\n * @see {@link AnnotPdf}\n */\nexport { AnnotPdf } from './adapters/index.js';\n\n// Future framework adapters will be exported here:\n// export { VuePdfViewer } from './adapters/index.js';\n// export { SveltePdfViewer } from './adapters/index.js';\n\n// ============================================================================\n// AI Tools for Annotation Generation\n// ============================================================================\n\n/**\n * AI-powered annotation generation tools\n *\n * Provides OpenAI-compatible function calling schemas and handlers\n * for generating PDF annotations with AI models.\n *\n * @see {@link module:ai-tools}\n */\nexport {\n annotationTools,\n getAnnotationTools,\n handleToolCall,\n handleToolCalls,\n createHighlight,\n createText,\n createInk\n} from './ai-tools/index.js';\n\n// ============================================================================\n// Package Metadata\n// ============================================================================\n\n/**\n * Library version\n * @constant {string}\n */\nexport const VERSION = '0.3.0';\n\n/**\n * Library name\n * @constant {string}\n */\nexport const LIB_NAME = 'web-annotation-renderer';\n"],"names":["VERSION","LIB_NAME"],"mappings":"+kBAwIaA,EAAU,QAMVC,EAAW"}
package/dist/index.js CHANGED
@@ -1,32 +1,48 @@
1
- import { AnnotationRenderer as p } from "./index2.js";
2
- import { PDFRenderer as m } from "./index3.js";
3
- import { LayerManager as s } from "./index4.js";
4
- import { TimelineSync as l } from "./index5.js";
5
- import { default as L } from "./index6.js";
1
+ import { AnnotationRenderer as x } from "./index2.js";
2
+ import { PDFRenderer as f } from "./index3.js";
3
+ import { LayerManager as i } from "./index4.js";
4
+ import { TimelineSync as c } from "./index5.js";
5
+ import { default as g } from "./index6.js";
6
6
  import { default as A } from "./index7.js";
7
- import { default as g } from "./index8.js";
8
- import { default as R } from "./index9.js";
9
- import * as r from "./index10.js";
10
- import * as e from "./index11.js";
11
- import { normalizeAnnotationArray as h } from "./index12.js";
12
- import * as o from "./index13.js";
13
- import { default as D } from "./index14.js";
14
- const t = "0.1.0", a = "web-annotation-renderer";
7
+ import { default as h } from "./index8.js";
8
+ import { default as L } from "./index9.js";
9
+ import * as o from "./index10.js";
10
+ import * as r from "./index11.js";
11
+ import { extractAllBlocks as k, extractMultiplePages as P, extractAllBlocks as w } from "./index12.js";
12
+ import { normalizeAnnotationArray as I } from "./index13.js";
13
+ import * as e from "./index14.js";
14
+ import { default as R } from "./index15.js";
15
+ import { annotationTools as E, getAnnotationTools as F } from "./index16.js";
16
+ import { handleToolCall as N, handleToolCalls as S } from "./index17.js";
17
+ import { createHighlight as V } from "./index18.js";
18
+ import { createText as v } from "./index19.js";
19
+ import { createInk as O } from "./index20.js";
20
+ const t = "0.3.0", a = "web-annotation-renderer";
15
21
  export {
16
- D as AnnotPdf,
17
- p as AnnotationRenderer,
18
- L as BaseLayer,
19
- R as DrawingLayer,
22
+ R as AnnotPdf,
23
+ x as AnnotationRenderer,
24
+ g as BaseLayer,
25
+ L as DrawingLayer,
20
26
  A as HighlightLayer,
21
27
  a as LIB_NAME,
22
- s as LayerManager,
23
- m as PDFRenderer,
24
- g as TextLayer,
25
- l as TimelineSync,
26
- o as TypeValidators,
28
+ i as LayerManager,
29
+ f as PDFRenderer,
30
+ h as TextLayer,
31
+ c as TimelineSync,
32
+ e as TypeValidators,
27
33
  t as VERSION,
28
- r as coordinateUtils,
29
- h as normalizeAnnotationArray,
30
- e as viewportUtils
34
+ E as annotationTools,
35
+ o as coordinateUtils,
36
+ V as createHighlight,
37
+ O as createInk,
38
+ v as createText,
39
+ k as extractAllBlocks,
40
+ P as extractMultiplePages,
41
+ w as extractPDFBlocks,
42
+ F as getAnnotationTools,
43
+ N as handleToolCall,
44
+ S as handleToolCalls,
45
+ I as normalizeAnnotationArray,
46
+ r as viewportUtils
31
47
  };
32
48
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/index.js"],"sourcesContent":["/**\n * @ai-annotator/renderer - Public API\n *\n * Single entry point for the Dynamic PDF Annotation Renderer library.\n * Exports all core subsystems, layers, utilities, and types.\n *\n * @module @ai-annotator/renderer\n */\n\n// ============================================================================\n// Core Rendering Engine\n// ============================================================================\n\n// Import statements\nimport { AnnotationRenderer } from './core/AnnotationRenderer.js';\nimport { PDFRenderer } from './core/PDFRenderer.js';\nimport { LayerManager } from './core/LayerManager.js';\nimport { TimelineSync } from './core/TimelineSync.js';\n\n// Export statements\nexport { AnnotationRenderer };\nexport { PDFRenderer };\nexport { LayerManager };\nexport { TimelineSync };\n\n// ============================================================================\n// Annotation Layers\n// ============================================================================\n\n// Framework-agnostic layer classes\n// BaseLayer: Abstract base class for creating custom layers\n// HighlightLayer, TextLayer, DrawingLayer: Built-in layer implementations\n\nimport BaseLayer from './layers/BaseLayer.js';\nimport HighlightLayer from './layers/HighlightLayer.js';\nimport TextLayer from './layers/TextLayer.js';\nimport DrawingLayer from './layers/DrawingLayer.js';\n\nexport { BaseLayer };\nexport { HighlightLayer };\nexport { TextLayer };\nexport { DrawingLayer };\n\n// ============================================================================\n// Utilities\n// ============================================================================\n\nimport * as coordinateUtils from './utils/coordinateUtils.js';\nimport * as viewportUtils from './utils/viewportUtils.js';\n\nexport { coordinateUtils };\nexport { viewportUtils };\n\n// Future: colorUtils, validators\n// import * as colorUtils from './utils/colorUtils.js';\n// export { colorUtils };\n\n// ============================================================================\n// Type Definitions & Validators\n// ============================================================================\n\n// Type definitions in src/types/annotations.js\n\n/**\n * Type Validators - Optional data normalization\n *\n * Import separately to use defensive normalization for annotation data.\n * These validators are standalone utilities that do not modify the core system.\n */\nexport { normalizeAnnotationArray } from './types/validators.js';\n\n// Namespace export for all validator utilities\nexport * as TypeValidators from './types/index.js';\n\n// ============================================================================\n// Framework Adapters\n// ============================================================================\n// Declarative framework-specific wrappers for AnnotationRenderer\n// These provide idiomatic APIs for React, Vue, and other frameworks\n\n/**\n * React adapter component for declarative PDF annotation rendering\n * @see {@link AnnotPdf}\n */\nexport { AnnotPdf } from './adapters/index.js';\n\n// Future framework adapters will be exported here:\n// export { VuePdfViewer } from './adapters/index.js';\n// export { SveltePdfViewer } from './adapters/index.js';\n\n// ============================================================================\n// Package Metadata\n// ============================================================================\n\n/**\n * Library version\n * @constant {string}\n */\nexport const VERSION = '0.1.0';\n\n/**\n * Library name\n * @constant {string}\n */\nexport const LIB_NAME = 'web-annotation-renderer';\n"],"names":["VERSION","LIB_NAME"],"mappings":";;;;;;;;;;;;;AAkGY,MAACA,IAAU,SAMVC,IAAW;"}
1
+ {"version":3,"file":"index.js","sources":["../src/index.js"],"sourcesContent":["/**\n * @ai-annotator/renderer - Public API\n *\n * Single entry point for the Dynamic PDF Annotation Renderer library.\n * Exports all core subsystems, layers, utilities, and types.\n *\n * @module @ai-annotator/renderer\n */\n\n// ============================================================================\n// Core Rendering Engine\n// ============================================================================\n\n// Import statements\nimport { AnnotationRenderer } from './core/AnnotationRenderer.js';\nimport { PDFRenderer } from './core/PDFRenderer.js';\nimport { LayerManager } from './core/LayerManager.js';\nimport { TimelineSync } from './core/TimelineSync.js';\n\n// Export statements\nexport { AnnotationRenderer };\nexport { PDFRenderer };\nexport { LayerManager };\nexport { TimelineSync };\n\n// ============================================================================\n// Annotation Layers\n// ============================================================================\n\n// Framework-agnostic layer classes\n// BaseLayer: Abstract base class for creating custom layers\n// HighlightLayer, TextLayer, DrawingLayer: Built-in layer implementations\n\nimport BaseLayer from './layers/BaseLayer.js';\nimport HighlightLayer from './layers/HighlightLayer.js';\nimport TextLayer from './layers/TextLayer.js';\nimport DrawingLayer from './layers/DrawingLayer.js';\n\nexport { BaseLayer };\nexport { HighlightLayer };\nexport { TextLayer };\nexport { DrawingLayer };\n\n// ============================================================================\n// Utilities\n// ============================================================================\n\nimport * as coordinateUtils from './utils/coordinateUtils.js';\nimport * as viewportUtils from './utils/viewportUtils.js';\n\nexport { coordinateUtils };\nexport { viewportUtils };\n\n// Future: colorUtils, validators\n// import * as colorUtils from './utils/colorUtils.js';\n// export { colorUtils };\n\n// ============================================================================\n// PDF Extraction Utilities\n// ============================================================================\n\n/**\n * PDF data extraction utilities for text and image blocks\n * Uses PDF.js getOperatorList() for efficient metadata extraction without rendering\n */\nimport { extractAllBlocks, extractMultiplePages } from './utils/pdfExtractor.js';\n\nexport { extractAllBlocks };\nexport { extractMultiplePages };\n\n// Alias for backwards compatibility and API consistency\nexport { extractAllBlocks as extractPDFBlocks };\n\n// ============================================================================\n// Type Definitions & Validators\n// ============================================================================\n\n// Type definitions in src/types/annotations.js\n\n/**\n * Type Validators - Optional data normalization\n *\n * Import separately to use defensive normalization for annotation data.\n * These validators are standalone utilities that do not modify the core system.\n */\nexport { normalizeAnnotationArray } from './types/validators.js';\n\n// Namespace export for all validator utilities\nexport * as TypeValidators from './types/index.js';\n\n// ============================================================================\n// Framework Adapters\n// ============================================================================\n// Declarative framework-specific wrappers for AnnotationRenderer\n// These provide idiomatic APIs for React, Vue, and other frameworks\n\n/**\n * React adapter component for declarative PDF annotation rendering\n * @see {@link AnnotPdf}\n */\nexport { AnnotPdf } from './adapters/index.js';\n\n// Future framework adapters will be exported here:\n// export { VuePdfViewer } from './adapters/index.js';\n// export { SveltePdfViewer } from './adapters/index.js';\n\n// ============================================================================\n// AI Tools for Annotation Generation\n// ============================================================================\n\n/**\n * AI-powered annotation generation tools\n *\n * Provides OpenAI-compatible function calling schemas and handlers\n * for generating PDF annotations with AI models.\n *\n * @see {@link module:ai-tools}\n */\nexport {\n annotationTools,\n getAnnotationTools,\n handleToolCall,\n handleToolCalls,\n createHighlight,\n createText,\n createInk\n} from './ai-tools/index.js';\n\n// ============================================================================\n// Package Metadata\n// ============================================================================\n\n/**\n * Library version\n * @constant {string}\n */\nexport const VERSION = '0.3.0';\n\n/**\n * Library name\n * @constant {string}\n */\nexport const LIB_NAME = 'web-annotation-renderer';\n"],"names":["VERSION","LIB_NAME"],"mappings":";;;;;;;;;;;;;;;;;;;AAwIY,MAACA,IAAU,SAMVC,IAAW;"}
package/dist/index12.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const l=require("./index15.cjs");function a(t,n,o,s,e){let i=t;return typeof t=="string"&&(i=parseFloat(t)),typeof i!="number"||isNaN(i)?(e.push(`[${o}]: Field "${s}" invalid value "${t}", using default ${n}`),n):i<0?(e.push(`[${o}]: Field "${s}" value ${i} below range [0,1], clamping to 0`),0):i>1?(e.push(`[${o}]: Field "${s}" value ${i} exceeds range [0,1], clamping to 1`),1):i}function d(t,n,o,s){if(typeof t!="string"||t.trim().length===0)return s.push(`[${o}]: Invalid color format "${t}", using default ${n}`),n;const e=t.trim(),i=/^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/,r=/^rgba?\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*(,\s*[\d.]+\s*)?\)$/,u=["red","blue","green","yellow","black","white","gray","grey","orange","purple","pink","brown","transparent"],h=i.test(e),$=r.test(e),A=u.includes(e.toLowerCase());return h||$||A?e:(s.push(`[${o}]: Invalid color format "${t}", using default ${n}`),n)}function f(t,n,o,s,e){let i=t;return typeof t=="string"&&(i=parseFloat(t)),typeof i!="number"||isNaN(i)||i<=0?(e.push(`[${o}]: Field "${s}" invalid value "${t}", using default ${n}`),n):i}function c(t,n,o){const s={};if(typeof t.id!="string"||t.id.trim().length===0){const e=Date.now(),i=Math.random().toString(36).substr(2,9);s.id=`anno-${e}-${i}`,o.push(`[${s.id}]: Auto-generated ID (original was missing or invalid)`)}else s.id=t.id.trim();return s.type=t.type,typeof t.page!="number"||t.page<1?(n.push(`[${s.id}]: Field "page" invalid value "${t.page}", using default ${l.BASE_DEFAULTS.page}`),s.page=l.BASE_DEFAULTS.page):s.page=Math.floor(t.page),typeof t.start!="number"||t.start<0?(n.push(`[${s.id}]: Field "start" invalid value "${t.start}", using default ${l.BASE_DEFAULTS.start}`),s.start=l.BASE_DEFAULTS.start):s.start=t.start,typeof t.end!="number"||t.end<0?(n.push(`[${s.id}]: Field "end" invalid value "${t.end}", using start value ${s.start}`),s.end=s.start):t.end<s.start?(n.push(`[${s.id}]: Field "end" (${t.end}) less than start (${s.start}), clamping to start`),s.end=s.start):s.end=t.end,s}function T(t,n,o){return!t||typeof t!="object"?(o.push(`[${n}]: Invalid quad object, using default`),{x:.1,y:.1,w:.8,h:.05}):{x:a(t.x,.1,n,"quad.x",o),y:a(t.y,.1,n,"quad.y",o),w:a(t.w,.8,n,"quad.w",o),h:a(t.h,.05,n,"quad.h",o)}}function p(t,n,o,s){const e={...t};n.mode!=="quads"?(o.push(`[${t.id}]: Field "mode" invalid value "${n.mode}", using default "${l.HIGHLIGHT_DEFAULTS.mode}"`),e.mode=l.HIGHLIGHT_DEFAULTS.mode):e.mode=n.mode,!Array.isArray(n.quads)||n.quads.length===0?(o.push(`[${t.id}]: Field "quads" missing or empty, using default`),e.quads=l.HIGHLIGHT_DEFAULTS.quads):e.quads=n.quads.map((r,u)=>T(r,t.id,o));const i=l.HIGHLIGHT_DEFAULTS.style.color;return!n.style||typeof n.style!="object"?(o.push(`[${t.id}]: Field "style" missing or invalid, using default`),e.style={color:i}):e.style={color:d(n.style.color,i,t.id,o)},e}function m(t,n,o,s){const e={...t};typeof n.content!="string"||n.content.trim().length===0?(o.push(`[${t.id}]: Field "content" missing or empty, using default "${l.TEXT_DEFAULTS.content}"`),e.content=l.TEXT_DEFAULTS.content):e.content=n.content,e.x=a(n.x,l.TEXT_DEFAULTS.x,t.id,"x",o),e.y=a(n.y,l.TEXT_DEFAULTS.y,t.id,"y",o),e.w=a(n.w,l.TEXT_DEFAULTS.w,t.id,"w",o),e.h=a(n.h,l.TEXT_DEFAULTS.h,t.id,"h",o);const i=l.TEXT_DEFAULTS.style.bg,r=l.TEXT_DEFAULTS.style.color;return!n.style||typeof n.style!="object"?(o.push(`[${t.id}]: Field "style" missing or invalid, using defaults`),e.style={bg:i,color:r}):e.style={bg:d(n.style.bg,i,t.id,o),color:d(n.style.color,r,t.id,o)},e}function F(t,n,o){return!t||typeof t!="object"?(o.push(`[${n}]: Invalid point object, using default`),{t:0,x:.1,y:.1}):{t:a(t.t,0,n,"point.t",o),x:a(t.x,.1,n,"point.x",o),y:a(t.y,.1,n,"point.y",o)}}function E(t,n,o){if(!t||typeof t!="object")return o.push(`[${n}]: Invalid stroke object, using default`),l.INK_DEFAULTS.strokes[0];const s={color:d(t.color,l.INK_DEFAULTS.strokes[0].color,n,o),size:f(t.size,l.INK_DEFAULTS.strokes[0].size,n,"stroke.size",o)};return!Array.isArray(t.points)||t.points.length===0?(o.push(`[${n}]: Stroke missing points array, using default`),s.points=l.INK_DEFAULTS.strokes[0].points):s.points=t.points.map(e=>F(e,n,o)),s}function g(t,n,o,s){const e={...t};return!Array.isArray(n.strokes)||n.strokes.length===0?(o.push(`[${t.id}]: Field "strokes" missing or empty, using default`),e.strokes=l.INK_DEFAULTS.strokes):e.strokes=n.strokes.map(i=>E(i,t.id,o)),e}function y(t,n){const o=[],s=[];if(!t||typeof t!="object")return{annotation:null,warnings:[],info:[],critical:`Annotation at index ${n}: Not a valid object`};if(typeof t.type!="string"||t.type.trim().length===0)return{annotation:null,warnings:[],info:[],critical:`Annotation at index ${n}: Missing or invalid type field`};const e=t.type.trim(),i=c(t,o,s);let r;if(e==="highlight")r=p(i,t,o);else if(e==="text")r=m(i,t,o);else if(e==="ink")r=g(i,t,o);else return{annotation:null,warnings:[],info:[],critical:`Annotation at index ${n}: Unsupported type "${e}"`};return{annotation:r,warnings:o,info:s,critical:null}}function z(t,n={}){n.skipInvalid;const o=n.warnInConsole!==!1,s=n.onWarning||null,e={normalized:[],warnings:[],info:[],skipped:[]};if(!Array.isArray(t)){const i="normalizeAnnotationArray: Input is not an array, returning empty result";return e.warnings.push(i),o&&console.warn(`[Annotation Normalizer] ${i}`),e}return t.forEach((i,r)=>{if(i==null){e.skipped.push({index:r,annotation:i,reason:"Annotation is null or undefined"});return}const u=y(i,r);if(u.critical){e.skipped.push({index:r,annotation:i,reason:u.critical}),o&&console.error(`[Annotation Normalizer] ${u.critical}`);return}e.normalized.push(u.annotation),e.warnings.push(...u.warnings),e.info.push(...u.info)}),o&&(e.warnings.length>0||e.info.length>0||e.skipped.length>0)&&(console.group("[Annotation Normalizer] Validation Summary"),e.normalized.length>0&&console.info(`✓ Normalized ${e.normalized.length} annotation(s)`),e.skipped.length>0&&(console.error(`✗ Skipped ${e.skipped.length} annotation(s)`),e.skipped.forEach(i=>{console.error(` Index ${i.index}: ${i.reason}`)})),e.warnings.length>0&&(console.warn(`⚠ ${e.warnings.length} warning(s):`),e.warnings.forEach(i=>console.warn(` ${i}`))),e.info.length>0&&(console.info(`ℹ ${e.info.length} info message(s):`),e.info.forEach(i=>console.info(` ${i}`))),console.groupEnd()),s&&typeof s=="function"&&s(e),e}exports.normalizeAnnotation=y;exports.normalizeAnnotationArray=z;exports.normalizeBaseFields=c;exports.normalizeColor=d;exports.normalizeCoordinate=a;exports.normalizeHighlight=p;exports.normalizeInk=g;exports.normalizePositiveNumber=f;exports.normalizeText=m;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const j=require("pdfjs-dist");function O(e){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e){for(const n in e)if(n!=="default"){const o=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(t,n,o.get?o:{enumerable:!0,get:()=>e[n]})}}return t.default=e,Object.freeze(t)}const M=O(j);async function I(e){try{const t=await e.getTextContent(),n=e.getViewport({scale:1}),o=n.width,a=n.height,i=[];for(const s of t.items){if(!s.str||!s.str.trim())continue;const r=s.transform,g=Math.sqrt(r[2]*r[2]+r[3]*r[3]),h=r[4],c=n.height-r[5],u=s.width,l=s.height||g,p=h,x=c-l,f=h+u,m=c,b=[Math.max(0,Math.min(1,p/o)),Math.max(0,Math.min(1,x/a)),Math.max(0,Math.min(1,f/o)),Math.max(0,Math.min(1,m/a))];i.push({type:"text",text:s.str,bbox_norm:b,font:s.fontName||"unknown",fontSize:g,source:"pdfjs"})}return i}catch(t){return console.error("Error extracting text blocks:",t),[]}}function X(e,t,n){const o=e[4],a=e[5],i=e[0],s=e[3],r=Math.abs(i),g=Math.abs(s),h=n-a-g,c=n-a,u=o,l=o+r;return[Math.max(0,Math.min(1,u/t)),Math.max(0,Math.min(1,h/n)),Math.max(0,Math.min(1,l/t)),Math.max(0,Math.min(1,c/n))]}function B(e,t){return[e[0]*t[0]+e[2]*t[1],e[1]*t[0]+e[3]*t[1],e[0]*t[2]+e[2]*t[3],e[1]*t[2]+e[3]*t[3],e[0]*t[4]+e[2]*t[5]+e[4],e[1]*t[4]+e[3]*t[5]+e[5]]}function P(e,t){return{[t.paintImageXObject]:"paintImageXObject",[t.paintInlineImageXObject]:"paintInlineImageXObject",[t.paintImageMaskXObject]:"paintImageMaskXObject",[t.paintJpegXObject]:"paintJpegXObject"}[e]||"unknown"}async function T(e){try{const t=await e.getOperatorList(),n=e.getViewport({scale:1}),o=n.width,a=n.height,i=[],s=[];let r=[1,0,0,1,0,0];const g=t.fnArray,h=t.argsArray,c=M.OPS,u=[c.paintImageXObject,c.paintInlineImageXObject,c.paintImageMaskXObject,c.paintJpegXObject];for(let l=0;l<g.length;l++){const p=g[l],x=h[l];if(p===c.save)s.push([...r]);else if(p===c.restore)s.length>0&&(r=s.pop());else if(p===c.transform){const[f,m,b,w,y,k]=x;r=B(r,[f,m,b,w,y,k])}else if(u.includes(p)){const f=X(r,o,a);i.push({type:"image",bbox_norm:f,source:"pdfjs",operator:P(p,c)})}}return i}catch(t){return console.error("Error extracting image blocks:",t),[]}}async function d(e,t){try{const o=await M.getDocument(e).promise;if(t<1||t>o.numPages)throw new Error(`Invalid page number: ${t}. Document has ${o.numPages} pages.`);const a=await o.getPage(t),i=a.getViewport({scale:1}),[s,r]=await Promise.all([I(a),T(a)]);return{textBlocks:s,imageBlocks:r,pageDimensions:{width:i.width,height:i.height},pageNumber:t}}catch(n){throw console.error(`Error extracting blocks from page ${t}:`,n),n}}async function D(e,t){const n=[];for(const o of t)try{const a=await d(e,o);n.push(a)}catch(a){console.error(`Failed to extract page ${o}:`,a),n.push({textBlocks:[],imageBlocks:[],pageDimensions:null,pageNumber:o,error:a.message})}return n}exports.extractAllBlocks=d;exports.extractMultiplePages=D;
2
2
  //# sourceMappingURL=index12.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index12.cjs","sources":["../src/types/validators.js"],"sourcesContent":["/**\n * Annotation Data Normalization Utilities\n *\n * This module provides defensive normalization functions that validate and fix\n * annotation data. Invalid values are replaced with safe defaults and warnings\n * are collected for user feedback.\n *\n * @module types/validators\n */\n\nimport {\n BASE_DEFAULTS,\n HIGHLIGHT_DEFAULTS,\n TEXT_DEFAULTS,\n INK_DEFAULTS\n} from './defaults.js';\n\n// ============================================================================\n// FIELD-LEVEL NORMALIZERS\n// ============================================================================\n\n/**\n * Normalize coordinate value to 0-1 range\n *\n * Validates that a value is a number in the 0-1 range. Out-of-range values\n * are clamped. Invalid values use the provided default.\n *\n * @param {*} value - Value to normalize\n * @param {number} defaultValue - Fallback value if invalid\n * @param {string} id - Annotation ID for warning messages\n * @param {string} fieldName - Field name for warning messages\n * @param {Array<string>} warnings - Array to collect warning messages\n * @returns {number} Normalized coordinate value in range [0, 1]\n *\n * @example\n * normalizeCoordinate(0.5, 0.1, 'txt-1', 'x', warnings) // Returns: 0.5\n * normalizeCoordinate(5, 0.1, 'txt-1', 'x', warnings) // Returns: 1, adds warning\n * normalizeCoordinate('abc', 0.1, 'txt-1', 'x', warnings) // Returns: 0.1, adds warning\n */\nexport function normalizeCoordinate(value, defaultValue, id, fieldName, warnings) {\n // Type coercion: parse string to number if needed\n let numValue = value;\n if (typeof value === 'string') {\n numValue = parseFloat(value);\n if (!isNaN(numValue) && numValue === value) {\n // Successfully parsed - no warning needed\n }\n }\n\n // Validate is valid number\n if (typeof numValue !== 'number' || isNaN(numValue)) {\n warnings.push(\n `[${id}]: Field \"${fieldName}\" invalid value \"${value}\", using default ${defaultValue}`\n );\n return defaultValue;\n }\n\n // Range check: clamp to [0, 1]\n if (numValue < 0) {\n warnings.push(\n `[${id}]: Field \"${fieldName}\" value ${numValue} below range [0,1], clamping to 0`\n );\n return 0;\n }\n\n if (numValue > 1) {\n warnings.push(\n `[${id}]: Field \"${fieldName}\" value ${numValue} exceeds range [0,1], clamping to 1`\n );\n return 1;\n }\n\n // Valid value\n return numValue;\n}\n\n/**\n * Normalize color string\n *\n * Validates that a value is a valid color string. Supports hex, rgb/rgba,\n * and named colors. Invalid colors use the provided default.\n *\n * @param {*} value - Color value to normalize\n * @param {string} defaultValue - Fallback color if invalid\n * @param {string} id - Annotation ID for warning messages\n * @param {Array<string>} warnings - Array to collect warning messages\n * @returns {string} Valid color string\n *\n * @example\n * normalizeColor('#fff', '#000', 'txt-1', warnings) // Returns: '#fff'\n * normalizeColor('rgba(255,0,0,0.5)', '#000', 'txt-1', warnings) // Returns: 'rgba(255,0,0,0.5)'\n * normalizeColor('notacolor', '#000', 'txt-1', warnings) // Returns: '#000', adds warning\n */\nexport function normalizeColor(value, defaultValue, id, warnings) {\n // Type check: must be non-empty string\n if (typeof value !== 'string' || value.trim().length === 0) {\n warnings.push(\n `[${id}]: Invalid color format \"${value}\", using default ${defaultValue}`\n );\n return defaultValue;\n }\n\n const trimmed = value.trim();\n\n // Regex patterns for color validation (cached at module level)\n const hexPattern = /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/;\n const rgbPattern = /^rgba?\\(\\s*\\d+\\s*,\\s*\\d+\\s*,\\s*\\d+\\s*(,\\s*[\\d.]+\\s*)?\\)$/;\n\n // Named colors (basic set)\n const namedColors = [\n 'red', 'blue', 'green', 'yellow', 'black', 'white', 'gray',\n 'grey', 'orange', 'purple', 'pink', 'brown', 'transparent'\n ];\n\n // Validate format\n const isHex = hexPattern.test(trimmed);\n const isRgb = rgbPattern.test(trimmed);\n const isNamed = namedColors.includes(trimmed.toLowerCase());\n\n if (isHex || isRgb || isNamed) {\n return trimmed;\n }\n\n // Invalid format\n warnings.push(\n `[${id}]: Invalid color format \"${value}\", using default ${defaultValue}`\n );\n return defaultValue;\n}\n\n/**\n * Normalize positive number\n *\n * Validates that a value is a positive number. Invalid values use the\n * provided default.\n *\n * @param {*} value - Value to normalize\n * @param {number} defaultValue - Fallback value if invalid\n * @param {string} id - Annotation ID for warning messages\n * @param {string} fieldName - Field name for warning messages\n * @param {Array<string>} warnings - Array to collect warning messages\n * @returns {number} Positive number\n *\n * @example\n * normalizePositiveNumber(5, 3, 'ink-1', 'size', warnings) // Returns: 5\n * normalizePositiveNumber(-1, 3, 'ink-1', 'size', warnings) // Returns: 3, adds warning\n * normalizePositiveNumber('abc', 3, 'ink-1', 'size', warnings) // Returns: 3, adds warning\n */\nexport function normalizePositiveNumber(value, defaultValue, id, fieldName, warnings) {\n // Type coercion: parse string to number if needed\n let numValue = value;\n if (typeof value === 'string') {\n numValue = parseFloat(value);\n }\n\n // Validate is valid number and positive\n if (typeof numValue !== 'number' || isNaN(numValue) || numValue <= 0) {\n warnings.push(\n `[${id}]: Field \"${fieldName}\" invalid value \"${value}\", using default ${defaultValue}`\n );\n return defaultValue;\n }\n\n return numValue;\n}\n\n// ============================================================================\n// BASE FIELDS NORMALIZER\n// ============================================================================\n\n/**\n * Normalize common base annotation fields\n *\n * Validates and normalizes fields common to all annotation types: id, type,\n * page, start, and end. Auto-generates ID if missing. Applies safe defaults\n * for invalid values.\n *\n * @param {Object} raw - Raw annotation object\n * @param {Array<string>} warnings - Array to collect warning messages\n * @param {Array<string>} info - Array to collect info messages\n * @returns {Object} Object with normalized base fields\n *\n * @example\n * normalizeBaseFields({ type: 'text', page: 2 }, warnings, info)\n * // Returns: { id: 'anno-1234...', type: 'text', page: 2, start: 0, end: 0 }\n */\nexport function normalizeBaseFields(raw, warnings, info) {\n const base = {};\n\n // ===== ID Field =====\n // Check: non-empty string\n // Invalid: auto-generate unique ID\n if (typeof raw.id !== 'string' || raw.id.trim().length === 0) {\n const timestamp = Date.now();\n const random = Math.random().toString(36).substr(2, 9);\n base.id = `anno-${timestamp}-${random}`;\n info.push(`[${base.id}]: Auto-generated ID (original was missing or invalid)`);\n } else {\n base.id = raw.id.trim();\n }\n\n // ===== Type Field =====\n // Pass through as-is (validated in parent function)\n base.type = raw.type;\n\n // ===== Page Field =====\n // Check: positive integer\n // Invalid: default to 1\n if (typeof raw.page !== 'number' || raw.page < 1) {\n warnings.push(\n `[${base.id}]: Field \"page\" invalid value \"${raw.page}\", using default ${BASE_DEFAULTS.page}`\n );\n base.page = BASE_DEFAULTS.page;\n } else {\n // Floor to ensure integer\n base.page = Math.floor(raw.page);\n }\n\n // ===== Start Field =====\n // Check: non-negative number\n // Invalid: default to 0\n if (typeof raw.start !== 'number' || raw.start < 0) {\n warnings.push(\n `[${base.id}]: Field \"start\" invalid value \"${raw.start}\", using default ${BASE_DEFAULTS.start}`\n );\n base.start = BASE_DEFAULTS.start;\n } else {\n base.start = raw.start;\n }\n\n // ===== End Field =====\n // Check: non-negative number >= start\n // Invalid: clamp to start value\n if (typeof raw.end !== 'number' || raw.end < 0) {\n warnings.push(\n `[${base.id}]: Field \"end\" invalid value \"${raw.end}\", using start value ${base.start}`\n );\n base.end = base.start;\n } else if (raw.end < base.start) {\n warnings.push(\n `[${base.id}]: Field \"end\" (${raw.end}) less than start (${base.start}), clamping to start`\n );\n base.end = base.start;\n } else {\n base.end = raw.end;\n }\n\n return base;\n}\n\n// ============================================================================\n// TYPE-SPECIFIC NORMALIZERS\n// ============================================================================\n\n/**\n * Normalize a single quad (rectangular region)\n *\n * @private\n * @param {Object} quad - Quad object with x, y, w, h\n * @param {string} id - Annotation ID\n * @param {Array<string>} warnings - Warnings array\n * @returns {Object} Normalized quad\n */\nfunction normalizeQuad(quad, id, warnings) {\n if (!quad || typeof quad !== 'object') {\n warnings.push(`[${id}]: Invalid quad object, using default`);\n return { x: 0.1, y: 0.1, w: 0.8, h: 0.05 };\n }\n\n return {\n x: normalizeCoordinate(quad.x, 0.1, id, 'quad.x', warnings),\n y: normalizeCoordinate(quad.y, 0.1, id, 'quad.y', warnings),\n w: normalizeCoordinate(quad.w, 0.8, id, 'quad.w', warnings),\n h: normalizeCoordinate(quad.h, 0.05, id, 'quad.h', warnings)\n };\n}\n\n/**\n * Normalize highlight annotation\n *\n * Validates and normalizes highlight-specific fields: mode, quads array,\n * and style.color. Applies defaults for invalid fields.\n *\n * @param {Object} base - Object with normalized base fields\n * @param {Object} raw - Raw annotation object\n * @param {Array<string>} warnings - Warnings array\n * @param {Array<string>} info - Info array\n * @returns {Object} Fully normalized highlight annotation\n *\n * @example\n * normalizeHighlight(base, raw, warnings, info)\n * // Returns: { ...base, mode: 'quads', quads: [...], style: {...} }\n */\nexport function normalizeHighlight(base, raw, warnings, info) {\n const annotation = { ...base };\n\n // ===== Mode Field =====\n // Check: value equals \"quads\"\n // Invalid: default to \"quads\"\n if (raw.mode !== 'quads') {\n warnings.push(\n `[${base.id}]: Field \"mode\" invalid value \"${raw.mode}\", using default \"${HIGHLIGHT_DEFAULTS.mode}\"`\n );\n annotation.mode = HIGHLIGHT_DEFAULTS.mode;\n } else {\n annotation.mode = raw.mode;\n }\n\n // ===== Quads Array =====\n // Check: non-empty array\n // Invalid: use default quads\n if (!Array.isArray(raw.quads) || raw.quads.length === 0) {\n warnings.push(\n `[${base.id}]: Field \"quads\" missing or empty, using default`\n );\n annotation.quads = HIGHLIGHT_DEFAULTS.quads;\n } else {\n // Normalize each quad\n annotation.quads = raw.quads.map((quad, idx) => normalizeQuad(quad, base.id, warnings));\n }\n\n // ===== Style Object =====\n // Check: object with color property\n const defaultColor = HIGHLIGHT_DEFAULTS.style.color;\n if (!raw.style || typeof raw.style !== 'object') {\n warnings.push(\n `[${base.id}]: Field \"style\" missing or invalid, using default`\n );\n annotation.style = { color: defaultColor };\n } else {\n annotation.style = {\n color: normalizeColor(raw.style.color, defaultColor, base.id, warnings)\n };\n }\n\n return annotation;\n}\n\n/**\n * Normalize text annotation\n *\n * Validates and normalizes text-specific fields: content, position (x, y),\n * dimensions (w, h), and style (bg, color). Applies defaults for invalid fields.\n *\n * @param {Object} base - Object with normalized base fields\n * @param {Object} raw - Raw annotation object\n * @param {Array<string>} warnings - Warnings array\n * @param {Array<string>} info - Info array\n * @returns {Object} Fully normalized text annotation\n *\n * @example\n * normalizeText(base, raw, warnings, info)\n * // Returns: { ...base, content: '...', x: 0.1, y: 0.1, w: 0.3, h: 0.1, style: {...} }\n */\nexport function normalizeText(base, raw, warnings, info) {\n const annotation = { ...base };\n\n // ===== Content Field =====\n // Check: non-empty string\n // Invalid: default to placeholder\n if (typeof raw.content !== 'string' || raw.content.trim().length === 0) {\n warnings.push(\n `[${base.id}]: Field \"content\" missing or empty, using default \"${TEXT_DEFAULTS.content}\"`\n );\n annotation.content = TEXT_DEFAULTS.content;\n } else {\n annotation.content = raw.content;\n }\n\n // ===== Position Fields (x, y) =====\n annotation.x = normalizeCoordinate(raw.x, TEXT_DEFAULTS.x, base.id, 'x', warnings);\n annotation.y = normalizeCoordinate(raw.y, TEXT_DEFAULTS.y, base.id, 'y', warnings);\n\n // ===== Dimension Fields (w, h) =====\n annotation.w = normalizeCoordinate(raw.w, TEXT_DEFAULTS.w, base.id, 'w', warnings);\n annotation.h = normalizeCoordinate(raw.h, TEXT_DEFAULTS.h, base.id, 'h', warnings);\n\n // ===== Style Object =====\n const defaultBg = TEXT_DEFAULTS.style.bg;\n const defaultColor = TEXT_DEFAULTS.style.color;\n\n if (!raw.style || typeof raw.style !== 'object') {\n warnings.push(\n `[${base.id}]: Field \"style\" missing or invalid, using defaults`\n );\n annotation.style = {\n bg: defaultBg,\n color: defaultColor\n };\n } else {\n annotation.style = {\n bg: normalizeColor(raw.style.bg, defaultBg, base.id, warnings),\n color: normalizeColor(raw.style.color, defaultColor, base.id, warnings)\n };\n }\n\n return annotation;\n}\n\n/**\n * Normalize a single ink point\n *\n * @private\n * @param {Object} point - Point object with t, x, y\n * @param {string} id - Annotation ID\n * @param {Array<string>} warnings - Warnings array\n * @returns {Object} Normalized point\n */\nfunction normalizePoint(point, id, warnings) {\n if (!point || typeof point !== 'object') {\n warnings.push(`[${id}]: Invalid point object, using default`);\n return { t: 0, x: 0.1, y: 0.1 };\n }\n\n return {\n t: normalizeCoordinate(point.t, 0, id, 'point.t', warnings),\n x: normalizeCoordinate(point.x, 0.1, id, 'point.x', warnings),\n y: normalizeCoordinate(point.y, 0.1, id, 'point.y', warnings)\n };\n}\n\n/**\n * Normalize a single ink stroke\n *\n * @private\n * @param {Object} stroke - Stroke object with color, size, points\n * @param {string} id - Annotation ID\n * @param {Array<string>} warnings - Warnings array\n * @returns {Object} Normalized stroke\n */\nfunction normalizeStroke(stroke, id, warnings) {\n if (!stroke || typeof stroke !== 'object') {\n warnings.push(`[${id}]: Invalid stroke object, using default`);\n return INK_DEFAULTS.strokes[0];\n }\n\n const normalized = {\n color: normalizeColor(stroke.color, INK_DEFAULTS.strokes[0].color, id, warnings),\n size: normalizePositiveNumber(stroke.size, INK_DEFAULTS.strokes[0].size, id, 'stroke.size', warnings)\n };\n\n // ===== Points Array =====\n if (!Array.isArray(stroke.points) || stroke.points.length === 0) {\n warnings.push(`[${id}]: Stroke missing points array, using default`);\n normalized.points = INK_DEFAULTS.strokes[0].points;\n } else {\n normalized.points = stroke.points.map(point => normalizePoint(point, id, warnings));\n }\n\n return normalized;\n}\n\n/**\n * Normalize ink annotation\n *\n * Validates and normalizes ink-specific fields: strokes array with color,\n * size, and points. Applies defaults for invalid fields.\n *\n * @param {Object} base - Object with normalized base fields\n * @param {Object} raw - Raw annotation object\n * @param {Array<string>} warnings - Warnings array\n * @param {Array<string>} info - Info array\n * @returns {Object} Fully normalized ink annotation\n *\n * @example\n * normalizeInk(base, raw, warnings, info)\n * // Returns: { ...base, strokes: [{ color: '...', size: 3, points: [...] }] }\n */\nexport function normalizeInk(base, raw, warnings, info) {\n const annotation = { ...base };\n\n // ===== Strokes Array =====\n // Check: non-empty array\n // Invalid: use default single stroke\n if (!Array.isArray(raw.strokes) || raw.strokes.length === 0) {\n warnings.push(\n `[${base.id}]: Field \"strokes\" missing or empty, using default`\n );\n annotation.strokes = INK_DEFAULTS.strokes;\n } else {\n // Normalize each stroke\n annotation.strokes = raw.strokes.map(stroke => normalizeStroke(stroke, base.id, warnings));\n }\n\n return annotation;\n}\n\n// ============================================================================\n// ORCHESTRATION - SINGLE ANNOTATION & ARRAY\n// ============================================================================\n\n/**\n * Normalize a single annotation\n *\n * Routes annotation to appropriate type-specific normalizer based on type field.\n * Handles critical validation errors (missing/invalid type).\n *\n * @param {Object} raw - Raw annotation object\n * @param {number} index - Position in original array (for error context)\n * @returns {Object} Result object with annotation, warnings, info, and critical error\n * @returns {Object|null} return.annotation - Normalized annotation or null if critical error\n * @returns {Array<string>} return.warnings - Warning messages\n * @returns {Array<string>} return.info - Info messages\n * @returns {string|null} return.critical - Critical error message or null\n *\n * @example\n * normalizeAnnotation({ type: 'text', content: 'Hello' }, 0)\n * // Returns: { annotation: {...}, warnings: [], info: [], critical: null }\n */\nexport function normalizeAnnotation(raw, index) {\n const warnings = [];\n const info = [];\n\n // Validate input is object\n if (!raw || typeof raw !== 'object') {\n return {\n annotation: null,\n warnings: [],\n info: [],\n critical: `Annotation at index ${index}: Not a valid object`\n };\n }\n\n // Check type field (critical - cannot route without type)\n if (typeof raw.type !== 'string' || raw.type.trim().length === 0) {\n return {\n annotation: null,\n warnings: [],\n info: [],\n critical: `Annotation at index ${index}: Missing or invalid type field`\n };\n }\n\n const type = raw.type.trim();\n\n // Normalize base fields first\n const base = normalizeBaseFields(raw, warnings, info);\n\n // Route to type-specific normalizer\n let annotation;\n\n if (type === 'highlight') {\n annotation = normalizeHighlight(base, raw, warnings, info);\n } else if (type === 'text') {\n annotation = normalizeText(base, raw, warnings, info);\n } else if (type === 'ink') {\n annotation = normalizeInk(base, raw, warnings, info);\n } else {\n return {\n annotation: null,\n warnings: [],\n info: [],\n critical: `Annotation at index ${index}: Unsupported type \"${type}\"`\n };\n }\n\n return {\n annotation,\n warnings,\n info,\n critical: null\n };\n}\n\n/**\n * Normalize array of annotations\n *\n * MAIN ENTRY POINT for annotation normalization. Processes each annotation,\n * collects warnings, and returns normalized data ready for rendering.\n *\n * @param {Array} rawAnnotations - Array of raw annotation objects\n * @param {Object} [options] - Configuration options\n * @param {boolean} [options.skipInvalid=true] - Skip critically invalid annotations\n * @param {boolean} [options.warnInConsole=true] - Log warnings to console\n * @param {Function} [options.onWarning] - Custom warning callback\n * @returns {Object} ValidationResult with normalized annotations and messages\n * @returns {Array} return.normalized - Successfully normalized annotations\n * @returns {Array<string>} return.warnings - Warning messages\n * @returns {Array<string>} return.info - Informational messages\n * @returns {Array<Object>} return.skipped - Skipped annotations with reasons\n *\n * @example\n * const result = normalizeAnnotationArray(rawAnnotations, {\n * skipInvalid: true,\n * warnInConsole: true\n * });\n *\n * renderer.setAnnotations(result.normalized);\n */\nexport function normalizeAnnotationArray(rawAnnotations, options = {}) {\n // Default options\n const skipInvalid = options.skipInvalid !== false; // Default: true\n const warnInConsole = options.warnInConsole !== false; // Default: true\n const onWarning = options.onWarning || null;\n\n // Initialize result structure\n const result = {\n normalized: [],\n warnings: [],\n info: [],\n skipped: []\n };\n\n // Validate input is array\n if (!Array.isArray(rawAnnotations)) {\n const warning = 'normalizeAnnotationArray: Input is not an array, returning empty result';\n result.warnings.push(warning);\n\n if (warnInConsole) {\n console.warn(`[Annotation Normalizer] ${warning}`);\n }\n\n return result;\n }\n\n // Process each annotation\n rawAnnotations.forEach((raw, index) => {\n // Skip null/undefined\n if (raw == null) {\n result.skipped.push({\n index,\n annotation: raw,\n reason: 'Annotation is null or undefined'\n });\n return;\n }\n\n // Normalize annotation\n const normalized = normalizeAnnotation(raw, index);\n\n // Check for critical error\n if (normalized.critical) {\n result.skipped.push({\n index,\n annotation: raw,\n reason: normalized.critical\n });\n\n if (warnInConsole) {\n console.error(`[Annotation Normalizer] ${normalized.critical}`);\n }\n\n return;\n }\n\n // Add to normalized array\n result.normalized.push(normalized.annotation);\n\n // Collect warnings and info\n result.warnings.push(...normalized.warnings);\n result.info.push(...normalized.info);\n });\n\n // Console output\n if (warnInConsole) {\n if (result.warnings.length > 0 || result.info.length > 0 || result.skipped.length > 0) {\n console.group('[Annotation Normalizer] Validation Summary');\n\n if (result.normalized.length > 0) {\n console.info(`✓ Normalized ${result.normalized.length} annotation(s)`);\n }\n\n if (result.skipped.length > 0) {\n console.error(`✗ Skipped ${result.skipped.length} annotation(s)`);\n result.skipped.forEach(s => {\n console.error(` Index ${s.index}: ${s.reason}`);\n });\n }\n\n if (result.warnings.length > 0) {\n console.warn(`⚠ ${result.warnings.length} warning(s):`);\n result.warnings.forEach(w => console.warn(` ${w}`));\n }\n\n if (result.info.length > 0) {\n console.info(`ℹ ${result.info.length} info message(s):`);\n result.info.forEach(i => console.info(` ${i}`));\n }\n\n console.groupEnd();\n }\n }\n\n // Call custom warning handler\n if (onWarning && typeof onWarning === 'function') {\n onWarning(result);\n }\n\n return result;\n}\n"],"names":["normalizeCoordinate","value","defaultValue","id","fieldName","warnings","numValue","normalizeColor","trimmed","hexPattern","rgbPattern","namedColors","isHex","isRgb","isNamed","normalizePositiveNumber","normalizeBaseFields","raw","info","base","timestamp","random","BASE_DEFAULTS","normalizeQuad","quad","normalizeHighlight","annotation","HIGHLIGHT_DEFAULTS","idx","defaultColor","normalizeText","TEXT_DEFAULTS","defaultBg","normalizePoint","point","normalizeStroke","stroke","INK_DEFAULTS","normalized","normalizeInk","normalizeAnnotation","index","type","normalizeAnnotationArray","rawAnnotations","options","warnInConsole","onWarning","result","warning","s","w"],"mappings":"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"}
1
+ {"version":3,"file":"index12.cjs","sources":["../src/utils/pdfExtractor.js"],"sourcesContent":["/**\n * PDF Data Extractor - Extract text and image blocks from PDF\n *\n * Uses PDF.js getOperatorList() for efficient metadata extraction without rendering.\n *\n * @module utils/pdfExtractor\n */\n\nimport * as pdfjsLib from \"pdfjs-dist\";\n\n/**\n * Extract text blocks from a PDF page with normalized coordinates\n *\n * @param {PDFPageProxy} page - PDF.js page object\n * @returns {Promise<Array>} Array of text blocks with normalized bounding boxes (0-1 range)\n */\nasync function extractTextBlocks(page) {\n try {\n const textContent = await page.getTextContent();\n const viewport = page.getViewport({ scale: 1.0 });\n\n const pageWidth = viewport.width;\n const pageHeight = viewport.height;\n\n const textBlocks = [];\n\n for (const item of textContent.items) {\n // Skip empty text\n if (!item.str || !item.str.trim()) {\n continue;\n }\n\n // Get transform matrix [a, b, c, d, e, f]\n const transform = item.transform;\n const fontSize = Math.sqrt(transform[2] * transform[2] + transform[3] * transform[3]);\n\n // Calculate bounding box (absolute coordinates)\n const x = transform[4];\n const y = viewport.height - transform[5]; // Convert to top-left origin\n const width = item.width;\n const height = item.height || fontSize;\n\n const x1 = x;\n const y1 = y - height;\n const x2 = x + width;\n const y2 = y;\n\n // Normalize coordinates to 0-1 range\n const bbox_norm = [\n Math.max(0.0, Math.min(1.0, x1 / pageWidth)),\n Math.max(0.0, Math.min(1.0, y1 / pageHeight)),\n Math.max(0.0, Math.min(1.0, x2 / pageWidth)),\n Math.max(0.0, Math.min(1.0, y2 / pageHeight))\n ];\n\n textBlocks.push({\n type: \"text\",\n text: item.str,\n bbox_norm: bbox_norm,\n font: item.fontName || \"unknown\",\n fontSize: fontSize,\n source: \"pdfjs\"\n });\n }\n\n return textBlocks;\n } catch (error) {\n console.error(\"Error extracting text blocks:\", error);\n return [];\n }\n}\n\n/**\n * Extract normalized bounding box from PDF transformation matrix\n *\n * @param {Array} transform - PDF transformation matrix [a, b, c, d, e, f]\n * @param {number} pageWidth - Page width for normalization\n * @param {number} pageHeight - Page height for coordinate conversion and normalization\n * @returns {Array} Normalized bounding box [x1, y1, x2, y2] in 0-1 range\n */\nfunction extractBBoxFromTransform(transform, pageWidth, pageHeight) {\n const x = transform[4];\n const y = transform[5];\n const scaleX = transform[0];\n const scaleY = transform[3];\n\n // Scale factors represent image dimensions\n const width = Math.abs(scaleX);\n const height = Math.abs(scaleY);\n\n // Convert from PDF bottom-left to image top-left origin\n const y1 = pageHeight - y - height;\n const y2 = pageHeight - y;\n const x1 = x;\n const x2 = x + width;\n\n // Normalize to 0-1 range\n return [\n Math.max(0.0, Math.min(1.0, x1 / pageWidth)),\n Math.max(0.0, Math.min(1.0, y1 / pageHeight)),\n Math.max(0.0, Math.min(1.0, x2 / pageWidth)),\n Math.max(0.0, Math.min(1.0, y2 / pageHeight))\n ];\n}\n\n/**\n * Multiply two transformation matrices\n *\n * @param {Array} m1 - First matrix [a, b, c, d, e, f]\n * @param {Array} m2 - Second matrix [a, b, c, d, e, f]\n * @returns {Array} Result matrix [a, b, c, d, e, f]\n */\nfunction multiplyTransforms(m1, m2) {\n return [\n m1[0] * m2[0] + m1[2] * m2[1],\n m1[1] * m2[0] + m1[3] * m2[1],\n m1[0] * m2[2] + m1[2] * m2[3],\n m1[1] * m2[2] + m1[3] * m2[3],\n m1[0] * m2[4] + m1[2] * m2[5] + m1[4],\n m1[1] * m2[4] + m1[3] * m2[5] + m1[5]\n ];\n}\n\n/**\n * Get human-readable operator name\n *\n * @param {number} op - Operator code\n * @param {Object} OPS - PDF.js OPS constants\n * @returns {string} Operator name\n */\nfunction getOperatorName(op, OPS) {\n const opNames = {\n [OPS.paintImageXObject]: \"paintImageXObject\",\n [OPS.paintInlineImageXObject]: \"paintInlineImageXObject\",\n [OPS.paintImageMaskXObject]: \"paintImageMaskXObject\",\n [OPS.paintJpegXObject]: \"paintJpegXObject\"\n };\n return opNames[op] || \"unknown\";\n}\n\n/**\n * Extract image blocks from a PDF page using getOperatorList with normalized coordinates\n *\n * @param {PDFPageProxy} page - PDF.js page object\n * @returns {Promise<Array>} Array of image blocks with normalized bounding boxes (0-1 range)\n */\nasync function extractImageBlocks(page) {\n try {\n const operatorList = await page.getOperatorList();\n const viewport = page.getViewport({ scale: 1.0 });\n\n const pageWidth = viewport.width;\n const pageHeight = viewport.height;\n\n const imageBlocks = [];\n const graphicsStateStack = []; // Track graphics state transformations\n let currentTransform = [1, 0, 0, 1, 0, 0]; // Identity matrix\n\n const ops = operatorList.fnArray;\n const args = operatorList.argsArray;\n\n // Image paint operator constants from PDF.js\n const OPS = pdfjsLib.OPS;\n const IMAGE_OPS = [\n OPS.paintImageXObject,\n OPS.paintInlineImageXObject,\n OPS.paintImageMaskXObject,\n OPS.paintJpegXObject\n ];\n\n for (let i = 0; i < ops.length; i++) {\n const op = ops[i];\n const arg = args[i];\n\n // Track graphics state stack\n if (op === OPS.save) {\n graphicsStateStack.push([...currentTransform]);\n } else if (op === OPS.restore) {\n if (graphicsStateStack.length > 0) {\n currentTransform = graphicsStateStack.pop();\n }\n } else if (op === OPS.transform) {\n // Update current transformation matrix\n const [a, b, c, d, e, f] = arg;\n currentTransform = multiplyTransforms(currentTransform, [a, b, c, d, e, f]);\n } else if (IMAGE_OPS.includes(op)) {\n // Extract image bounding box (normalized)\n const bbox_norm = extractBBoxFromTransform(currentTransform, pageWidth, pageHeight);\n\n imageBlocks.push({\n type: \"image\",\n bbox_norm: bbox_norm,\n source: \"pdfjs\",\n operator: getOperatorName(op, OPS)\n });\n }\n }\n\n return imageBlocks;\n } catch (error) {\n console.error(\"Error extracting image blocks:\", error);\n return [];\n }\n}\n\n/**\n * Extract all blocks (text and images) from a PDF page\n *\n * @param {string} pdfPath - Path to PDF file\n * @param {number} pageNumber - Page number (1-indexed)\n * @returns {Promise<Object>} Object with textBlocks and imageBlocks arrays\n */\nexport async function extractAllBlocks(pdfPath, pageNumber) {\n try {\n // Load PDF document\n const loadingTask = pdfjsLib.getDocument(pdfPath);\n const pdfDoc = await loadingTask.promise;\n\n // Validate page number\n if (pageNumber < 1 || pageNumber > pdfDoc.numPages) {\n throw new Error(`Invalid page number: ${pageNumber}. Document has ${pdfDoc.numPages} pages.`);\n }\n\n // Get page\n const page = await pdfDoc.getPage(pageNumber);\n const viewport = page.getViewport({ scale: 1.0 });\n\n // Extract text and image blocks in parallel\n const [textBlocks, imageBlocks] = await Promise.all([\n extractTextBlocks(page),\n extractImageBlocks(page)\n ]);\n\n return {\n textBlocks,\n imageBlocks,\n pageDimensions: {\n width: viewport.width,\n height: viewport.height\n },\n pageNumber: pageNumber\n };\n } catch (error) {\n console.error(`Error extracting blocks from page ${pageNumber}:`, error);\n throw error;\n }\n}\n\n/**\n * Extract blocks from multiple pages\n *\n * @param {string} pdfPath - Path to PDF file\n * @param {Array<number>} pageNumbers - Array of page numbers (1-indexed)\n * @returns {Promise<Array>} Array of extraction results, one per page\n */\nexport async function extractMultiplePages(pdfPath, pageNumbers) {\n const results = [];\n\n for (const pageNum of pageNumbers) {\n try {\n const pageData = await extractAllBlocks(pdfPath, pageNum);\n results.push(pageData);\n } catch (error) {\n console.error(`Failed to extract page ${pageNum}:`, error);\n results.push({\n textBlocks: [],\n imageBlocks: [],\n pageDimensions: null,\n pageNumber: pageNum,\n error: error.message\n });\n }\n }\n\n return results;\n}\n"],"names":["extractTextBlocks","page","textContent","viewport","pageWidth","pageHeight","textBlocks","item","transform","fontSize","x","y","width","height","x1","y1","x2","y2","bbox_norm","error","extractBBoxFromTransform","scaleX","scaleY","multiplyTransforms","m1","m2","getOperatorName","op","OPS","extractImageBlocks","operatorList","imageBlocks","graphicsStateStack","currentTransform","ops","args","pdfjsLib","IMAGE_OPS","i","arg","a","b","c","d","e","f","extractAllBlocks","pdfPath","pageNumber","pdfDoc","extractMultiplePages","pageNumbers","results","pageNum","pageData"],"mappings":"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"}