import { getDocument, GlobalWorkerOptions, type PDFDocumentProxy, type PDFPageProxy, type RenderTask } from "pdfjs-dist"; import { installStreamAsyncIterator } from "./streamPolyfill"; GlobalWorkerOptions.workerSrc = new URL("pdfjs-dist/build/pdf.worker.min.mjs", import.meta.url).toString(); installStreamAsyncIterator(); export type { PDFDocumentProxy, PDFPageProxy }; /** * Opens PDF bytes. The bytes are copied because pdf.js transfers the buffer to its worker, which * would detach the caller's array. Glyphs are drawn as paths (`disableFontFace`) so the preview looks * the same on WebKitGTK and WebView2. (pdf.js 6 dropped `isEvalSupported`; it no longer evaluates font code.) */ export function openPdf(bytes: Uint8Array): Promise { return getDocument({ data: bytes.slice(), disableFontFace: true }).promise; } /** Releases the document and its worker resources. */ export function closePdf(doc: PDFDocumentProxy): Promise { return doc.loadingTask.destroy(); } const tasks = new WeakMap(); /** Cancels whatever render is running for `slot` (a canvas, or any object the caller keys on). */ export function cancelPageRender(slot: object): void { tasks.get(slot)?.cancel(); tasks.delete(slot); } /** * Draws `page` into `canvas` at `scale` device pixels per PDF point, sizing the backing store to * match. Starting a render for a slot cancels its previous one; a cancelled render rejects with * pdf.js's RenderingCancelledException (see isRenderCancelled). */ export async function renderPageToCanvas(page: PDFPageProxy, canvas: HTMLCanvasElement, scale: number, slot: object = canvas): Promise { cancelPageRender(slot); const viewport = page.getViewport({ scale }); canvas.width = Math.ceil(viewport.width); canvas.height = Math.ceil(viewport.height); const task = page.render({ canvas, viewport }); tasks.set(slot, task); try { await task.promise; } finally { if (tasks.get(slot) === task) tasks.delete(slot); } } export const isRenderCancelled = (err: unknown): boolean => (err as { name?: string } | null)?.name === "RenderingCancelledException";