@anaralabs/lector 3.10.2 → 3.10.4
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/_tsup-dts-rollup.d.ts +9 -51
- package/dist/index.js +226 -285
- package/package.json +1 -1
|
@@ -124,12 +124,6 @@ declare interface AnnotationTooltipProps {
|
|
|
124
124
|
}) => React.ReactNode;
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
-
declare type CacheEntry = {
|
|
128
|
-
bitmap: ImageBitmap;
|
|
129
|
-
width: number;
|
|
130
|
-
height: number;
|
|
131
|
-
};
|
|
132
|
-
|
|
133
127
|
/**
|
|
134
128
|
* Calculates the highlight rectangles for a given text match.
|
|
135
129
|
*
|
|
@@ -192,6 +186,8 @@ export declare const ensureAnnotationLayerStyles: () => void;
|
|
|
192
186
|
|
|
193
187
|
export declare const firstMemo: <T>(first: boolean, memo: unknown, initializer: () => T) => T;
|
|
194
188
|
|
|
189
|
+
export declare const getDefaultPdfJsAssetUrls: (version: string) => PdfJsAssetUrls;
|
|
190
|
+
|
|
195
191
|
export declare const getEndOfHighlight: (selection: ColoredHighlight) => number;
|
|
196
192
|
|
|
197
193
|
export declare const getFitWidthZoom: (containerWidth: number, viewports: PageViewport[], zoomOptions: {
|
|
@@ -305,6 +301,13 @@ export declare const Pages: ({ children, gap, virtualizerOptions, initialOffset,
|
|
|
305
301
|
onOffsetChange?: (offset: number) => void;
|
|
306
302
|
}) => JSX.Element;
|
|
307
303
|
|
|
304
|
+
export declare interface PdfJsAssetUrls {
|
|
305
|
+
wasmUrl: string;
|
|
306
|
+
cMapUrl: string;
|
|
307
|
+
standardFontDataUrl: string;
|
|
308
|
+
iccUrl: string;
|
|
309
|
+
}
|
|
310
|
+
|
|
308
311
|
export declare const PDFLinkServiceContext: Context<LinkService>;
|
|
309
312
|
|
|
310
313
|
declare interface PDFState {
|
|
@@ -351,51 +354,6 @@ export declare type PDFVirtualizer = Virtualizer<any, any>;
|
|
|
351
354
|
|
|
352
355
|
export declare const PreviousPage: () => void;
|
|
353
356
|
|
|
354
|
-
/**
|
|
355
|
-
* LRU cache for rendered page bitmaps. When scrolling back to a previously
|
|
356
|
-
* rendered page at the same scale, we can draw from cache instantly instead
|
|
357
|
-
* of re-rendering through PDF.js.
|
|
358
|
-
*
|
|
359
|
-
* Cache keys include a document ID to prevent collisions when multiple
|
|
360
|
-
* <Root> instances render different PDFs on the same page.
|
|
361
|
-
*/
|
|
362
|
-
declare class RenderCache {
|
|
363
|
-
private cache;
|
|
364
|
-
private maxEntries;
|
|
365
|
-
private invalidatedDocs;
|
|
366
|
-
constructor(maxEntries?: number);
|
|
367
|
-
private key;
|
|
368
|
-
get(documentId: string, pageNumber: number, scale: number, background?: string): CacheEntry | undefined;
|
|
369
|
-
set(documentId: string, pageNumber: number, scale: number, canvas: HTMLCanvasElement, background?: string): Promise<void>;
|
|
370
|
-
/** Remove all cached entries for a specific document (call on Root unmount). */
|
|
371
|
-
invalidateDocument(documentId: string): void;
|
|
372
|
-
clear(): void;
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
export declare const renderCache: RenderCache;
|
|
376
|
-
|
|
377
|
-
/**
|
|
378
|
-
* Serializes PDF page render operations so only one runs at a time.
|
|
379
|
-
* This prevents multiple heavy pages from competing for CPU and blocking the UI.
|
|
380
|
-
*/
|
|
381
|
-
declare class RenderQueue {
|
|
382
|
-
private queue;
|
|
383
|
-
private running;
|
|
384
|
-
enqueue(execute: () => Promise<void>): {
|
|
385
|
-
promise: Promise<void>;
|
|
386
|
-
cancel: () => void;
|
|
387
|
-
};
|
|
388
|
-
private flush;
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
/**
|
|
392
|
-
* Global singleton — intentionally shared across all <Root> instances.
|
|
393
|
-
* Serializing renders across documents prevents overall GPU/CPU pressure
|
|
394
|
-
* on the main thread (CanvasGraphics is single-threaded). The trade-off
|
|
395
|
-
* is increased latency in multi-viewer setups.
|
|
396
|
-
*/
|
|
397
|
-
export declare const renderQueue: RenderQueue;
|
|
398
|
-
|
|
399
357
|
export declare const Root: ForwardRefExoticComponent<Omit<HTMLProps<HTMLDivElement> & usePDFDocumentParams & {
|
|
400
358
|
loader?: ReactNode;
|
|
401
359
|
}, "ref"> & RefAttributes<unknown>>;
|
package/dist/index.js
CHANGED
|
@@ -676,40 +676,6 @@ var ensureAnnotationLayerStyles = () => {
|
|
|
676
676
|
style.textContent = annotationLayerStyles;
|
|
677
677
|
document.head.appendChild(style);
|
|
678
678
|
};
|
|
679
|
-
|
|
680
|
-
// src/lib/cancellable.ts
|
|
681
|
-
var cancellable = (promise) => {
|
|
682
|
-
let isCancelled = false;
|
|
683
|
-
const wrappedPromise = new Promise((resolve, reject) => {
|
|
684
|
-
promise.then(
|
|
685
|
-
(value) => {
|
|
686
|
-
if (!isCancelled) {
|
|
687
|
-
resolve(value);
|
|
688
|
-
}
|
|
689
|
-
},
|
|
690
|
-
(error) => {
|
|
691
|
-
if (!isCancelled) {
|
|
692
|
-
reject(error);
|
|
693
|
-
}
|
|
694
|
-
}
|
|
695
|
-
);
|
|
696
|
-
});
|
|
697
|
-
return {
|
|
698
|
-
promise: wrappedPromise,
|
|
699
|
-
cancel() {
|
|
700
|
-
isCancelled = true;
|
|
701
|
-
}
|
|
702
|
-
};
|
|
703
|
-
};
|
|
704
|
-
|
|
705
|
-
// src/lib/pdfjs.ts
|
|
706
|
-
var pdfJsPromise = null;
|
|
707
|
-
var loadPdfJs = () => {
|
|
708
|
-
if (!pdfJsPromise) {
|
|
709
|
-
pdfJsPromise = import('pdfjs-dist/legacy/build/pdf.mjs');
|
|
710
|
-
}
|
|
711
|
-
return pdfJsPromise;
|
|
712
|
-
};
|
|
713
679
|
var usePdfJump = () => {
|
|
714
680
|
const virtualizer = usePdf((state) => state.virtualizer);
|
|
715
681
|
const setHighlight = usePdf((state) => state.setHighlight);
|
|
@@ -1041,13 +1007,15 @@ var useAnnotationLayer = (params) => {
|
|
|
1041
1007
|
if (linkService._pdfDocumentProxy !== pdfDocumentProxy) {
|
|
1042
1008
|
linkService.setDocument(pdfDocumentProxy);
|
|
1043
1009
|
}
|
|
1044
|
-
annotationLayerRef.current
|
|
1045
|
-
|
|
1010
|
+
const container = annotationLayerRef.current;
|
|
1011
|
+
let cancelled = false;
|
|
1012
|
+
container.replaceChildren();
|
|
1013
|
+
container.className = "annotationLayer";
|
|
1046
1014
|
const viewport = pdfPageProxy.getViewport({ scale: 1 }).clone({
|
|
1047
1015
|
dontFlip: true
|
|
1048
1016
|
});
|
|
1049
1017
|
const annotationLayerConfig = {
|
|
1050
|
-
div:
|
|
1018
|
+
div: container,
|
|
1051
1019
|
viewport,
|
|
1052
1020
|
page: pdfPageProxy,
|
|
1053
1021
|
linkService,
|
|
@@ -1058,25 +1026,26 @@ var useAnnotationLayer = (params) => {
|
|
|
1058
1026
|
structTreeLayer: void 0,
|
|
1059
1027
|
commentManager: void 0
|
|
1060
1028
|
};
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
}
|
|
1076
|
-
}
|
|
1077
|
-
|
|
1029
|
+
(async () => {
|
|
1030
|
+
try {
|
|
1031
|
+
if (cancelled) return;
|
|
1032
|
+
const { AnnotationLayer: AnnotationLayer2 } = await import('pdfjs-dist/legacy/build/pdf.mjs');
|
|
1033
|
+
if (cancelled) return;
|
|
1034
|
+
const annotationLayer = new AnnotationLayer2(annotationLayerConfig);
|
|
1035
|
+
annotationLayerObjectRef.current = annotationLayer;
|
|
1036
|
+
const annotations = await pdfPageProxy.getAnnotations();
|
|
1037
|
+
if (cancelled) return;
|
|
1038
|
+
await annotationLayer.render({
|
|
1039
|
+
...annotationLayerConfig,
|
|
1040
|
+
...mergedParams,
|
|
1041
|
+
annotations,
|
|
1042
|
+
linkService
|
|
1043
|
+
});
|
|
1044
|
+
} catch (_error) {
|
|
1045
|
+
}
|
|
1046
|
+
})();
|
|
1078
1047
|
return () => {
|
|
1079
|
-
|
|
1048
|
+
cancelled = true;
|
|
1080
1049
|
};
|
|
1081
1050
|
}, [pdfPageProxy, pdfDocumentProxy, mergedParams, linkService]);
|
|
1082
1051
|
return {
|
|
@@ -1135,125 +1104,6 @@ function clampScaleForPage(targetScale, pageWidth, pageHeight) {
|
|
|
1135
1104
|
);
|
|
1136
1105
|
return Math.max(safeScale, 0);
|
|
1137
1106
|
}
|
|
1138
|
-
|
|
1139
|
-
// src/lib/render-cache.ts
|
|
1140
|
-
var RenderCache = class {
|
|
1141
|
-
cache = /* @__PURE__ */ new Map();
|
|
1142
|
-
maxEntries;
|
|
1143
|
-
// Tracks invalidated documents so in-flight createImageBitmap calls
|
|
1144
|
-
// don't insert orphaned entries after invalidateDocument() runs.
|
|
1145
|
-
invalidatedDocs = /* @__PURE__ */ new Set();
|
|
1146
|
-
constructor(maxEntries = 60) {
|
|
1147
|
-
this.maxEntries = maxEntries;
|
|
1148
|
-
}
|
|
1149
|
-
key(documentId, pageNumber, scale, background) {
|
|
1150
|
-
return `${documentId}-${pageNumber}-${scale}-${background ?? "white"}`;
|
|
1151
|
-
}
|
|
1152
|
-
get(documentId, pageNumber, scale, background) {
|
|
1153
|
-
const k = this.key(documentId, pageNumber, scale, background);
|
|
1154
|
-
const entry = this.cache.get(k);
|
|
1155
|
-
if (!entry) return void 0;
|
|
1156
|
-
this.cache.delete(k);
|
|
1157
|
-
this.cache.set(k, entry);
|
|
1158
|
-
return entry;
|
|
1159
|
-
}
|
|
1160
|
-
async set(documentId, pageNumber, scale, canvas, background) {
|
|
1161
|
-
const k = this.key(documentId, pageNumber, scale, background);
|
|
1162
|
-
const w = canvas.width;
|
|
1163
|
-
const h = canvas.height;
|
|
1164
|
-
if (w === 0 || h === 0) return;
|
|
1165
|
-
while (this.cache.size >= this.maxEntries) {
|
|
1166
|
-
const oldest = this.cache.keys().next().value;
|
|
1167
|
-
if (oldest !== void 0) {
|
|
1168
|
-
const entry = this.cache.get(oldest);
|
|
1169
|
-
entry?.bitmap.close();
|
|
1170
|
-
this.cache.delete(oldest);
|
|
1171
|
-
}
|
|
1172
|
-
}
|
|
1173
|
-
try {
|
|
1174
|
-
const bitmap = await createImageBitmap(canvas);
|
|
1175
|
-
if (this.invalidatedDocs.has(documentId)) {
|
|
1176
|
-
bitmap.close();
|
|
1177
|
-
return;
|
|
1178
|
-
}
|
|
1179
|
-
this.cache.set(k, {
|
|
1180
|
-
bitmap,
|
|
1181
|
-
width: w,
|
|
1182
|
-
height: h
|
|
1183
|
-
});
|
|
1184
|
-
} catch {
|
|
1185
|
-
}
|
|
1186
|
-
}
|
|
1187
|
-
/** Remove all cached entries for a specific document (call on Root unmount). */
|
|
1188
|
-
invalidateDocument(documentId) {
|
|
1189
|
-
this.invalidatedDocs.add(documentId);
|
|
1190
|
-
for (const [k, entry] of this.cache) {
|
|
1191
|
-
if (k.startsWith(`${documentId}-`)) {
|
|
1192
|
-
entry.bitmap.close();
|
|
1193
|
-
this.cache.delete(k);
|
|
1194
|
-
}
|
|
1195
|
-
}
|
|
1196
|
-
setTimeout(() => {
|
|
1197
|
-
this.invalidatedDocs.delete(documentId);
|
|
1198
|
-
}, 1e3);
|
|
1199
|
-
}
|
|
1200
|
-
clear() {
|
|
1201
|
-
for (const entry of this.cache.values()) {
|
|
1202
|
-
entry.bitmap.close();
|
|
1203
|
-
}
|
|
1204
|
-
this.cache.clear();
|
|
1205
|
-
this.invalidatedDocs.clear();
|
|
1206
|
-
}
|
|
1207
|
-
};
|
|
1208
|
-
var renderCache = new RenderCache();
|
|
1209
|
-
|
|
1210
|
-
// src/lib/render-queue.ts
|
|
1211
|
-
var RenderQueue = class {
|
|
1212
|
-
queue = [];
|
|
1213
|
-
running = false;
|
|
1214
|
-
enqueue(execute) {
|
|
1215
|
-
let resolve;
|
|
1216
|
-
let reject;
|
|
1217
|
-
const promise = new Promise((res, rej) => {
|
|
1218
|
-
resolve = res;
|
|
1219
|
-
reject = rej;
|
|
1220
|
-
});
|
|
1221
|
-
const job = {
|
|
1222
|
-
execute,
|
|
1223
|
-
resolve,
|
|
1224
|
-
reject,
|
|
1225
|
-
cancelled: false
|
|
1226
|
-
};
|
|
1227
|
-
this.queue.push(job);
|
|
1228
|
-
this.flush();
|
|
1229
|
-
return {
|
|
1230
|
-
promise,
|
|
1231
|
-
cancel: () => {
|
|
1232
|
-
job.cancelled = true;
|
|
1233
|
-
job.resolve();
|
|
1234
|
-
}
|
|
1235
|
-
};
|
|
1236
|
-
}
|
|
1237
|
-
async flush() {
|
|
1238
|
-
if (this.running) return;
|
|
1239
|
-
this.running = true;
|
|
1240
|
-
while (this.queue.length > 0) {
|
|
1241
|
-
const job = this.queue.shift();
|
|
1242
|
-
if (job.cancelled) {
|
|
1243
|
-
job.resolve();
|
|
1244
|
-
continue;
|
|
1245
|
-
}
|
|
1246
|
-
try {
|
|
1247
|
-
await job.execute();
|
|
1248
|
-
job.resolve();
|
|
1249
|
-
} catch (error) {
|
|
1250
|
-
job.reject(error);
|
|
1251
|
-
}
|
|
1252
|
-
}
|
|
1253
|
-
this.running = false;
|
|
1254
|
-
}
|
|
1255
|
-
};
|
|
1256
|
-
var renderQueue = new RenderQueue();
|
|
1257
1107
|
var useDpr = () => {
|
|
1258
1108
|
const [dpr, setDPR] = useState(
|
|
1259
1109
|
typeof window === "undefined" ? 1 : Math.min(window.devicePixelRatio, 2)
|
|
@@ -1277,123 +1127,149 @@ var useDpr = () => {
|
|
|
1277
1127
|
};
|
|
1278
1128
|
|
|
1279
1129
|
// src/hooks/layers/useCanvasLayer.tsx
|
|
1130
|
+
var CACHE_MAX = 60;
|
|
1131
|
+
var cacheEntries = [];
|
|
1132
|
+
var canvasBitmapCache = /* @__PURE__ */ new WeakMap();
|
|
1133
|
+
function clearBitmapCache(documentId) {
|
|
1134
|
+
if (documentId === void 0) {
|
|
1135
|
+
for (const entry of cacheEntries) {
|
|
1136
|
+
entry.bitmap.close();
|
|
1137
|
+
canvasBitmapCache.get(entry.proxy)?.delete(entry.key);
|
|
1138
|
+
}
|
|
1139
|
+
cacheEntries.length = 0;
|
|
1140
|
+
return;
|
|
1141
|
+
}
|
|
1142
|
+
for (let i = cacheEntries.length - 1; i >= 0; i--) {
|
|
1143
|
+
const entry = cacheEntries[i];
|
|
1144
|
+
if (entry.docId !== documentId) continue;
|
|
1145
|
+
entry.bitmap.close();
|
|
1146
|
+
canvasBitmapCache.get(entry.proxy)?.delete(entry.key);
|
|
1147
|
+
cacheEntries.splice(i, 1);
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
function cacheKey(scale, background) {
|
|
1151
|
+
const bg = background ?? "white";
|
|
1152
|
+
let hash = Math.round(scale * 1e4);
|
|
1153
|
+
for (let i = 0; i < bg.length; i++) {
|
|
1154
|
+
hash = hash * 31 + bg.charCodeAt(i) | 0;
|
|
1155
|
+
}
|
|
1156
|
+
return hash;
|
|
1157
|
+
}
|
|
1158
|
+
function getCachedBitmap(proxy, scale, background) {
|
|
1159
|
+
const key = cacheKey(scale, background);
|
|
1160
|
+
const bitmap = canvasBitmapCache.get(proxy)?.get(key);
|
|
1161
|
+
if (!bitmap) return null;
|
|
1162
|
+
const idx = cacheEntries.findIndex((e) => e.proxy === proxy && e.key === key);
|
|
1163
|
+
if (idx !== -1 && idx !== cacheEntries.length - 1) {
|
|
1164
|
+
const [entry] = cacheEntries.splice(idx, 1);
|
|
1165
|
+
cacheEntries.push(entry);
|
|
1166
|
+
}
|
|
1167
|
+
return bitmap;
|
|
1168
|
+
}
|
|
1169
|
+
function setCachedBitmap(docId, proxy, scale, background, bitmap) {
|
|
1170
|
+
const key = cacheKey(scale, background);
|
|
1171
|
+
let map = canvasBitmapCache.get(proxy);
|
|
1172
|
+
if (!map) {
|
|
1173
|
+
map = /* @__PURE__ */ new Map();
|
|
1174
|
+
canvasBitmapCache.set(proxy, map);
|
|
1175
|
+
}
|
|
1176
|
+
const existing = map.get(key);
|
|
1177
|
+
if (existing && existing !== bitmap) {
|
|
1178
|
+
existing.close();
|
|
1179
|
+
const idx = cacheEntries.findIndex(
|
|
1180
|
+
(e) => e.proxy === proxy && e.key === key
|
|
1181
|
+
);
|
|
1182
|
+
if (idx !== -1) cacheEntries.splice(idx, 1);
|
|
1183
|
+
}
|
|
1184
|
+
map.set(key, bitmap);
|
|
1185
|
+
cacheEntries.push({ docId, proxy, key, bitmap });
|
|
1186
|
+
while (cacheEntries.length > CACHE_MAX) {
|
|
1187
|
+
const evicted = cacheEntries.shift();
|
|
1188
|
+
const evictedMap = canvasBitmapCache.get(evicted.proxy);
|
|
1189
|
+
if (evictedMap?.get(evicted.key) === evicted.bitmap) {
|
|
1190
|
+
evictedMap.delete(evicted.key);
|
|
1191
|
+
evicted.bitmap.close();
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1280
1195
|
var useCanvasLayer = ({ background }) => {
|
|
1281
1196
|
const canvasRef = useRef(null);
|
|
1282
1197
|
const pageNumber = usePDFPageNumber();
|
|
1283
1198
|
const dpr = useDpr();
|
|
1284
1199
|
const bouncyZoom = usePdf((state) => state.zoom);
|
|
1200
|
+
const docId = usePdf((state) => state.pdfDocumentProxy.fingerprints[0] ?? "");
|
|
1285
1201
|
const pdfPageProxy = usePdf((state) => state.getPdfPageProxy(pageNumber));
|
|
1286
1202
|
const markPageRendered = usePdf((state) => state.markPageRendered);
|
|
1287
1203
|
const unmarkPageRendered = usePdf((state) => state.unmarkPageRendered);
|
|
1288
|
-
const documentId = usePdf(
|
|
1289
|
-
(state) => state.pdfDocumentProxy.fingerprints[0] ?? "default"
|
|
1290
|
-
);
|
|
1291
1204
|
const [zoom] = useDebounce(bouncyZoom, 100);
|
|
1292
|
-
const lastRenderedScaleRef = useRef(0);
|
|
1293
|
-
const lastBackgroundRef = useRef(background);
|
|
1294
|
-
const lastPageProxyRef = useRef(pdfPageProxy);
|
|
1295
|
-
const pageDimsRef = useRef(null);
|
|
1296
|
-
if (!pageDimsRef.current || pageDimsRef.current.proxy !== pdfPageProxy) {
|
|
1297
|
-
const vp = pdfPageProxy.getViewport({ scale: 1 });
|
|
1298
|
-
pageDimsRef.current = {
|
|
1299
|
-
width: vp.width,
|
|
1300
|
-
height: vp.height,
|
|
1301
|
-
proxy: pdfPageProxy
|
|
1302
|
-
};
|
|
1303
|
-
}
|
|
1304
1205
|
useLayoutEffect(() => {
|
|
1305
|
-
if (!canvasRef.current)
|
|
1306
|
-
|
|
1307
|
-
}
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
lastBackgroundRef.current = background;
|
|
1311
|
-
lastRenderedScaleRef.current = 0;
|
|
1312
|
-
}
|
|
1313
|
-
const { width: pageWidth, height: pageHeight } = pageDimsRef.current;
|
|
1314
|
-
const bgColor = background ?? "white";
|
|
1206
|
+
if (!canvasRef.current) return;
|
|
1207
|
+
const baseCanvas = canvasRef.current;
|
|
1208
|
+
const baseViewport = pdfPageProxy.getViewport({ scale: 1 });
|
|
1209
|
+
const pageWidth = baseViewport.width;
|
|
1210
|
+
const pageHeight = baseViewport.height;
|
|
1315
1211
|
const targetBaseScale = dpr * Math.min(zoom, 1);
|
|
1316
1212
|
const baseScale = clampScaleForPage(targetBaseScale, pageWidth, pageHeight);
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
}
|
|
1333
|
-
lastRenderedScaleRef.current = baseScale;
|
|
1334
|
-
};
|
|
1335
|
-
const cached = renderCache.get(
|
|
1336
|
-
documentId,
|
|
1337
|
-
pageNumber,
|
|
1338
|
-
baseScale,
|
|
1339
|
-
background
|
|
1340
|
-
);
|
|
1213
|
+
baseCanvas.width = Math.floor(pageWidth * baseScale);
|
|
1214
|
+
baseCanvas.height = Math.floor(pageHeight * baseScale);
|
|
1215
|
+
baseCanvas.style.position = "absolute";
|
|
1216
|
+
baseCanvas.style.top = "0";
|
|
1217
|
+
baseCanvas.style.left = "0";
|
|
1218
|
+
baseCanvas.style.width = `${pageWidth}px`;
|
|
1219
|
+
baseCanvas.style.height = `${pageHeight}px`;
|
|
1220
|
+
baseCanvas.style.transform = "translate(0px, 0px)";
|
|
1221
|
+
baseCanvas.style.zIndex = "0";
|
|
1222
|
+
baseCanvas.style.pointerEvents = "none";
|
|
1223
|
+
baseCanvas.style.backgroundColor = background ?? "white";
|
|
1224
|
+
baseCanvas.style.visibility = "";
|
|
1225
|
+
const context = baseCanvas.getContext("2d");
|
|
1226
|
+
if (!context) return;
|
|
1227
|
+
const cached = getCachedBitmap(pdfPageProxy, baseScale, background);
|
|
1341
1228
|
if (cached) {
|
|
1342
|
-
|
|
1229
|
+
context.drawImage(cached, 0, 0);
|
|
1343
1230
|
markPageRendered(pageNumber);
|
|
1344
1231
|
return;
|
|
1345
1232
|
}
|
|
1233
|
+
context.setTransform(1, 0, 0, 1, 0, 0);
|
|
1234
|
+
context.clearRect(0, 0, baseCanvas.width, baseCanvas.height);
|
|
1235
|
+
baseCanvas.style.visibility = "hidden";
|
|
1346
1236
|
let cancelled = false;
|
|
1347
|
-
|
|
1348
|
-
const
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
const viewport = pdfPageProxy.getViewport({ scale: baseScale });
|
|
1363
|
-
const renderingTask = pdfPageProxy.render({
|
|
1364
|
-
canvas: buffer,
|
|
1365
|
-
canvasContext: bufferCtx,
|
|
1366
|
-
viewport,
|
|
1367
|
-
background
|
|
1368
|
-
});
|
|
1369
|
-
activeRenderingTask = renderingTask;
|
|
1370
|
-
renderingTask.promise.then(() => {
|
|
1371
|
-
activeRenderingTask = null;
|
|
1372
|
-
if (cancelled || !canvasRef.current) {
|
|
1373
|
-
resolve();
|
|
1374
|
-
return;
|
|
1375
|
-
}
|
|
1376
|
-
swapToCanvas(buffer, w, h);
|
|
1377
|
-
markPageRendered(pageNumber);
|
|
1378
|
-
renderCache.set(documentId, pageNumber, baseScale, buffer, background).finally(() => {
|
|
1379
|
-
buffer.width = 0;
|
|
1380
|
-
buffer.height = 0;
|
|
1381
|
-
});
|
|
1382
|
-
resolve();
|
|
1383
|
-
}).catch((error) => {
|
|
1384
|
-
activeRenderingTask = null;
|
|
1385
|
-
if (error.name === "RenderingCancelledException") {
|
|
1386
|
-
resolve();
|
|
1237
|
+
const viewport = pdfPageProxy.getViewport({ scale: baseScale });
|
|
1238
|
+
const renderingTask = pdfPageProxy.render({
|
|
1239
|
+
canvas: baseCanvas,
|
|
1240
|
+
canvasContext: context,
|
|
1241
|
+
viewport,
|
|
1242
|
+
background
|
|
1243
|
+
});
|
|
1244
|
+
renderingTask.promise.then(() => {
|
|
1245
|
+
if (cancelled) return;
|
|
1246
|
+
baseCanvas.style.visibility = "";
|
|
1247
|
+
markPageRendered(pageNumber);
|
|
1248
|
+
if (typeof createImageBitmap !== "undefined") {
|
|
1249
|
+
createImageBitmap(baseCanvas).then((bitmap) => {
|
|
1250
|
+
if (cancelled) {
|
|
1251
|
+
bitmap.close();
|
|
1387
1252
|
return;
|
|
1388
1253
|
}
|
|
1389
|
-
|
|
1254
|
+
setCachedBitmap(
|
|
1255
|
+
docId,
|
|
1256
|
+
pdfPageProxy,
|
|
1257
|
+
baseScale,
|
|
1258
|
+
background,
|
|
1259
|
+
bitmap
|
|
1260
|
+
);
|
|
1261
|
+
}).catch(() => {
|
|
1390
1262
|
});
|
|
1391
|
-
}
|
|
1263
|
+
}
|
|
1264
|
+
}).catch((error) => {
|
|
1265
|
+
if (cancelled) return;
|
|
1266
|
+
if (error?.name === "RenderingCancelledException") return;
|
|
1267
|
+
baseCanvas.style.visibility = "";
|
|
1268
|
+
console.error("PDF render error:", error);
|
|
1392
1269
|
});
|
|
1393
1270
|
return () => {
|
|
1394
1271
|
cancelled = true;
|
|
1395
|
-
|
|
1396
|
-
void activeRenderingTask?.cancel();
|
|
1272
|
+
void renderingTask.cancel();
|
|
1397
1273
|
};
|
|
1398
1274
|
}, [
|
|
1399
1275
|
pdfPageProxy,
|
|
@@ -1401,16 +1277,16 @@ var useCanvasLayer = ({ background }) => {
|
|
|
1401
1277
|
dpr,
|
|
1402
1278
|
zoom,
|
|
1403
1279
|
pageNumber,
|
|
1404
|
-
|
|
1405
|
-
|
|
1280
|
+
markPageRendered,
|
|
1281
|
+
docId
|
|
1406
1282
|
]);
|
|
1407
1283
|
useEffect(() => {
|
|
1408
1284
|
const canvas = canvasRef.current;
|
|
1409
1285
|
return () => {
|
|
1410
1286
|
unmarkPageRendered(pageNumber);
|
|
1411
1287
|
if (canvas) {
|
|
1412
|
-
canvas.width =
|
|
1413
|
-
canvas.height =
|
|
1288
|
+
canvas.width = 0;
|
|
1289
|
+
canvas.height = 0;
|
|
1414
1290
|
}
|
|
1415
1291
|
};
|
|
1416
1292
|
}, [pageNumber, unmarkPageRendered]);
|
|
@@ -2647,10 +2523,8 @@ var useTextLayer = () => {
|
|
|
2647
2523
|
textLayerRef.current.cancel();
|
|
2648
2524
|
textLayerRef.current = null;
|
|
2649
2525
|
}
|
|
2650
|
-
void
|
|
2651
|
-
if (isCancelled || textContainerRef.current !== textContainer)
|
|
2652
|
-
return;
|
|
2653
|
-
}
|
|
2526
|
+
void import('pdfjs-dist/legacy/build/pdf.mjs').then(({ TextLayer: TextLayer2 }) => {
|
|
2527
|
+
if (isCancelled || textContainerRef.current !== textContainer) return;
|
|
2654
2528
|
const textLayer = new TextLayer2({
|
|
2655
2529
|
textContentSource: pdfPageProxy.streamTextContent(),
|
|
2656
2530
|
container: textContainer,
|
|
@@ -2659,8 +2533,7 @@ var useTextLayer = () => {
|
|
|
2659
2533
|
textLayerRef.current = textLayer;
|
|
2660
2534
|
return textLayer.render();
|
|
2661
2535
|
}).then(() => {
|
|
2662
|
-
|
|
2663
|
-
if (!textLayer || isCancelled || textContainerRef.current !== textContainer) {
|
|
2536
|
+
if (isCancelled || textContainerRef.current !== textContainer) {
|
|
2664
2537
|
return;
|
|
2665
2538
|
}
|
|
2666
2539
|
const endOfContent = document.createElement("div");
|
|
@@ -2668,7 +2541,7 @@ var useTextLayer = () => {
|
|
|
2668
2541
|
textContainer.appendChild(endOfContent);
|
|
2669
2542
|
bindMouseEvents(textContainer, endOfContent);
|
|
2670
2543
|
}).catch((error) => {
|
|
2671
|
-
if (error.name !== "AbortException") {
|
|
2544
|
+
if (error instanceof Error && error.name !== "AbortException") {
|
|
2672
2545
|
console.error("TextLayer rendering error:", error);
|
|
2673
2546
|
}
|
|
2674
2547
|
}).finally(() => {
|
|
@@ -2715,6 +2588,33 @@ var TextLayer = memo(
|
|
|
2715
2588
|
}
|
|
2716
2589
|
);
|
|
2717
2590
|
TextLayer.displayName = "TextLayer";
|
|
2591
|
+
|
|
2592
|
+
// src/lib/cancellable.ts
|
|
2593
|
+
var cancellable = (promise) => {
|
|
2594
|
+
let isCancelled = false;
|
|
2595
|
+
const wrappedPromise = new Promise((resolve, reject) => {
|
|
2596
|
+
promise.then(
|
|
2597
|
+
(value) => {
|
|
2598
|
+
if (!isCancelled) {
|
|
2599
|
+
resolve(value);
|
|
2600
|
+
}
|
|
2601
|
+
},
|
|
2602
|
+
(error) => {
|
|
2603
|
+
if (!isCancelled) {
|
|
2604
|
+
reject(error);
|
|
2605
|
+
}
|
|
2606
|
+
}
|
|
2607
|
+
);
|
|
2608
|
+
});
|
|
2609
|
+
return {
|
|
2610
|
+
promise: wrappedPromise,
|
|
2611
|
+
cancel() {
|
|
2612
|
+
isCancelled = true;
|
|
2613
|
+
}
|
|
2614
|
+
};
|
|
2615
|
+
};
|
|
2616
|
+
|
|
2617
|
+
// src/hooks/usePdfOutline.tsx
|
|
2718
2618
|
var usePDFOutline = () => {
|
|
2719
2619
|
const pdfDocumentProxy = usePdf((state) => state.pdfDocumentProxy);
|
|
2720
2620
|
const [outline, setOutline] = useState();
|
|
@@ -5337,7 +5237,28 @@ var Pages = ({
|
|
|
5337
5237
|
}
|
|
5338
5238
|
);
|
|
5339
5239
|
};
|
|
5340
|
-
|
|
5240
|
+
|
|
5241
|
+
// src/lib/pdfjs.ts
|
|
5242
|
+
var pdfJsPromise = null;
|
|
5243
|
+
var loadPdfJs = () => {
|
|
5244
|
+
if (!pdfJsPromise) {
|
|
5245
|
+
pdfJsPromise = import('pdfjs-dist/legacy/build/pdf.mjs');
|
|
5246
|
+
}
|
|
5247
|
+
return pdfJsPromise;
|
|
5248
|
+
};
|
|
5249
|
+
var ASSET_CDN_BASE = "https://cdn.jsdelivr.net/npm/pdfjs-dist";
|
|
5250
|
+
var getDefaultPdfJsAssetUrls = (version) => {
|
|
5251
|
+
const base = `${ASSET_CDN_BASE}@${version}`;
|
|
5252
|
+
return {
|
|
5253
|
+
wasmUrl: `${base}/wasm/`,
|
|
5254
|
+
cMapUrl: `${base}/cmaps/`,
|
|
5255
|
+
standardFontDataUrl: `${base}/standard_fonts/`,
|
|
5256
|
+
iccUrl: `${base}/iccs/`
|
|
5257
|
+
};
|
|
5258
|
+
};
|
|
5259
|
+
|
|
5260
|
+
// src/hooks/document/document.ts
|
|
5261
|
+
function buildDocumentInitParams(source, pdfJsVersion, overrides) {
|
|
5341
5262
|
let params;
|
|
5342
5263
|
if (typeof source === "string" || source instanceof URL) {
|
|
5343
5264
|
params = { url: source };
|
|
@@ -5346,6 +5267,7 @@ function buildDocumentInitParams(source, overrides) {
|
|
|
5346
5267
|
} else {
|
|
5347
5268
|
params = { ...source };
|
|
5348
5269
|
}
|
|
5270
|
+
const assetUrls = getDefaultPdfJsAssetUrls(pdfJsVersion);
|
|
5349
5271
|
const defaults = {
|
|
5350
5272
|
// Skip the slow _guessMax binary-search auto-detection of max canvas area.
|
|
5351
5273
|
// 1 GiB = 256 megapixels at 4 bytes/pixel. If the device can't allocate
|
|
@@ -5357,7 +5279,22 @@ function buildDocumentInitParams(source, overrides) {
|
|
|
5357
5279
|
enableHWA: true,
|
|
5358
5280
|
// Explicitly opt-in to OffscreenCanvas in the worker for image processing.
|
|
5359
5281
|
// Already the browser default, but being explicit avoids edge cases.
|
|
5360
|
-
isOffscreenCanvasSupported: true
|
|
5282
|
+
isOffscreenCanvasSupported: true,
|
|
5283
|
+
// PDF.js 5.x split out auxiliary resources that are loaded on demand.
|
|
5284
|
+
// Without these URLs, several content types render as blank pages
|
|
5285
|
+
// because pdf.js silently fails to load decoders / fonts / colour
|
|
5286
|
+
// profiles. The most visible symptom: scanned PDFs with JPEG2000 or
|
|
5287
|
+
// JBIG2 images (Internet Archive, government archives) render as
|
|
5288
|
+
// completely blank pages — every image fails with
|
|
5289
|
+
// "OpenJPEG failed to initialize". Defaulting these to a versioned
|
|
5290
|
+
// jsDelivr URL gets the viewer working out of the box; production
|
|
5291
|
+
// deployments should self-host and pass overrides via
|
|
5292
|
+
// `documentOptions`.
|
|
5293
|
+
wasmUrl: assetUrls.wasmUrl,
|
|
5294
|
+
cMapUrl: assetUrls.cMapUrl,
|
|
5295
|
+
cMapPacked: true,
|
|
5296
|
+
standardFontDataUrl: assetUrls.standardFontDataUrl,
|
|
5297
|
+
iccUrl: assetUrls.iccUrl
|
|
5361
5298
|
};
|
|
5362
5299
|
return { ...defaults, ...params, ...overrides };
|
|
5363
5300
|
}
|
|
@@ -5410,12 +5347,16 @@ var usePDFDocumentContext = ({
|
|
|
5410
5347
|
setProgress(0);
|
|
5411
5348
|
let loadingTask = null;
|
|
5412
5349
|
let isDisposed = false;
|
|
5413
|
-
void loadPdfJs().then(({ getDocument }) => {
|
|
5350
|
+
void loadPdfJs().then(({ getDocument, version }) => {
|
|
5414
5351
|
if (isDisposed) {
|
|
5415
5352
|
return;
|
|
5416
5353
|
}
|
|
5417
5354
|
loadingTask = getDocument(
|
|
5418
|
-
buildDocumentInitParams(
|
|
5355
|
+
buildDocumentInitParams(
|
|
5356
|
+
source,
|
|
5357
|
+
version,
|
|
5358
|
+
documentOptionsRef.current
|
|
5359
|
+
)
|
|
5419
5360
|
);
|
|
5420
5361
|
loadingTask.onProgress = (progressEvent) => {
|
|
5421
5362
|
if (progressEvent.loaded === progressEvent.total) {
|
|
@@ -5476,11 +5417,11 @@ var Root = forwardRef(
|
|
|
5476
5417
|
const linkService = useCreatePDFLinkService(
|
|
5477
5418
|
initialState?.pdfDocumentProxy ?? null
|
|
5478
5419
|
);
|
|
5479
|
-
const documentId = initialState?.pdfDocumentProxy
|
|
5420
|
+
const documentId = initialState?.pdfDocumentProxy?.fingerprints?.[0];
|
|
5480
5421
|
useEffect(() => {
|
|
5481
5422
|
if (!documentId) return;
|
|
5482
5423
|
return () => {
|
|
5483
|
-
|
|
5424
|
+
clearBitmapCache(documentId);
|
|
5484
5425
|
};
|
|
5485
5426
|
}, [documentId]);
|
|
5486
5427
|
return /* @__PURE__ */ jsx(Primitive.div, { ref, ...props, children: initialState ? /* @__PURE__ */ jsx(PDFStore.Provider, { initialValue: initialState, children: /* @__PURE__ */ jsx(PDFLinkServiceContext.Provider, { value: linkService, children }) }) : loader ?? "Loading..." });
|