UNPKG

pdf-to-png-converter

Version:

Node.js utility to convert PDF file/buffer pages to PNG files/buffers. No build-time compilation required — pre-built native binaries included for all major platforms.

79 lines (78 loc) 3.65 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const node_worker_threads_1 = require("node:worker_threads"); const normalizePdfToPngOptions_js_1 = require("./normalizePdfToPngOptions.js"); const pageRenderer_js_1 = require("./pageRenderer.js"); const pdfjsLoader_js_1 = require("./pdfjsLoader.js"); /** * Worker-thread entry point for `renderInWorkerThreads` mode. * * Each worker loads its OWN copy of the PDF document (pdf.js documents are not transferable * across threads) and renders the pages the pool assigns to it, end-to-end: getPage → render → * PNG encode. Disk writes stay on the main thread so the SEC-001/002/003 path guards run in * exactly one place. Workers never exit on their own — the pool terminates them. * * Runs only as a compiled artifact (`out/pageRenderWorker.js`); see `resolveWorkerEntryPath` * in `src/workerPool.ts` for how the pool locates it. */ if (node_worker_threads_1.parentPort === null) { throw new Error('pageRenderWorker must be started as a worker thread.'); } const port = node_worker_threads_1.parentPort; const init = node_worker_threads_1.workerData; // Re-normalize inside the worker: pure, keeps NormalizedPdfToPngOptions the single validation // boundary on both sides of the thread hop, and reconstructs defaulted fields dropped from the // serializable subset. const normalizedOptions = (0, normalizePdfToPngOptions_js_1.normalizePdfToPngOptions)(init.documentOptions); let documentPromise; /** * Posts a response that carries a thrown value. Error instances structured-clone with * name/message/stack preserved; values that cannot be cloned (functions, exotic objects some * libraries throw) are downgraded to a plain Error so the response always gets through. */ function postErrorResponse(build, error) { try { port.postMessage(build(error)); } catch { port.postMessage(build(new Error(error instanceof Error ? error.message : String(error)))); } } async function handleRender(request) { let pdfDocument; try { // Loaded lazily once per worker; getPdfDocument transfers (detaches) this worker's // private copy of the buffer, which is fine — it is loaded exactly once. documentPromise ??= (0, pdfjsLoader_js_1.getPdfDocument)(init.pdfBuffer, normalizedOptions); pdfDocument = await documentPromise; } catch (error) { postErrorResponse((cause) => ({ type: 'fatal', error: cause }), error); return; } try { const page = await (0, pageRenderer_js_1.renderPdfPage)(pdfDocument, request.pageName, request.pageNumber, normalizedOptions.viewportScale, init.materializeContent); const response = { type: 'result', index: request.index, pageNumber: page.pageNumber, name: page.name, width: page.width, height: page.height, rotation: page.rotation, content: page.content, }; // The PNG bytes are structured-clone COPIED across the thread boundary, not // transferred: @napi-rs/canvas allocates encode() output as a napi-external // ArrayBuffer, which Node.js cannot transfer ("Cannot transfer object of // unsupported type"). One copy per page (typically well under 1 MB) is negligible // next to the render work this mode parallelizes. port.postMessage(response); } catch (error) { postErrorResponse((cause) => ({ type: 'render-error', index: request.index, error: cause }), error); } } port.on('message', (request) => { void handleRender(request); });