hazo_pdf 1.2.1 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,6 +6,7 @@ A React component library for viewing and annotating PDF documents with support
6
6
 
7
7
  - 📄 **PDF Viewing** - Render PDF documents with customizable zoom levels
8
8
  - ✏️ **Annotations** - Square and FreeText annotation tools
9
+ - 🔍 **Programmatic Highlights** - Ref-based API for creating and managing highlights programmatically
9
10
  - 🎨 **Customizable Styling** - Extensive configuration options via INI file
10
11
  - ⏰ **Timestamp Support** - Automatic timestamp appending to annotations
11
12
  - 🏷️ **Custom Stamps** - Add quick-insert stamps via right-click menu
@@ -19,6 +20,16 @@ A React component library for viewing and annotating PDF documents with support
19
20
  npm install hazo_pdf
20
21
  ```
21
22
 
23
+ ### Optional Dependencies
24
+
25
+ **hazo_logs** (optional): For structured logging and debugging
26
+
27
+ ```bash
28
+ npm install hazo_logs
29
+ ```
30
+
31
+ The `hazo_logs` package is an optional peer dependency. If not installed, hazo_pdf will use console-based logging as a fallback.
32
+
22
33
  ## CSS Import Options
23
34
 
24
35
  The library provides two CSS files to choose from:
@@ -68,7 +79,7 @@ import 'hazo_pdf/styles.css';
68
79
 
69
80
  function App() {
70
81
  return (
71
- <PdfViewer
82
+ <PdfViewer
72
83
  url="/path/to/document.pdf"
73
84
  />
74
85
  );
@@ -77,6 +88,27 @@ function App() {
77
88
 
78
89
  That's it! The PDF viewer will load and display your document with default styling and pan mode enabled.
79
90
 
91
+ ### With Logging (Optional)
92
+
93
+ For debugging and monitoring, you can integrate hazo_logs:
94
+
95
+ ```tsx
96
+ import { PdfViewer } from 'hazo_pdf';
97
+ import { create_logger } from 'hazo_logs';
98
+ import 'hazo_pdf/styles.css';
99
+
100
+ const logger = create_logger('my_app', 'config/hazo_logs_config.ini');
101
+
102
+ function App() {
103
+ return (
104
+ <PdfViewer
105
+ url="/path/to/document.pdf"
106
+ logger={logger}
107
+ />
108
+ );
109
+ }
110
+ ```
111
+
80
112
  ---
81
113
 
82
114
  ## Examples
@@ -413,6 +445,204 @@ See `config/hazo_pdf_config.ini` in the project root for all available configura
413
445
 
414
446
  ---
415
447
 
448
+ ## Programmatic Highlight API
449
+
450
+ The PDF viewer exposes a ref-based API for programmatically creating, removing, and managing highlights. This allows external code to control highlights without user interaction.
451
+
452
+ ### Basic Usage
453
+
454
+ ```tsx
455
+ import { PdfViewer, PdfViewerRef } from 'hazo_pdf';
456
+ import { useRef } from 'react';
457
+ import 'hazo_pdf/styles.css';
458
+
459
+ function HighlightExample() {
460
+ const viewer_ref = useRef<PdfViewerRef>(null);
461
+
462
+ const add_highlight = () => {
463
+ // Highlight region on page 0 at PDF coordinates [100, 500, 300, 550]
464
+ const id = viewer_ref.current?.highlight_region(0, [100, 500, 300, 550], {
465
+ border_color: '#FF0000',
466
+ background_color: '#FFFF00',
467
+ background_opacity: 0.4
468
+ });
469
+ console.log('Created highlight:', id);
470
+ };
471
+
472
+ const remove_specific_highlight = (id: string) => {
473
+ const removed = viewer_ref.current?.remove_highlight(id);
474
+ console.log('Highlight removed:', removed);
475
+ };
476
+
477
+ const clear_all = () => {
478
+ viewer_ref.current?.clear_all_highlights();
479
+ };
480
+
481
+ return (
482
+ <div style={{ width: '100%', height: '800px' }}>
483
+ <button onClick={add_highlight}>Add Highlight</button>
484
+ <button onClick={clear_all}>Clear All Highlights</button>
485
+
486
+ <PdfViewer
487
+ ref={viewer_ref}
488
+ url="/document.pdf"
489
+ />
490
+ </div>
491
+ );
492
+ }
493
+ ```
494
+
495
+ ### PdfViewerRef Interface
496
+
497
+ The ref exposes three methods for highlight management:
498
+
499
+ #### `highlight_region(page_index, rect, options?)`
500
+
501
+ Creates a new highlight annotation on the specified page.
502
+
503
+ **Parameters:**
504
+ - `page_index` (number): Zero-based page index where the highlight should appear
505
+ - `rect` ([number, number, number, number]): Rectangle coordinates in PDF space [x1, y1, x2, y2]
506
+ - `options` (HighlightOptions, optional): Styling options
507
+
508
+ **Returns:** `string` - The unique ID of the created highlight annotation
509
+
510
+ **HighlightOptions:**
511
+ ```typescript
512
+ {
513
+ border_color?: string; // Hex color (e.g., "#FF0000")
514
+ background_color?: string; // Hex color (e.g., "#FFFF00")
515
+ background_opacity?: number; // 0-1 (e.g., 0.4)
516
+ }
517
+ ```
518
+
519
+ **Example:**
520
+ ```tsx
521
+ const id = viewer_ref.current?.highlight_region(
522
+ 0, // Page 0
523
+ [100, 500, 300, 550], // PDF coordinates
524
+ {
525
+ border_color: '#FF0000',
526
+ background_color: '#FFFF00',
527
+ background_opacity: 0.4
528
+ }
529
+ );
530
+ ```
531
+
532
+ #### `remove_highlight(id)`
533
+
534
+ Removes a specific highlight by its ID.
535
+
536
+ **Parameters:**
537
+ - `id` (string): The highlight ID returned from `highlight_region()`
538
+
539
+ **Returns:** `boolean` - `true` if the highlight was found and removed, `false` otherwise
540
+
541
+ **Example:**
542
+ ```tsx
543
+ const removed = viewer_ref.current?.remove_highlight('highlight-123');
544
+ if (removed) {
545
+ console.log('Highlight removed successfully');
546
+ }
547
+ ```
548
+
549
+ #### `clear_all_highlights()`
550
+
551
+ Removes all highlights created via the `highlight_region()` API. Does not affect user-created annotations.
552
+
553
+ **Example:**
554
+ ```tsx
555
+ viewer_ref.current?.clear_all_highlights();
556
+ ```
557
+
558
+ ### Advanced Example: Search Results Highlighting
559
+
560
+ A common use case is highlighting search results in a PDF:
561
+
562
+ ```tsx
563
+ import { useState, useRef } from 'react';
564
+ import { PdfViewer, PdfViewerRef } from 'hazo_pdf';
565
+ import 'hazo_pdf/styles.css';
566
+
567
+ interface SearchResult {
568
+ page: number;
569
+ rect: [number, number, number, number];
570
+ text: string;
571
+ }
572
+
573
+ function SearchableViewer() {
574
+ const viewer_ref = useRef<PdfViewerRef>(null);
575
+ const [highlight_ids, set_highlight_ids] = useState<string[]>([]);
576
+
577
+ // Simulated search results
578
+ const search_results: SearchResult[] = [
579
+ { page: 0, rect: [100, 500, 300, 550], text: 'Result 1' },
580
+ { page: 0, rect: [100, 400, 300, 450], text: 'Result 2' },
581
+ { page: 1, rect: [150, 600, 350, 650], text: 'Result 3' }
582
+ ];
583
+
584
+ const highlight_search_results = () => {
585
+ // Clear previous highlights
586
+ viewer_ref.current?.clear_all_highlights();
587
+
588
+ // Add new highlights
589
+ const ids = search_results.map(result =>
590
+ viewer_ref.current?.highlight_region(result.page, result.rect, {
591
+ border_color: '#3B82F6',
592
+ background_color: '#DBEAFE',
593
+ background_opacity: 0.3
594
+ })
595
+ ).filter(Boolean) as string[];
596
+
597
+ set_highlight_ids(ids);
598
+ };
599
+
600
+ const clear_search = () => {
601
+ viewer_ref.current?.clear_all_highlights();
602
+ set_highlight_ids([]);
603
+ };
604
+
605
+ return (
606
+ <div style={{ width: '100%', height: '100vh', display: 'flex', flexDirection: 'column' }}>
607
+ <div style={{ padding: '1rem', background: '#f0f0f0' }}>
608
+ <button onClick={highlight_search_results}>
609
+ Highlight Search Results ({search_results.length})
610
+ </button>
611
+ <button onClick={clear_search}>Clear Highlights</button>
612
+ <span>Highlighted: {highlight_ids.length} results</span>
613
+ </div>
614
+
615
+ <div style={{ flex: 1 }}>
616
+ <PdfViewer
617
+ ref={viewer_ref}
618
+ url="/document.pdf"
619
+ />
620
+ </div>
621
+ </div>
622
+ );
623
+ }
624
+ ```
625
+
626
+ ### Coordinate System Notes
627
+
628
+ - Highlights use PDF coordinate space (points), not screen pixels
629
+ - PDF coordinates start at the bottom-left corner (Y increases upward)
630
+ - The `rect` parameter format is `[x1, y1, x2, y2]` where:
631
+ - `x1, y1`: Bottom-left corner
632
+ - `x2, y2`: Top-right corner
633
+ - If you need to convert screen coordinates to PDF coordinates, you'll need to use the PDF page viewport (see the test app for examples)
634
+
635
+ ### Styling Defaults
636
+
637
+ If no `options` are provided to `highlight_region()`, the highlight uses default colors from the configuration file:
638
+ - `border_color`: From `highlight_border_color` config setting
639
+ - `background_color`: From `highlight_fill_color` config setting
640
+ - `background_opacity`: From `highlight_fill_opacity` config setting
641
+
642
+ You can override any or all of these on a per-highlight basis.
643
+
644
+ ---
645
+
416
646
  ## API Reference
417
647
 
418
648
  ### PdfViewer Props
@@ -433,6 +663,7 @@ See `config/hazo_pdf_config.ini` in the project root for all available configura
433
663
  | `scale` | `number` | `1.0` | Initial zoom level. Values > 1.0 zoom in, < 1.0 zoom out. |
434
664
  | `background_color` | `string` | `"#2d2d2d"` | Background color for areas outside PDF pages (hex format: `#RRGGBB`). Overrides config file value. |
435
665
  | `config_file` | `string` | `undefined` | Path to configuration INI file (e.g., `"config/hazo_pdf_config.ini"`). If not provided, uses default configuration. |
666
+ | `logger` | `Logger` | `undefined` | Logger instance from hazo_logs or custom logger matching the Logger interface. If not provided, falls back to console-based logging. Useful for debugging and monitoring PDF operations. |
436
667
 
437
668
  ##### Event Callbacks
438
669
 
@@ -573,6 +804,107 @@ interface PdfAnnotation {
573
804
  }
574
805
  ```
575
806
 
807
+ **Note:** Highlights created via the programmatic API (`PdfViewerRef.highlight_region()`) will have `type: 'Highlight'` and `flags: 'api_highlight'` to distinguish them from user-created annotations.
808
+
809
+ ### PdfViewerRef Interface
810
+
811
+ Interface for the ref exposed by `PdfViewer`. Use with `useRef<PdfViewerRef>()` to access programmatic highlight methods.
812
+
813
+ ```typescript
814
+ interface PdfViewerRef {
815
+ highlight_region: (
816
+ page_index: number,
817
+ rect: [number, number, number, number],
818
+ options?: HighlightOptions
819
+ ) => string;
820
+
821
+ remove_highlight: (id: string) => boolean;
822
+
823
+ clear_all_highlights: () => void;
824
+ }
825
+ ```
826
+
827
+ See [Programmatic Highlight API](#programmatic-highlight-api) for detailed usage.
828
+
829
+ ### HighlightOptions Interface
830
+
831
+ Options for customizing highlights created via the API.
832
+
833
+ ```typescript
834
+ interface HighlightOptions {
835
+ border_color?: string; // Hex format (e.g., "#FF0000")
836
+ background_color?: string; // Hex format (e.g., "#FFFF00")
837
+ background_opacity?: number; // 0-1 (e.g., 0.4)
838
+ }
839
+ ```
840
+
841
+ ### Logger Interface
842
+
843
+ Interface for custom logging integration. Compatible with hazo_logs and custom logger implementations.
844
+
845
+ ```typescript
846
+ interface Logger {
847
+ info: (message: string, data?: Record<string, unknown>) => void;
848
+ debug: (message: string, data?: Record<string, unknown>) => void;
849
+ warn: (message: string, data?: Record<string, unknown>) => void;
850
+ error: (message: string, data?: Record<string, unknown>) => void;
851
+ }
852
+ ```
853
+
854
+ **Usage with hazo_logs:**
855
+
856
+ ```tsx
857
+ import { PdfViewer } from 'hazo_pdf';
858
+ import { create_logger } from 'hazo_logs';
859
+
860
+ const logger = create_logger('my_app', 'config/hazo_logs_config.ini');
861
+
862
+ <PdfViewer
863
+ url="/document.pdf"
864
+ logger={logger}
865
+ />
866
+ ```
867
+
868
+ **Usage with custom logger:**
869
+
870
+ ```tsx
871
+ import { PdfViewer } from 'hazo_pdf';
872
+
873
+ const custom_logger = {
874
+ info: (message, data) => console.log('[INFO]', message, data),
875
+ debug: (message, data) => console.debug('[DEBUG]', message, data),
876
+ warn: (message, data) => console.warn('[WARN]', message, data),
877
+ error: (message, data) => console.error('[ERROR]', message, data),
878
+ };
879
+
880
+ <PdfViewer
881
+ url="/document.pdf"
882
+ logger={custom_logger}
883
+ />
884
+ ```
885
+
886
+ **Logger Utilities:**
887
+
888
+ ```typescript
889
+ import { set_logger, get_logger } from 'hazo_pdf';
890
+
891
+ // Set logger globally for all hazo_pdf components
892
+ set_logger(my_logger);
893
+
894
+ // Get current logger instance
895
+ const current_logger = get_logger();
896
+ ```
897
+
898
+ **Logging Output:**
899
+
900
+ The library logs operations such as:
901
+ - PDF conversion events (image to PDF, text to PDF, Excel to PDF)
902
+ - PDF loading and rendering
903
+ - Annotation operations
904
+ - Error conditions
905
+
906
+ If no logger is provided, hazo_pdf falls back to console-based logging with a `[hazo_pdf]` prefix.
907
+
576
908
  ### PDFDocumentProxy
577
909
 
578
910
  Type from `pdfjs-dist`. Contains PDF metadata and page proxies.
@@ -105,6 +105,42 @@ var default_config = {
105
105
  toolbar_save_label: "Save",
106
106
  toolbar_saving_label: "Saving...",
107
107
  toolbar_metadata_label: "Metadata"
108
+ },
109
+ file_manager: {
110
+ file_manager_enabled: false,
111
+ show_file_list: true,
112
+ allow_delete: true,
113
+ show_popout_button: true,
114
+ file_list_height: 60,
115
+ selected_color: "#3b82f6",
116
+ file_list_background_color: "#f9fafb",
117
+ file_list_border_color: "#e5e7eb"
118
+ },
119
+ file_upload: {
120
+ upload_enabled: true,
121
+ allowed_types: "application/pdf,image/jpeg,image/png,image/gif,image/webp,text/plain,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel",
122
+ max_file_size: 10485760,
123
+ // 10MB
124
+ max_files: 10,
125
+ show_add_button: true,
126
+ dropzone_border_color: "#d1d5db",
127
+ dropzone_border_color_active: "#3b82f6",
128
+ dropzone_background_color: "#f9fafb"
129
+ },
130
+ pdf_conversion: {
131
+ conversion_enabled: true,
132
+ page_size: "letter",
133
+ image_quality: 0.85,
134
+ image_fit: "fit",
135
+ margin: 36
136
+ },
137
+ file_button: {
138
+ icon_size: 24,
139
+ icon_color: "#6b7280",
140
+ icon_color_hover: "#374151",
141
+ icon_color_with_files: "#3b82f6",
142
+ badge_background: "#3b82f6",
143
+ badge_text_color: "#ffffff"
108
144
  }
109
145
  };
110
146
 
@@ -312,4 +348,4 @@ export {
312
348
  download_pdf,
313
349
  save_and_download_pdf
314
350
  };
315
- //# sourceMappingURL=chunk-S3AJUZ7D.js.map
351
+ //# sourceMappingURL=chunk-R4SDDAZW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/config/default_config.ts","../src/utils/pdf_saver.ts"],"sourcesContent":["/**\n * Default configuration values for hazo_pdf\n * All styling defaults organized by category\n */\n\nimport type { PdfViewerConfig } from '../types/config';\n\n/**\n * Default PDF Viewer Configuration\n * These values are used when no config file is provided or when values are missing\n */\nexport const default_config: PdfViewerConfig = {\n fonts: {\n freetext_font_family: 'Arial, sans-serif',\n freetext_font_size_min: 12,\n freetext_font_size_max: 24,\n freetext_font_size_default: 14,\n font_foreground_color: '#000000', // Black by default\n },\n\n highlight_annotation: {\n highlight_fill_color: '#FFFF00',\n highlight_fill_opacity: 0.3,\n highlight_border_color: '#FFD700',\n highlight_border_color_hover: '#FFD700',\n highlight_fill_opacity_hover: 0.4,\n },\n\n square_annotation: {\n square_fill_color: '#FF0000',\n square_fill_opacity: 0.2,\n square_border_color: '#FF0000',\n square_border_color_hover: '#CC0000',\n square_fill_opacity_hover: 0.3,\n },\n\n freetext_annotation: {\n freetext_text_color: '#000000',\n freetext_text_color_hover: '#000000',\n freetext_border_color: '#003366',\n freetext_border_width: 1,\n freetext_background_color: '#E6F3FF',\n freetext_background_opacity: 0.1,\n freetext_font_weight: 'normal',\n freetext_font_style: 'normal',\n freetext_text_decoration: 'none',\n freetext_padding_horizontal: 4,\n freetext_padding_vertical: 2,\n },\n\n page_styling: {\n page_border_color: '#999999',\n page_box_shadow: '0 2px 8px rgba(0, 0, 0, 0.3)',\n page_background_color: '#ffffff',\n },\n\n viewer: {\n viewer_background_color: '#2d2d2d',\n append_timestamp_to_text_edits: false,\n annotation_text_suffix_fixed_text: '',\n add_enclosing_brackets_to_suffixes: true,\n suffix_enclosing_brackets: '[]',\n suffix_text_position: 'below_multi_line',\n },\n\n context_menu: {\n context_menu_background_color: '#ffffff',\n context_menu_border_color: '#d1d5db',\n context_menu_item_hover_background: '#f3f4f6',\n context_menu_item_disabled_opacity: 0.5,\n right_click_custom_stamps: '', // Empty string means no custom stamps\n },\n\n dialog: {\n dialog_backdrop_opacity: 0.2,\n dialog_background_color: '#ffffff',\n dialog_border_color: '#d1d5db',\n dialog_button_submit_color: '#16a34a',\n dialog_button_submit_color_hover: '#15803d',\n dialog_button_cancel_color: '#6b7280',\n dialog_button_cancel_color_hover: '#4b5563',\n dialog_button_disabled_opacity: 0.4,\n },\n\n toolbar: {\n toolbar_background_color: '#f9fafb',\n toolbar_border_color: '#e5e7eb',\n toolbar_font_family: 'system-ui, -apple-system, sans-serif',\n toolbar_font_size: 14,\n toolbar_font_color: '#111827',\n toolbar_button_background_color: '#ffffff',\n toolbar_button_background_color_hover: '#f3f4f6',\n toolbar_button_text_color: '#374151',\n toolbar_button_active_background_color: '#3b82f6',\n toolbar_button_active_text_color: '#ffffff',\n toolbar_button_save_background_color: '#10b981',\n toolbar_button_save_background_color_hover: '#059669',\n toolbar_button_save_text_color: '#ffffff',\n toolbar_button_disabled_opacity: 0.5,\n toolbar_show_zoom_controls: true,\n toolbar_show_square_button: true,\n toolbar_show_undo_button: true,\n toolbar_show_redo_button: true,\n toolbar_show_save_button: true,\n toolbar_show_metadata_button: true,\n toolbar_show_annotate_button: true,\n toolbar_zoom_out_label: '−',\n toolbar_zoom_in_label: '+',\n toolbar_zoom_reset_label: 'Reset',\n toolbar_square_label: 'Square',\n toolbar_undo_label: 'Undo',\n toolbar_redo_label: 'Redo',\n toolbar_save_label: 'Save',\n toolbar_saving_label: 'Saving...',\n toolbar_metadata_label: 'Metadata',\n },\n\n file_manager: {\n file_manager_enabled: false,\n show_file_list: true,\n allow_delete: true,\n show_popout_button: true,\n file_list_height: 60,\n selected_color: '#3b82f6',\n file_list_background_color: '#f9fafb',\n file_list_border_color: '#e5e7eb',\n },\n\n file_upload: {\n upload_enabled: true,\n allowed_types: 'application/pdf,image/jpeg,image/png,image/gif,image/webp,text/plain,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel',\n max_file_size: 10485760, // 10MB\n max_files: 10,\n show_add_button: true,\n dropzone_border_color: '#d1d5db',\n dropzone_border_color_active: '#3b82f6',\n dropzone_background_color: '#f9fafb',\n },\n\n pdf_conversion: {\n conversion_enabled: true,\n page_size: 'letter',\n image_quality: 0.85,\n image_fit: 'fit',\n margin: 36,\n },\n\n file_button: {\n icon_size: 24,\n icon_color: '#6b7280',\n icon_color_hover: '#374151',\n icon_color_with_files: '#3b82f6',\n badge_background: '#3b82f6',\n badge_text_color: '#ffffff',\n },\n};\n","/**\n * PDF Saver Utility\n * Saves annotations directly into PDF documents using pdf-lib\n * This allows annotations to be embedded in the PDF file itself\n */\n\nimport type { PdfAnnotation, PdfViewerConfig } from '../types';\nimport { default_config } from '../config/default_config';\n\n/**\n * Save annotations into a PDF document\n * This function fetches the PDF, adds annotations, and downloads the modified PDF\n * @param pdf_url - URL of the PDF file\n * @param annotations - Array of annotations to save\n * @param output_filename - Name for the saved PDF file (default: original filename with '_annotated' suffix)\n * @param config - Optional configuration for styling values\n * @returns Promise that resolves when the PDF is saved\n */\nexport async function save_annotations_to_pdf(\n pdf_url: string,\n annotations: PdfAnnotation[],\n _output_filename?: string, // Currently unused, kept for API compatibility\n config?: PdfViewerConfig | null\n): Promise<Uint8Array> {\n try {\n // Dynamically import pdf-lib\n const { PDFDocument, rgb } = await import('pdf-lib');\n \n // Fetch the original PDF\n console.log('[PDF Saver] Fetching PDF from:', pdf_url);\n const pdf_response = await fetch(pdf_url);\n if (!pdf_response.ok) {\n throw new Error(`Failed to fetch PDF: ${pdf_response.status} ${pdf_response.statusText}`);\n }\n \n const pdf_bytes = await pdf_response.arrayBuffer();\n console.log('[PDF Saver] PDF fetched, size:', pdf_bytes.byteLength, 'bytes');\n \n // Load the PDF document\n const pdf_doc = await PDFDocument.load(pdf_bytes);\n console.log('[PDF Saver] PDF loaded, pages:', pdf_doc.getPageCount());\n \n // Get config values or use defaults\n const fonts_config = config?.fonts || default_config.fonts;\n const highlight_config = config?.highlight_annotation || default_config.highlight_annotation;\n const square_config = config?.square_annotation || default_config.square_annotation;\n const freetext_config = config?.freetext_annotation || default_config.freetext_annotation;\n \n // Add annotations to each page\n for (const annotation of annotations) {\n if (annotation.page_index >= pdf_doc.getPageCount()) {\n console.warn(`[PDF Saver] Annotation ${annotation.id} references page ${annotation.page_index}, but PDF only has ${pdf_doc.getPageCount()} pages. Skipping.`);\n continue;\n }\n \n const page = pdf_doc.getPage(annotation.page_index);\n const [x1, y1, x2, y2] = annotation.rect;\n \n // PDF coordinate system: bottom-left is origin (pdfjs-dist)\n // pdf-lib uses bottom-left as origin too, so coordinates should be fine\n // But we need to ensure rect is normalized\n const rect_x = Math.min(x1, x2);\n const rect_y = Math.min(y1, y2);\n const rect_width = Math.abs(x2 - x1);\n const rect_height = Math.abs(y2 - y1);\n \n // Parse color (hex or rgb to RGB for pdf-lib)\n // Supports both hex (#RRGGBB) and rgb(r, g, b) formats\n let color = rgb(0, 0, 0); // Default black\n if (annotation.color) {\n const color_str = annotation.color.trim();\n \n // Handle rgb(r, g, b) format\n const rgb_pattern = /^rgb\\s*\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*\\)$/i;\n const rgb_match = color_str.match(rgb_pattern);\n if (rgb_match) {\n const r = parseInt(rgb_match[1], 10);\n const g = parseInt(rgb_match[2], 10);\n const b = parseInt(rgb_match[3], 10);\n // Validate RGB values (0-255) and convert to 0-1 range for pdf-lib\n if (r >= 0 && r <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255) {\n color = rgb(r / 255, g / 255, b / 255);\n } else {\n console.warn(`[PDF Saver] Invalid RGB values for annotation ${annotation.id}: r=${r}, g=${g}, b=${b}`);\n }\n } else if (color_str.startsWith('#')) {\n // Handle hex format (#RRGGBB)\n const hex = color_str.slice(1).trim();\n if (hex.length === 6 && /^[0-9A-Fa-f]{6}$/.test(hex)) {\n const r = parseInt(hex.substring(0, 2), 16) / 255;\n const g = parseInt(hex.substring(2, 4), 16) / 255;\n const b = parseInt(hex.substring(4, 6), 16) / 255;\n color = rgb(r, g, b);\n } else {\n console.warn(`[PDF Saver] Invalid hex color format for annotation ${annotation.id}: ${color_str}`);\n }\n } else {\n console.warn(`[PDF Saver] Unrecognized color format for annotation ${annotation.id}: ${color_str}`);\n }\n }\n \n // Create annotation based on type using pdf-lib's annotation methods\n try {\n switch (annotation.type) {\n case 'Square': {\n // Create a rectangle/square annotation\n page.drawRectangle({\n x: rect_x,\n y: rect_y,\n width: rect_width,\n height: rect_height,\n borderColor: color,\n borderWidth: 2,\n borderOpacity: 0.8,\n });\n \n // Add text comment if present\n if (annotation.contents) {\n const comment_color_str = (annotation.color || square_config.square_border_color).trim();\n let comment_r = 0, comment_g = 0, comment_b = 0;\n \n // Parse color (hex or rgb format)\n const rgb_pattern = /^rgb\\s*\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*\\)$/i;\n const rgb_match = comment_color_str.match(rgb_pattern);\n if (rgb_match) {\n comment_r = parseInt(rgb_match[1], 10) / 255;\n comment_g = parseInt(rgb_match[2], 10) / 255;\n comment_b = parseInt(rgb_match[3], 10) / 255;\n } else if (comment_color_str.startsWith('#')) {\n const hex = comment_color_str.slice(1).trim();\n if (hex.length === 6 && /^[0-9A-Fa-f]{6}$/.test(hex)) {\n comment_r = parseInt(hex.substring(0, 2), 16) / 255;\n comment_g = parseInt(hex.substring(2, 4), 16) / 255;\n comment_b = parseInt(hex.substring(4, 6), 16) / 255;\n }\n }\n \n page.drawText(annotation.contents, {\n x: rect_x,\n y: rect_y + rect_height + 5,\n size: fonts_config.freetext_font_size_default,\n color: rgb(comment_r, comment_g, comment_b),\n });\n }\n break;\n }\n \n case 'Highlight': {\n // Create a highlight annotation (semi-transparent rectangle)\n const highlight_color_str = (annotation.color || highlight_config.highlight_fill_color).trim();\n let highlight_r = 255 / 255, highlight_g = 255 / 255, highlight_b = 0 / 255; // Default yellow\n \n // Parse color (hex or rgb format)\n const rgb_pattern = /^rgb\\s*\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*\\)$/i;\n const rgb_match = highlight_color_str.match(rgb_pattern);\n if (rgb_match) {\n highlight_r = parseInt(rgb_match[1], 10) / 255;\n highlight_g = parseInt(rgb_match[2], 10) / 255;\n highlight_b = parseInt(rgb_match[3], 10) / 255;\n } else if (highlight_color_str.startsWith('#')) {\n const hex = highlight_color_str.slice(1).trim();\n if (hex.length === 6 && /^[0-9A-Fa-f]{6}$/.test(hex)) {\n highlight_r = parseInt(hex.substring(0, 2), 16) / 255;\n highlight_g = parseInt(hex.substring(2, 4), 16) / 255;\n highlight_b = parseInt(hex.substring(4, 6), 16) / 255;\n }\n }\n const highlight_color = rgb(highlight_r, highlight_g, highlight_b);\n \n page.drawRectangle({\n x: rect_x,\n y: rect_y,\n width: rect_width,\n height: rect_height,\n color: highlight_color,\n opacity: highlight_config.highlight_fill_opacity,\n });\n \n // Add text comment if present\n if (annotation.contents) {\n page.drawText(annotation.contents, {\n x: rect_x,\n y: rect_y + rect_height + 5,\n size: fonts_config.freetext_font_size_default,\n color: rgb(0, 0, 0),\n });\n }\n break;\n }\n \n case 'FreeText': {\n // Create a free text annotation\n if (annotation.contents) {\n // Text color priority: annotation.color > freetext_text_color > font_foreground_color > default black\n const text_color_str = (annotation.color || \n freetext_config.freetext_text_color || \n fonts_config.font_foreground_color || \n '#000000').trim();\n let text_r = 0, text_g = 0, text_b = 0;\n \n // Parse color (hex or rgb format)\n const rgb_pattern = /^rgb\\s*\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*\\)$/i;\n const rgb_match = text_color_str.match(rgb_pattern);\n if (rgb_match) {\n text_r = parseInt(rgb_match[1], 10) / 255;\n text_g = parseInt(rgb_match[2], 10) / 255;\n text_b = parseInt(rgb_match[3], 10) / 255;\n } else if (text_color_str.startsWith('#')) {\n const hex = text_color_str.slice(1).trim();\n if (hex.length === 6 && /^[0-9A-Fa-f]{6}$/.test(hex)) {\n text_r = parseInt(hex.substring(0, 2), 16) / 255;\n text_g = parseInt(hex.substring(2, 4), 16) / 255;\n text_b = parseInt(hex.substring(4, 6), 16) / 255;\n }\n }\n \n page.drawText(annotation.contents, {\n x: rect_x,\n y: rect_y,\n size: fonts_config.freetext_font_size_default,\n color: rgb(text_r, text_g, text_b),\n maxWidth: rect_width,\n });\n }\n break;\n }\n \n default:\n console.warn(`[PDF Saver] Unsupported annotation type: ${annotation.type}`);\n }\n } catch (annotation_error) {\n console.error(`[PDF Saver] Error adding annotation ${annotation.id}:`, annotation_error);\n // Continue with other annotations\n }\n }\n \n // Save the PDF\n const modified_pdf_bytes = await pdf_doc.save();\n console.log('[PDF Saver] PDF modified, size:', modified_pdf_bytes.length, 'bytes');\n \n return modified_pdf_bytes;\n } catch (error) {\n if (error && typeof error === 'object' && 'message' in error && \n typeof error.message === 'string' && error.message.includes('pdf-lib')) {\n throw new Error('pdf-lib is required to save annotations to PDF. Please install it: npm install pdf-lib');\n }\n console.error('[PDF Saver] Error saving PDF:', error);\n throw error;\n }\n}\n\n/**\n * Download PDF bytes as a file\n * @param pdf_bytes - PDF file bytes\n * @param filename - Name for the downloaded file\n */\nexport function download_pdf(pdf_bytes: Uint8Array, filename: string): void {\n // Create a new ArrayBuffer view to ensure compatibility with Blob constructor\n // Uint8Array.buffer can be SharedArrayBuffer, which Blob doesn't accept directly\n const buffer = new Uint8Array(pdf_bytes).buffer;\n const blob = new Blob([buffer], { type: 'application/pdf' });\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = filename;\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n URL.revokeObjectURL(url);\n}\n\n/**\n * Save annotations to PDF and download\n * @param pdf_url - URL of the PDF file\n * @param annotations - Array of annotations to save\n * @param output_filename - Name for the saved PDF file (default: original filename with '_annotated' suffix)\n * @param config - Optional configuration for styling values\n */\nexport async function save_and_download_pdf(\n pdf_url: string,\n annotations: PdfAnnotation[],\n output_filename?: string,\n config?: PdfViewerConfig | null\n): Promise<void> {\n const pdf_bytes = await save_annotations_to_pdf(pdf_url, annotations, output_filename, config);\n \n // Generate output filename\n const original_filename = pdf_url.split('/').pop() || 'document.pdf';\n const filename_without_ext = original_filename.replace(/\\.pdf$/i, '');\n const final_filename = output_filename || `${filename_without_ext}_annotated.pdf`;\n \n // Download the modified PDF\n download_pdf(pdf_bytes, final_filename);\n console.log('[PDF Saver] PDF saved as:', final_filename);\n}\n\n"],"mappings":"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","names":[]}