From e76558fe1f0e324a3ec6626d04beb0a7831f8c70 Mon Sep 17 00:00:00 2001 From: PJ Date: Sat, 20 Jun 2026 12:42:04 -0400 Subject: [PATCH] feat(pdf): add pdf.js preview renderer --- src/components/PdfPreview.tsx | 46 +++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/components/PdfPreview.tsx diff --git a/src/components/PdfPreview.tsx b/src/components/PdfPreview.tsx new file mode 100644 index 0000000..a9d5fc2 --- /dev/null +++ b/src/components/PdfPreview.tsx @@ -0,0 +1,46 @@ +import { useEffect, useRef } from "react"; +import * as pdfjs from "pdfjs-dist"; +import workerUrl from "pdfjs-dist/build/pdf.worker.min.mjs?url"; + +pdfjs.GlobalWorkerOptions.workerSrc = workerUrl; + +export function PdfPreview({ data }: { data: Uint8Array }) { + const ref = useRef(null); + + useEffect(() => { + const container = ref.current; + if (!container) return; + let cancelled = false; + + (async () => { + const doc = await pdfjs.getDocument({ data: data.slice() }).promise; + if (cancelled) return; + const width = container.clientWidth; + const dpr = window.devicePixelRatio || 1; + const canvases: HTMLCanvasElement[] = []; + + for (let n = 1; n <= doc.numPages; n++) { + const page = await doc.getPage(n); + if (cancelled) return; + const base = page.getViewport({ scale: 1 }); + const scale = width / base.width; + const viewport = page.getViewport({ scale: scale * dpr }); + const canvas = document.createElement("canvas"); + canvas.className = "pdf-page"; + canvas.width = viewport.width; + canvas.height = viewport.height; + canvas.style.width = "100%"; + await page.render({ canvasContext: canvas.getContext("2d")!, viewport }).promise; + if (cancelled) return; + canvases.push(canvas); + } + container.replaceChildren(...canvases); + })(); + + return () => { + cancelled = true; + }; + }, [data]); + + return
; +}