/** * PDF.js worker for processing PDFs in the browser * This file runs in a Web Worker context */ // Import types for worker context import type { IWorkerMessage, IPdfProcessRequest, IPdfProcessResponse, TWorkerMessageType } from './interfaces.js'; import { PreviewError } from './interfaces.js'; // PDF.js library (loaded from CDN or bundled) declare const pdfjsLib: any; /** * Worker context interface */ declare const self: any; /** * PDF.js configuration */ const PDFJS_CDN_URL = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js'; const WORKER_CDN_URL = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js'; /** * Worker state */ let isInitialized = false; let pdfjsWorker: any = null; /** * Initialize PDF.js in worker context */ async function initializePdfJs(): Promise { if (isInitialized) { return; } try { // Load PDF.js library self.importScripts(PDFJS_CDN_URL); if (typeof pdfjsLib === 'undefined') { throw new Error('Failed to load PDF.js library'); } // Configure PDF.js worker pdfjsLib.GlobalWorkerOptions.workerSrc = WORKER_CDN_URL; isInitialized = true; postMessage({ type: 'WORKER_READY', id: 'init', data: { version: pdfjsLib.version } } as IWorkerMessage); } catch (error) { postMessage({ type: 'PROCESS_ERROR', id: 'init', error: `Failed to initialize PDF.js: ${error instanceof Error ? error.message : String(error)}` } as IWorkerMessage); } } /** * Process PDF and generate JPEG preview */ async function processPdf(requestId: string, request: IPdfProcessRequest): Promise { if (!isInitialized) { postMessage({ type: 'PROCESS_ERROR', id: requestId, error: 'Worker not initialized' } as IWorkerMessage); return; } try { // Load PDF document const loadingTask = pdfjsLib.getDocument({ data: request.pdfData, cMapUrl: 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/cmaps/', cMapPacked: true, }); const pdf = await loadingTask.promise; // Validate page number if (request.options.page > pdf.numPages || request.options.page < 1) { throw new Error(`Page ${request.options.page} not found. Document has ${pdf.numPages} pages.`); } // Get the specified page const page = await pdf.getPage(request.options.page); // Calculate viewport const viewport = page.getViewport({ scale: request.options.scale }); // Adjust viewport to fit within max dimensions let { width, height } = viewport; if (request.options.width && width > request.options.width) { const scale = request.options.width / width; width = request.options.width; height = height * scale; } if (request.options.height && height > request.options.height) { const scale = request.options.height / height; height = request.options.height; width = width * scale; } const scaledViewport = page.getViewport({ scale: Math.min(width / viewport.width, height / viewport.height) * request.options.scale }); // Create canvas and render page const canvas = new OffscreenCanvas(scaledViewport.width, scaledViewport.height); const context = canvas.getContext('2d'); if (!context) { throw new Error('Failed to get 2D rendering context'); } const renderContext = { canvasContext: context, viewport: scaledViewport, }; await page.render(renderContext).promise; // Convert to JPEG const blob = await canvas.convertToBlob({ type: 'image/jpeg', quality: request.options.quality / 100, }); // Convert blob to ArrayBuffer const arrayBuffer = await blob.arrayBuffer(); // Send response const response: IPdfProcessResponse = { imageData: arrayBuffer, width: scaledViewport.width, height: scaledViewport.height, }; postMessage({ type: 'PROCESS_COMPLETE', id: requestId, data: response } as IWorkerMessage); } catch (error) { postMessage({ type: 'PROCESS_ERROR', id: requestId, error: error instanceof Error ? error.message : String(error) } as IWorkerMessage); } } /** * Handle worker messages */ self.addEventListener('message', async (event: MessageEvent) => { const { type, id, data } = event.data; switch (type) { case 'INIT': await initializePdfJs(); break; case 'PROCESS_PDF': await processPdf(id, data as IPdfProcessRequest); break; default: postMessage({ type: 'PROCESS_ERROR', id: id || 'unknown', error: `Unknown message type: ${type}` } as IWorkerMessage); } }); // Auto-initialize when worker starts initializePdfJs();