import { flattenPages, type CanvasLike, type FlattenResult, type PdfDocLike } from "../pdf/flatten"; /** Lets the browser paint and handle input; falls back to a timer when rAF is paused (hidden window). */ export const yieldToBrowser = (): Promise => new Promise((resolve) => { let done = false; const finish = () => { if (!done) { done = true; resolve(); } }; setTimeout(finish, 50); requestAnimationFrame(() => setTimeout(finish, 0)); }); /** JPEG bytes of a canvas via the browser's encoder. */ export function encodeCanvasJpeg(canvas: CanvasLike, quality: number): Promise { return new Promise((resolve, reject) => { (canvas as unknown as HTMLCanvasElement).toBlob( (blob) => { if (!blob) return reject(new Error("the browser could not encode the page image (out of memory?)")); blob.arrayBuffer().then((buf) => resolve(new Uint8Array(buf)), reject); }, "image/jpeg", quality, ); }); } export interface BrowserFlattenOptions { signal?: AbortSignal; onProgress?: (page: number, pages: number) => void; } /** Flattens PDF bytes at 300 DPI with pdf.js and a DOM canvas; opens and closes the document itself. */ export async function flattenInBrowser(bytes: Uint8Array, opts: BrowserFlattenOptions = {}): Promise { const { openPdf, closePdf } = await import("./pdfjs"); const doc = await openPdf(bytes); try { return await flattenPages({ pdf: doc as unknown as PdfDocLike, createCanvas: (width, height) => { const canvas = document.createElement("canvas"); canvas.width = width; canvas.height = height; return canvas as unknown as CanvasLike; }, encodeJpeg: encodeCanvasJpeg, yieldToUi: yieldToBrowser, signal: opts.signal, onProgress: opts.onProgress, }); } finally { await closePdf(doc).catch(() => {}); } }