import * as pdfjs from "pdfjs-dist"; import pdfWorker from "pdfjs-dist/build/pdf.worker.min.mjs?url"; import { LIMITS, fileTooLargeMessage, tooManyPagesMessage } from "@shared/types"; pdfjs.GlobalWorkerOptions.workerSrc = pdfWorker; function canvasToJpeg(canvas: HTMLCanvasElement): Promise { return new Promise((resolve, reject) => { canvas.toBlob( (blob) => { if (!blob) reject(new Error("تبدیل تصویر ناموفق بود")); else resolve(blob); }, "image/jpeg", LIMITS.jpegQuality / 100, ); }); } export async function renderPdfToJpegs( file: File, onProgress?: (done: number, total: number) => void, ): Promise { if (file.size > LIMITS.maxFileBytes) { throw new Error(fileTooLargeMessage(file.size)); } const data = new Uint8Array(await file.arrayBuffer()); let pdf; try { pdf = await pdfjs.getDocument({ data }).promise; } catch (err) { const name = err && typeof err === "object" && "name" in err ? String((err as { name: string }).name) : ""; if (name === "PasswordException") { throw new Error("این PDF رمزگذاری شده است و قابل تبدیل نیست."); } if (name === "InvalidPDFException") { throw new Error("این فایل یک PDF معتبر نیست."); } throw err; } if (pdf.numPages < 1) { throw new Error("این PDF صفحه‌ای برای نمایش ندارد."); } if (pdf.numPages > LIMITS.maxPages) { throw new Error(tooManyPagesMessage(pdf.numPages)); } const pages: Blob[] = []; onProgress?.(0, pdf.numPages); for (let i = 1; i <= pdf.numPages; i++) { const page = await pdf.getPage(i); const base = page.getViewport({ scale: 1 }); const scale = Math.min(LIMITS.maxPageWidth / base.width, 2); const viewport = page.getViewport({ scale }); const canvas = document.createElement("canvas"); canvas.width = Math.floor(viewport.width); canvas.height = Math.floor(viewport.height); const ctx = canvas.getContext("2d"); if (!ctx) throw new Error("تبدیل تصویر ناموفق بود"); const renderTask = page.render({ canvasContext: ctx, canvas, viewport, } as Parameters[0]); await renderTask.promise; pages.push(await canvasToJpeg(canvas)); onProgress?.(i, pdf.numPages); } return pages; }