@epam/pdf-highlighter-kit 0.0.10 → 0.0.14
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/dist/PDFHighlightViewer.d.ts +14 -4
- package/dist/PDFHighlightViewer.d.ts.map +1 -1
- package/dist/PDFHighlightViewer.js +130 -49
- package/dist/PDFHighlightViewer.js.map +1 -1
- package/dist/api.d.ts +11 -5
- package/dist/api.d.ts.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js.map +1 -1
- package/dist/core/pdf-engine.d.ts +5 -3
- package/dist/core/pdf-engine.d.ts.map +1 -1
- package/dist/core/pdf-engine.js +30 -18
- package/dist/core/pdf-engine.js.map +1 -1
- package/dist/core/performance-optimizer.d.ts +13 -10
- package/dist/core/performance-optimizer.d.ts.map +1 -1
- package/dist/core/performance-optimizer.js +19 -5
- package/dist/core/performance-optimizer.js.map +1 -1
- package/dist/core/unified-layer-builder.d.ts +8 -2
- package/dist/core/unified-layer-builder.d.ts.map +1 -1
- package/dist/core/unified-layer-builder.js +58 -22
- package/dist/core/unified-layer-builder.js.map +1 -1
- package/dist/core/viewport-manager.d.ts +3 -3
- package/dist/core/viewport-manager.d.ts.map +1 -1
- package/dist/core/viewport-manager.js +2 -2
- package/dist/core/viewport-manager.js.map +1 -1
- package/dist/index.d.ts +11 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -7
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +32 -9
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -1
- package/dist/utils/label-style.d.ts.map +1 -1
- package/dist/utils/label-style.js +3 -2
- package/dist/utils/label-style.js.map +1 -1
- package/dist/utils/pdf-rotation-math.d.ts +11 -0
- package/dist/utils/pdf-rotation-math.d.ts.map +1 -0
- package/dist/utils/pdf-rotation-math.js +16 -0
- package/dist/utils/pdf-rotation-math.js.map +1 -0
- package/dist/utils/pdf-utils.d.ts +3 -2
- package/dist/utils/pdf-utils.d.ts.map +1 -1
- package/dist/utils/pdf-utils.js +2 -2
- package/dist/utils/pdf-utils.js.map +1 -1
- package/dist/utils/rotate-bbox.d.ts +20 -0
- package/dist/utils/rotate-bbox.d.ts.map +1 -0
- package/dist/utils/rotate-bbox.js +101 -0
- package/dist/utils/rotate-bbox.js.map +1 -0
- package/dist/utils/worker-loader-simple.d.ts.map +1 -1
- package/dist/utils/worker-loader-simple.js +4 -1
- package/dist/utils/worker-loader-simple.js.map +1 -1
- package/package.json +4 -4
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { PDFHighlightViewer as IPDFHighlightViewer } from './api';
|
|
2
|
-
import { ViewerOptions, LoadPDFOptions, TextRange, SelectionWithMetadata, PerformanceMetrics, HighlightAnalytics, AccessibilityFeatures, InteractionMode, InputHighlightData, HighlightStyle, HighlightLabelStyle, ZoomValue, ThumbnailOptions } from './types';
|
|
2
|
+
import { PDFSource, ViewerOptions, LoadPDFOptions, TextRange, SelectionWithMetadata, PerformanceMetrics, HighlightAnalytics, AccessibilityFeatures, InteractionMode, InputHighlightData, HighlightStyle, HighlightLabelStyle, ZoomValue, ThumbnailOptions, PageRotationDegrees, RotationDirection } from './types';
|
|
3
3
|
type EventCallback = (data?: unknown) => void;
|
|
4
4
|
export declare class PDFHighlightViewer implements IPDFHighlightViewer {
|
|
5
5
|
private pdfEngine;
|
|
@@ -23,12 +23,17 @@ export declare class PDFHighlightViewer implements IPDFHighlightViewer {
|
|
|
23
23
|
private isInitialized;
|
|
24
24
|
private navIndex;
|
|
25
25
|
private pageDimensions;
|
|
26
|
+
/** Intrinsic page size in normalized units (PDF default viewport at currentScale / scale). */
|
|
27
|
+
private intrinsicPageNormalized;
|
|
28
|
+
/** Extra clockwise rotation per page on top of PDF `/Rotate`. */
|
|
29
|
+
private pageDisplayRotations;
|
|
26
30
|
private defaultPageHeight;
|
|
27
31
|
private eventListeners;
|
|
28
32
|
private scrollListener;
|
|
29
33
|
private analytics;
|
|
30
34
|
constructor();
|
|
31
35
|
init(container: HTMLElement, options?: ViewerOptions): Promise<void>;
|
|
36
|
+
private syncPageDisplayRotationsFromOptions;
|
|
32
37
|
/**
|
|
33
38
|
* Setup container with proper structure and styling
|
|
34
39
|
*/
|
|
@@ -50,8 +55,11 @@ export declare class PDFHighlightViewer implements IPDFHighlightViewer {
|
|
|
50
55
|
* Set placeholder size for a page container using real PDF dimensions
|
|
51
56
|
*/
|
|
52
57
|
private setPagePlaceholderSize;
|
|
58
|
+
private getUserClockwiseRotation;
|
|
59
|
+
private effectiveViewportRotationDegrees;
|
|
53
60
|
/**
|
|
54
|
-
* Get and cache
|
|
61
|
+
* Get and cache display page dimensions (rotated viewport pixels at currentScale)
|
|
62
|
+
* and intrinsic normalized size for highlight mapping.
|
|
55
63
|
*/
|
|
56
64
|
private getPageDimensions;
|
|
57
65
|
/**
|
|
@@ -62,7 +70,7 @@ export declare class PDFHighlightViewer implements IPDFHighlightViewer {
|
|
|
62
70
|
* Handle keyboard navigation
|
|
63
71
|
*/
|
|
64
72
|
private handleKeyboardNavigation;
|
|
65
|
-
loadPDF(source:
|
|
73
|
+
loadPDF(source: PDFSource, options?: LoadPDFOptions): Promise<void>;
|
|
66
74
|
/**
|
|
67
75
|
* Normalize selectedPages: filter to 1..numPages, dedupe, sort. Empty result => null (show all).
|
|
68
76
|
*/
|
|
@@ -95,6 +103,8 @@ export declare class PDFHighlightViewer implements IPDFHighlightViewer {
|
|
|
95
103
|
resetZoom(): void;
|
|
96
104
|
getCurrentPage(): number;
|
|
97
105
|
getTotalPages(): number;
|
|
106
|
+
setPageDisplayRotation(pageNumber: number, degrees: PageRotationDegrees, direction?: RotationDirection): void;
|
|
107
|
+
getPageDisplayRotation(pageNumber: number): PageRotationDegrees;
|
|
98
108
|
getThumbnails(pageNumbers: number[], options?: ThumbnailOptions): Promise<Map<number, HTMLCanvasElement>>;
|
|
99
109
|
getThumbnailsDataUrl(pageNumbers: number[], options?: ThumbnailOptions): Promise<Map<number, string>>;
|
|
100
110
|
/**
|
|
@@ -135,7 +145,7 @@ export declare class PDFHighlightViewer implements IPDFHighlightViewer {
|
|
|
135
145
|
getSelection: () => string;
|
|
136
146
|
getSelectionWithContext: () => SelectionWithMetadata | null;
|
|
137
147
|
clearSelection: () => void;
|
|
138
|
-
selectText: (
|
|
148
|
+
selectText: (_range: TextRange) => void;
|
|
139
149
|
copySelection: (format?: "plain" | "formatted" | "citation") => void;
|
|
140
150
|
createHighlightFromSelection: (style?: HighlightStyle) => InputHighlightData | null;
|
|
141
151
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PDFHighlightViewer.d.ts","sourceRoot":"","sources":["../src/PDFHighlightViewer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,IAAI,mBAAmB,EAAE,MAAM,OAAO,CAAC;AAClE,OAAO,EACL,aAAa,EACb,cAAc,EAKd,SAAS,EACT,qBAAqB,EACrB,kBAAkB,EAClB,kBAAkB,EAClB,qBAAqB,EACrB,eAAe,EACf,kBAAkB,EAElB,cAAc,EACd,mBAAmB,EACnB,SAAS,EAET,gBAAgB,
|
|
1
|
+
{"version":3,"file":"PDFHighlightViewer.d.ts","sourceRoot":"","sources":["../src/PDFHighlightViewer.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ZoomMode, } from './types';
|
|
1
|
+
import { ZoomMode, RotationDirection, } from './types';
|
|
2
2
|
import { PDFEngine } from './core/pdf-engine';
|
|
3
3
|
import { ViewportManager } from './core/viewport-manager';
|
|
4
4
|
import { UnifiedLayerBuilder } from './core/unified-layer-builder';
|
|
@@ -7,6 +7,8 @@ import { PerformanceOptimizer } from './core/performance-optimizer';
|
|
|
7
7
|
import { buildHighlightsIndex } from './utils/highlight-adapter';
|
|
8
8
|
import { applyHighlightVisualStyle, getHighlightBaseOpacity, getHighlightHoverOpacity, resolveHighlightStyle, } from './utils/highlight-style';
|
|
9
9
|
import { appendLabelIcon, applyBaseOutlineStyle, applyLabelOutlineStyle, applyLabelStyle, scaleLabelStyle, } from './utils/label-style';
|
|
10
|
+
import { clockwiseToCcw, displayRotationToClockwise, rotateBoundingBoxForCcwRotation, } from './utils/rotate-bbox';
|
|
11
|
+
import { sumPdfIntrinsicAndUserRotation } from './utils/pdf-rotation-math';
|
|
10
12
|
const CONTAINER_PADDING = 40;
|
|
11
13
|
const ZOOM_STEP = 1.2;
|
|
12
14
|
export class PDFHighlightViewer {
|
|
@@ -31,6 +33,10 @@ export class PDFHighlightViewer {
|
|
|
31
33
|
this.isInitialized = false;
|
|
32
34
|
this.navIndex = -1;
|
|
33
35
|
this.pageDimensions = new Map();
|
|
36
|
+
/** Intrinsic page size in normalized units (PDF default viewport at currentScale / scale). */
|
|
37
|
+
this.intrinsicPageNormalized = new Map();
|
|
38
|
+
/** Extra clockwise rotation per page on top of PDF `/Rotate`. */
|
|
39
|
+
this.pageDisplayRotations = new Map();
|
|
34
40
|
this.defaultPageHeight = 800;
|
|
35
41
|
this.eventListeners = [];
|
|
36
42
|
this.scrollListener = null;
|
|
@@ -60,9 +66,8 @@ export class PDFHighlightViewer {
|
|
|
60
66
|
clearSelection: () => {
|
|
61
67
|
this.interactionHandler.clearSelection();
|
|
62
68
|
},
|
|
63
|
-
selectText: (
|
|
69
|
+
selectText: (_range) => {
|
|
64
70
|
// TODO: Implement programmatic text selection
|
|
65
|
-
console.log('selectText not yet implemented:', range);
|
|
66
71
|
},
|
|
67
72
|
copySelection: (format = 'plain') => {
|
|
68
73
|
const selection = this.textSelection.getSelection();
|
|
@@ -175,9 +180,22 @@ export class PDFHighlightViewer {
|
|
|
175
180
|
if (this.options.accessibility) {
|
|
176
181
|
this.setupAccessibility();
|
|
177
182
|
}
|
|
183
|
+
this.syncPageDisplayRotationsFromOptions();
|
|
178
184
|
this.isInitialized = true;
|
|
179
185
|
this.emit('initialized');
|
|
180
186
|
}
|
|
187
|
+
syncPageDisplayRotationsFromOptions() {
|
|
188
|
+
this.pageDisplayRotations.clear();
|
|
189
|
+
const raw = this.options.pageDisplayRotations;
|
|
190
|
+
if (!raw)
|
|
191
|
+
return;
|
|
192
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
193
|
+
const n = Number(key);
|
|
194
|
+
if (Number.isInteger(n) && n >= 1) {
|
|
195
|
+
this.pageDisplayRotations.set(n, value);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
181
199
|
/**
|
|
182
200
|
* Setup container with proper structure and styling
|
|
183
201
|
*/
|
|
@@ -409,22 +427,38 @@ export class PDFHighlightViewer {
|
|
|
409
427
|
pageContainer.style.height = `${this.defaultPageHeight}px`;
|
|
410
428
|
}
|
|
411
429
|
}
|
|
430
|
+
getUserClockwiseRotation(pageNumber) {
|
|
431
|
+
return this.pageDisplayRotations.get(pageNumber) ?? 0;
|
|
432
|
+
}
|
|
433
|
+
effectiveViewportRotationDegrees(intrinsicRotateDegrees, pageNumber) {
|
|
434
|
+
return sumPdfIntrinsicAndUserRotation(intrinsicRotateDegrees, this.getUserClockwiseRotation(pageNumber));
|
|
435
|
+
}
|
|
412
436
|
/**
|
|
413
|
-
* Get and cache
|
|
437
|
+
* Get and cache display page dimensions (rotated viewport pixels at currentScale)
|
|
438
|
+
* and intrinsic normalized size for highlight mapping.
|
|
414
439
|
*/
|
|
415
440
|
async getPageDimensions(pageNumber) {
|
|
416
|
-
|
|
417
|
-
const
|
|
418
|
-
if (
|
|
419
|
-
return
|
|
420
|
-
|
|
421
|
-
const
|
|
422
|
-
const
|
|
441
|
+
const cachedDisplay = this.pageDimensions.get(pageNumber);
|
|
442
|
+
const cachedIntrinsic = this.intrinsicPageNormalized.get(pageNumber);
|
|
443
|
+
if (cachedDisplay && cachedIntrinsic) {
|
|
444
|
+
return cachedDisplay;
|
|
445
|
+
}
|
|
446
|
+
const pdfPage = await this.pdfEngine.getPage(pageNumber);
|
|
447
|
+
const intrinsicVp = pdfPage.getViewport({ scale: this.currentScale });
|
|
448
|
+
const scale = this.currentScale > 0 ? this.currentScale : 1;
|
|
449
|
+
this.intrinsicPageNormalized.set(pageNumber, {
|
|
450
|
+
width: intrinsicVp.width / scale,
|
|
451
|
+
height: intrinsicVp.height / scale,
|
|
452
|
+
});
|
|
453
|
+
const effectiveRotation = this.effectiveViewportRotationDegrees(pdfPage.rotate, pageNumber);
|
|
454
|
+
const displayVp = pdfPage.getViewport({
|
|
455
|
+
scale: this.currentScale,
|
|
456
|
+
rotation: effectiveRotation,
|
|
457
|
+
});
|
|
423
458
|
const dimensions = {
|
|
424
|
-
width:
|
|
425
|
-
height:
|
|
459
|
+
width: displayVp.width,
|
|
460
|
+
height: displayVp.height,
|
|
426
461
|
};
|
|
427
|
-
// Cache the dimensions
|
|
428
462
|
this.pageDimensions.set(pageNumber, dimensions);
|
|
429
463
|
return dimensions;
|
|
430
464
|
}
|
|
@@ -493,6 +527,7 @@ export class PDFHighlightViewer {
|
|
|
493
527
|
await this.pdfEngine.loadDocument(source);
|
|
494
528
|
const docInfo = this.pdfEngine.getDocumentInfo();
|
|
495
529
|
this.documentNumPages = docInfo.numPages;
|
|
530
|
+
this.syncPageDisplayRotationsFromOptions();
|
|
496
531
|
const rawSelected = options?.selectedPages ?? this.options.selectedPages;
|
|
497
532
|
const selectedPages = this.normalizeSelectedPages(rawSelected, this.documentNumPages);
|
|
498
533
|
this.selectedPages = selectedPages;
|
|
@@ -601,7 +636,7 @@ export class PDFHighlightViewer {
|
|
|
601
636
|
const pageContainer = this.pageContainers.get(pageNumber);
|
|
602
637
|
if (pageContainer && !pageContainer.classList.contains('rendered')) {
|
|
603
638
|
batch.push(this.renderPage(pageNumber).catch((error) => {
|
|
604
|
-
console.
|
|
639
|
+
console.error(`Failed to render page ${pageNumber}:`, error);
|
|
605
640
|
}));
|
|
606
641
|
}
|
|
607
642
|
}
|
|
@@ -618,15 +653,15 @@ export class PDFHighlightViewer {
|
|
|
618
653
|
return;
|
|
619
654
|
// Check if already rendered
|
|
620
655
|
if (pageContainer.classList.contains('rendered')) {
|
|
621
|
-
console.log(`Page ${pageNumber}: skipping, already has 'rendered' class`);
|
|
622
656
|
return;
|
|
623
657
|
}
|
|
624
|
-
console.log(`Page ${pageNumber}: rendering at scale ${this.currentScale}`);
|
|
625
658
|
try {
|
|
626
659
|
// Add loading state
|
|
627
660
|
pageContainer.classList.add('loading');
|
|
661
|
+
const pdfPage = await this.pdfEngine.getPage(pageNumber);
|
|
662
|
+
const effectiveRotation = this.effectiveViewportRotationDegrees(pdfPage.rotate, pageNumber);
|
|
628
663
|
// Render PDF canvas
|
|
629
|
-
const canvas = await this.pdfEngine.renderPage(pageNumber, this.currentScale);
|
|
664
|
+
const canvas = await this.pdfEngine.renderPage(pageNumber, this.currentScale, undefined, effectiveRotation);
|
|
630
665
|
// Clear container and add canvas
|
|
631
666
|
pageContainer.innerHTML = '';
|
|
632
667
|
pageContainer.appendChild(canvas);
|
|
@@ -698,8 +733,10 @@ export class PDFHighlightViewer {
|
|
|
698
733
|
if (!this.container) {
|
|
699
734
|
return { scaleX: 1, scaleY: 1 };
|
|
700
735
|
}
|
|
701
|
-
const
|
|
702
|
-
const
|
|
736
|
+
const pageNum = this.currentPage || 1;
|
|
737
|
+
const page = await this.pdfEngine.getPage(pageNum);
|
|
738
|
+
const effectiveRotation = this.effectiveViewportRotationDegrees(page.rotate, pageNum);
|
|
739
|
+
const viewport = page.getViewport({ scale: 1, rotation: effectiveRotation });
|
|
703
740
|
const scaleX = (this.container.clientWidth - CONTAINER_PADDING) / viewport.width;
|
|
704
741
|
const scaleY = (this.container.clientHeight - CONTAINER_PADDING) / viewport.height;
|
|
705
742
|
return { scaleX, scaleY };
|
|
@@ -719,8 +756,38 @@ export class PDFHighlightViewer {
|
|
|
719
756
|
getTotalPages() {
|
|
720
757
|
return this.totalPages;
|
|
721
758
|
}
|
|
759
|
+
setPageDisplayRotation(pageNumber, degrees, direction = RotationDirection.Clockwise) {
|
|
760
|
+
if (degrees === 0) {
|
|
761
|
+
this.pageDisplayRotations.delete(pageNumber);
|
|
762
|
+
if (this.options.pageDisplayRotations) {
|
|
763
|
+
const next = { ...this.options.pageDisplayRotations };
|
|
764
|
+
delete next[pageNumber];
|
|
765
|
+
this.options.pageDisplayRotations = Object.keys(next).length > 0 ? next : undefined;
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
else {
|
|
769
|
+
const cw = displayRotationToClockwise(degrees, direction);
|
|
770
|
+
this.pageDisplayRotations.set(pageNumber, cw);
|
|
771
|
+
this.options.pageDisplayRotations = {
|
|
772
|
+
...(this.options.pageDisplayRotations ?? {}),
|
|
773
|
+
[pageNumber]: cw,
|
|
774
|
+
};
|
|
775
|
+
}
|
|
776
|
+
void this.reRenderVisiblePages();
|
|
777
|
+
this.emit('pageRotationChanged', { pageNumber, degrees, direction });
|
|
778
|
+
}
|
|
779
|
+
getPageDisplayRotation(pageNumber) {
|
|
780
|
+
return this.pageDisplayRotations.get(pageNumber) ?? 0;
|
|
781
|
+
}
|
|
722
782
|
async getThumbnails(pageNumbers, options) {
|
|
723
|
-
|
|
783
|
+
const viewportRotations = { ...(options?.viewportRotations ?? {}) };
|
|
784
|
+
for (const n of pageNumbers) {
|
|
785
|
+
if (viewportRotations[n] !== undefined)
|
|
786
|
+
continue;
|
|
787
|
+
const pdfPage = await this.pdfEngine.getPage(n);
|
|
788
|
+
viewportRotations[n] = this.effectiveViewportRotationDegrees(pdfPage.rotate, n);
|
|
789
|
+
}
|
|
790
|
+
return this.pdfEngine.getThumbnails(pageNumbers, { ...options, viewportRotations });
|
|
724
791
|
}
|
|
725
792
|
async getThumbnailsDataUrl(pageNumbers, options) {
|
|
726
793
|
const canvases = await this.getThumbnails(pageNumbers, options);
|
|
@@ -814,7 +881,7 @@ export class PDFHighlightViewer {
|
|
|
814
881
|
// Refresh only affected pages
|
|
815
882
|
for (const pageNumber of affectedPages) {
|
|
816
883
|
this.refreshHighlightLayerForPage(pageNumber);
|
|
817
|
-
this.updatePageUnifiedLayer(pageNumber);
|
|
884
|
+
void this.updatePageUnifiedLayer(pageNumber);
|
|
818
885
|
this.buildSpatialIndexForPage(pageNumber);
|
|
819
886
|
}
|
|
820
887
|
this.emit('highlightAdded', { highlight, pages: Array.from(affectedPages) });
|
|
@@ -836,7 +903,7 @@ export class PDFHighlightViewer {
|
|
|
836
903
|
this.updateAnalytics();
|
|
837
904
|
for (const pageNumber of affectedPages) {
|
|
838
905
|
this.refreshHighlightLayerForPage(pageNumber);
|
|
839
|
-
this.updatePageUnifiedLayer(pageNumber);
|
|
906
|
+
void this.updatePageUnifiedLayer(pageNumber);
|
|
840
907
|
this.buildSpatialIndexForPage(pageNumber);
|
|
841
908
|
}
|
|
842
909
|
this.emit('highlightRemoved', { termId, pages: Array.from(affectedPages) });
|
|
@@ -869,7 +936,7 @@ export class PDFHighlightViewer {
|
|
|
869
936
|
this.updateAnalytics();
|
|
870
937
|
for (const pageNumber of affectedPages) {
|
|
871
938
|
this.refreshHighlightLayerForPage(pageNumber);
|
|
872
|
-
this.updatePageUnifiedLayer(pageNumber);
|
|
939
|
+
void this.updatePageUnifiedLayer(pageNumber);
|
|
873
940
|
this.buildSpatialIndexForPage(pageNumber);
|
|
874
941
|
}
|
|
875
942
|
this.emit('styleUpdated', { termId, style: next.style, patch: stylePatch });
|
|
@@ -877,7 +944,7 @@ export class PDFHighlightViewer {
|
|
|
877
944
|
/**
|
|
878
945
|
* Update unified layer for a specific page
|
|
879
946
|
*/
|
|
880
|
-
updatePageUnifiedLayer(pageNumber) {
|
|
947
|
+
async updatePageUnifiedLayer(pageNumber) {
|
|
881
948
|
const pageContainer = this.pageContainers.get(pageNumber);
|
|
882
949
|
if (!pageContainer)
|
|
883
950
|
return;
|
|
@@ -897,7 +964,19 @@ export class PDFHighlightViewer {
|
|
|
897
964
|
};
|
|
898
965
|
}),
|
|
899
966
|
}));
|
|
900
|
-
|
|
967
|
+
let viewport;
|
|
968
|
+
try {
|
|
969
|
+
const pdfPage = await this.pdfEngine.getPage(pageNumber);
|
|
970
|
+
const effectiveRotation = this.effectiveViewportRotationDegrees(pdfPage.rotate, pageNumber);
|
|
971
|
+
viewport = pdfPage.getViewport({
|
|
972
|
+
scale: this.currentScale,
|
|
973
|
+
rotation: effectiveRotation,
|
|
974
|
+
});
|
|
975
|
+
}
|
|
976
|
+
catch {
|
|
977
|
+
viewport = undefined;
|
|
978
|
+
}
|
|
979
|
+
this.layerBuilder.updateHighlights(pageContainer, normalizedHighlights, pageNumber, pageData.textContent, this.currentScale, viewport);
|
|
901
980
|
}
|
|
902
981
|
/**
|
|
903
982
|
* Update all unified layers
|
|
@@ -926,10 +1005,10 @@ export class PDFHighlightViewer {
|
|
|
926
1005
|
if (!this.container)
|
|
927
1006
|
return;
|
|
928
1007
|
const pageToKeep = this.currentPage;
|
|
929
|
-
console.log('Zoom changed to:', this.currentScale);
|
|
930
1008
|
// Clear ALL cached data for the new scale
|
|
931
1009
|
this.pdfEngine.clearAllPageCache();
|
|
932
|
-
this.pageDimensions.clear();
|
|
1010
|
+
this.pageDimensions.clear();
|
|
1011
|
+
this.intrinsicPageNormalized.clear();
|
|
933
1012
|
// Clear all containers and update their sizes for new scale
|
|
934
1013
|
let totalHeight = 0;
|
|
935
1014
|
let validDimensions = 0;
|
|
@@ -960,7 +1039,6 @@ export class PDFHighlightViewer {
|
|
|
960
1039
|
// Recompute visible pages after scroll restore for correct rendering
|
|
961
1040
|
const scrollTopAfterRestore = this.container.scrollTop;
|
|
962
1041
|
const visiblePagesAfterRestore = this.viewportManager.getVisiblePages(scrollTopAfterRestore, containerHeight);
|
|
963
|
-
console.log('Re-rendering visible pages at new scale:', visiblePagesAfterRestore);
|
|
964
1042
|
// Render visible pages immediately
|
|
965
1043
|
for (const pageNumber of visiblePagesAfterRestore) {
|
|
966
1044
|
try {
|
|
@@ -1041,14 +1119,8 @@ export class PDFHighlightViewer {
|
|
|
1041
1119
|
if (!this.container)
|
|
1042
1120
|
return;
|
|
1043
1121
|
const pageTop = this.getPageScrollTop(pageNumber);
|
|
1044
|
-
const
|
|
1045
|
-
const
|
|
1046
|
-
if (!pixelDimensions) {
|
|
1047
|
-
throw new Error(`Page dimensions for page ${pageNumber} are not available`);
|
|
1048
|
-
}
|
|
1049
|
-
const dimensions = this.toPageCoordinateDimensions(pixelDimensions);
|
|
1050
|
-
const normalizedY = origin.startsWith('bottom') ? dimensions.height - y : y;
|
|
1051
|
-
const targetY = pageTop + normalizedY * this.currentScale - this.container.clientHeight * 0.3;
|
|
1122
|
+
const normalizedBBox = this.normalizeBBoxForPage({ page: pageNumber, x1: x, y1: y, x2: x, y2: y }, pageNumber, this.options.bboxSourceDimensions, this.options.bboxOrigin);
|
|
1123
|
+
const targetY = pageTop + normalizedBBox.y1 * this.currentScale - this.container.clientHeight * 0.3;
|
|
1052
1124
|
this.container.scrollTop = Math.max(0, targetY);
|
|
1053
1125
|
this.emit('coordinateNavigation', { pageNumber, x, y });
|
|
1054
1126
|
}
|
|
@@ -1118,11 +1190,9 @@ export class PDFHighlightViewer {
|
|
|
1118
1190
|
}
|
|
1119
1191
|
enableProfiling() {
|
|
1120
1192
|
// TODO: Enable detailed performance profiling
|
|
1121
|
-
console.log('Profiling enabled');
|
|
1122
1193
|
}
|
|
1123
1194
|
disableProfiling() {
|
|
1124
1195
|
// TODO: Disable detailed performance profiling
|
|
1125
|
-
console.log('Profiling disabled');
|
|
1126
1196
|
}
|
|
1127
1197
|
// =============================================================================
|
|
1128
1198
|
// Event Management
|
|
@@ -1516,11 +1586,12 @@ export class PDFHighlightViewer {
|
|
|
1516
1586
|
normalizeBBoxForPage(bbox, pageNumber, bboxSourceDimensions, bboxOrigin) {
|
|
1517
1587
|
const origin = bboxOrigin ?? this.options.bboxOrigin ?? 'bottom-right';
|
|
1518
1588
|
const computedSourceDimensions = bboxSourceDimensions ?? this.options.bboxSourceDimensions;
|
|
1519
|
-
const
|
|
1520
|
-
if (!
|
|
1589
|
+
const intrinsic = this.intrinsicPageNormalized.get(pageNumber);
|
|
1590
|
+
if (!intrinsic) {
|
|
1521
1591
|
throw new Error(`Page dimensions for page ${pageNumber} are not available`);
|
|
1522
1592
|
}
|
|
1523
|
-
const
|
|
1593
|
+
const pageWidth = intrinsic.width;
|
|
1594
|
+
const pageHeight = intrinsic.height;
|
|
1524
1595
|
let x1 = bbox.x1;
|
|
1525
1596
|
let x2 = bbox.x2;
|
|
1526
1597
|
let y1 = bbox.y1;
|
|
@@ -1543,12 +1614,18 @@ export class PDFHighlightViewer {
|
|
|
1543
1614
|
y1 = pageHeight - y1;
|
|
1544
1615
|
y2 = pageHeight - y2;
|
|
1545
1616
|
}
|
|
1546
|
-
|
|
1617
|
+
let result = {
|
|
1547
1618
|
x1: Math.min(x1, x2),
|
|
1548
1619
|
y1: Math.min(y1, y2),
|
|
1549
1620
|
x2: Math.max(x1, x2),
|
|
1550
1621
|
y2: Math.max(y1, y2),
|
|
1551
1622
|
};
|
|
1623
|
+
const userCw = this.getUserClockwiseRotation(pageNumber);
|
|
1624
|
+
if (userCw !== 0) {
|
|
1625
|
+
const ccw = clockwiseToCcw(userCw);
|
|
1626
|
+
result = rotateBoundingBoxForCcwRotation(result, pageWidth, pageHeight, ccw);
|
|
1627
|
+
}
|
|
1628
|
+
return result;
|
|
1552
1629
|
}
|
|
1553
1630
|
/**
|
|
1554
1631
|
* Build spatial indices for displayed pages only
|
|
@@ -1683,9 +1760,12 @@ export class PDFHighlightViewer {
|
|
|
1683
1760
|
return;
|
|
1684
1761
|
}
|
|
1685
1762
|
try {
|
|
1686
|
-
// Get the PDF page and its viewport
|
|
1687
1763
|
const pdfPage = await this.pdfEngine.getPage(pageNumber);
|
|
1688
|
-
const
|
|
1764
|
+
const effectiveRotation = this.effectiveViewportRotationDegrees(pdfPage.rotate, pageNumber);
|
|
1765
|
+
const viewport = pdfPage.getViewport({
|
|
1766
|
+
scale: this.currentScale,
|
|
1767
|
+
rotation: effectiveRotation,
|
|
1768
|
+
});
|
|
1689
1769
|
// Extract text content from PDF
|
|
1690
1770
|
const textContent = await pdfPage.getTextContent();
|
|
1691
1771
|
// Create text layer container
|
|
@@ -1785,8 +1865,6 @@ export class PDFHighlightViewer {
|
|
|
1785
1865
|
textLayer.appendChild(textSpan);
|
|
1786
1866
|
});
|
|
1787
1867
|
pageContainer.appendChild(textLayer);
|
|
1788
|
-
console.log(`Text layer added to page ${pageNumber} with ${textContent.items.length} text items`);
|
|
1789
|
-
console.log('Text span style applied:', textLayer.children[0]?.getAttribute('style'));
|
|
1790
1868
|
}
|
|
1791
1869
|
catch (error) {
|
|
1792
1870
|
console.error(`Failed to add text layer to page ${pageNumber}:`, error);
|
|
@@ -1802,8 +1880,8 @@ export class PDFHighlightViewer {
|
|
|
1802
1880
|
const targetHeight = (coord.y2 - coord.y1) * scale;
|
|
1803
1881
|
const existingHighlights = highlightLayer.children;
|
|
1804
1882
|
let overlappingCount = 0;
|
|
1805
|
-
for (
|
|
1806
|
-
const existing =
|
|
1883
|
+
for (const existingHighlight of existingHighlights) {
|
|
1884
|
+
const existing = existingHighlight;
|
|
1807
1885
|
const existingLeft = parseFloat(existing.style.left);
|
|
1808
1886
|
const existingTop = parseFloat(existing.style.top);
|
|
1809
1887
|
const existingWidth = parseFloat(existing.style.width);
|
|
@@ -1888,6 +1966,9 @@ export class PDFHighlightViewer {
|
|
|
1888
1966
|
// Clear state
|
|
1889
1967
|
this.eventListeners = [];
|
|
1890
1968
|
this.isInitialized = false;
|
|
1969
|
+
this.pageDimensions.clear();
|
|
1970
|
+
this.intrinsicPageNormalized.clear();
|
|
1971
|
+
this.pageDisplayRotations.clear();
|
|
1891
1972
|
this.emit('destroyed');
|
|
1892
1973
|
}
|
|
1893
1974
|
}
|