diff --git a/src/pages/exam/setup/ExamTemplateSetupPage.tsx b/src/pages/exam/setup/ExamTemplateSetupPage.tsx index d92e680..21f9b82 100644 --- a/src/pages/exam/setup/ExamTemplateSetupPage.tsx +++ b/src/pages/exam/setup/ExamTemplateSetupPage.tsx @@ -159,7 +159,21 @@ const ExamTemplateSetupInner: React.FC = () => { setPdfError(null) try { const bytes = await examRepository.getTemplateSourcePdf(templateId) - pages = await loadPdfPageImages(bytes) + pages = await loadPdfPageImages(bytes, undefined, (partialPages) => { + const newPage = partialPages[partialPages.length - 1] + const allGeometries = pageGeometryFromImages(partialPages) + pageGeometriesRef.current = allGeometries + const ed = editorRef.current + if (ed) { + const geometry = allGeometries[partialPages.length - 1] + const shapeId = createShapeId(PDF_PAGE_IDS_PREFIX + newPage.pageNumber) + if (!ed.getCurrentPageShapes().find((s) => s.id === shapeId)) { + ed.createShapes([{ id: shapeId, type: PDF_PAGE_SHAPE_TYPE, x: geometry.x, y: geometry.y, isLocked: true, props: { w: geometry.w, h: geometry.h, src: newPage.src, pageNumber: newPage.pageNumber } } as any]) + try { ed.sendToBack([shapeId as any]) } catch { /* */ } + } + } + setPdfStatus('ready') + }) setPdfStatus(pages.length ? 'ready' : 'missing') } catch (pdfErr) { const pdfMsg = apiMessage(pdfErr).message diff --git a/src/pages/exam/setup/pdfLoader.ts b/src/pages/exam/setup/pdfLoader.ts index 3f7baa8..4e3bfae 100644 --- a/src/pages/exam/setup/pdfLoader.ts +++ b/src/pages/exam/setup/pdfLoader.ts @@ -12,20 +12,27 @@ export interface PdfPageImage { height: number } -export async function loadPdfPageImages(pdfBytes: ArrayBuffer, targetWidth = PAGE_WIDTH): Promise { +export async function loadPdfPageImages( + pdfBytes: ArrayBuffer, + targetWidth = PAGE_WIDTH, + onPageReady?: (pages: PdfPageImage[]) => void, +): Promise { const pdf = await pdfjsLib.getDocument({ data: new Uint8Array(pdfBytes) }).promise const pages: PdfPageImage[] = [] + // Reuse a single canvas across all pages to avoid allocating ~120 MB of canvas memory + // for a typical 36-page exam paper. + const canvas = document.createElement("canvas") for (let pageNumber = 1; pageNumber <= pdf.numPages; pageNumber += 1) { const page = await pdf.getPage(pageNumber) const baseViewport = page.getViewport({ scale: 1 }) const scale = targetWidth / baseViewport.width const viewport = page.getViewport({ scale }) - const canvas = document.createElement("canvas") canvas.width = Math.ceil(viewport.width) canvas.height = Math.ceil(viewport.height) const context = canvas.getContext("2d") if (!context) throw new Error("Unable to create PDF render canvas") + context.clearRect(0, 0, canvas.width, canvas.height) await page.render({ canvasContext: context, viewport }).promise pages.push({ pageNumber, @@ -33,6 +40,7 @@ export async function loadPdfPageImages(pdfBytes: ArrayBuffer, targetWidth = PAG width: canvas.width, height: canvas.height, }) + onPageReady?.([...pages]) } return pages