@embedpdf/engines
@embedpdf/engines
provides high-level, promise-first PDF rendering engines built on top of low-level WASM modules like @embedpdf/pdfium
. It offers pluggable engines that work seamlessly across browsers, Node.js, and serverless environments with full TypeScript support.
Key Features
- High-level abstraction – handles tasks, DPR scaling, annotation color resolution, range/linearized loading
- Universal runtimes – works in browsers, Node.js, and serverless environments
- Typed & composable – 100% TypeScript with generics for custom image pipelines
- Worker-optimized – built-in web worker support for non-blocking PDF processing
Installation
npm i @embedpdf/engines @embedpdf/pdfium
Usage Patterns
There are three main ways to use @embedpdf/engines
depending on your environment and performance requirements:
1. Web Worker (Recommended for Browsers)
Using a web worker is the recommended approach for browser environments as it:
- Keeps PDF processing off the main thread
- Prevents UI blocking during intensive operations
- Allows for better resource management
- Enables concurrent processing
Setting up the Worker
First, create a web worker file:
webworker.ts
import { PdfiumEngineRunner } from '@embedpdf/engines';
async function init() {
const response = await fetch(
'https://cdn.jsdelivr.net/npm/@embedpdf/pdfium/dist/pdfium.wasm'
);
const wasmBinary = await response.arrayBuffer();
const runner = new PdfiumEngineRunner(wasmBinary);
runner.prepare();
}
init();
Using the Worker Engine
main.ts
import { WebWorkerEngine } from '@embedpdf/engines/worker';
// Create worker and engine
const worker = new Worker(new URL('./webworker.ts', import.meta.url), {
type: 'module'
});
const engine = new WebWorkerEngine(worker);
// Wait for initialization
await engine.initialize().toPromise();
// Use the engine
const document = await engine
.openDocumentUrl({ id: 'demo', url: '/demo.pdf' })
.toPromise();
const blob = await engine
.renderPage(document, document.pages[0])
.toPromise();
2. Direct Engine (Browser Main Thread)
For simpler use cases or when worker setup is not feasible:
import { init } from '@embedpdf/pdfium';
import { PdfiumEngine } from '@embedpdf/engines/pdfium';
const response = await fetch(
'https://cdn.jsdelivr.net/npm/@embedpdf/pdfium/dist/pdfium.wasm'
);
const wasmBinary = await response.arrayBuffer();
// Initialize PDFium
const pdfium = await init({ wasmBinary });
// Create engine
const engine = new PdfiumEngine(pdfium);
engine.initialize();
// Use the engine
const document = await engine
.openDocumentUrl({ id: 'demo', url: '/demo.pdf' })
.toPromise();
const blob = await engine
.renderPage(document, document.pages[0])
.toPromise();
3. Node.js Environment
Node.js usage requires image converters since browser APIs like OffscreenCanvas
aren’t available:
import { readFile } from 'fs/promises';
import sharp from 'sharp';
import { init } from '@embedpdf/pdfium';
import { PdfiumEngine } from '@embedpdf/engines/pdfium';
import { createNodeImageDataToBufferConverter } from '@embedpdf/engines/converters';
import { ConsoleLogger } from '@embedpdf/models';
async function processPDF() {
const logger = new ConsoleLogger();
// Create image converter using Sharp
const imageConverter = createNodeImageDataToBufferConverter(sharp, 'image/webp');
// Initialize PDFium
const pdfiumInstance = await init();
const engine = new PdfiumEngine(pdfiumInstance, logger, imageConverter);
engine.initialize();
// Load and process PDF
const pdfBuffer = await readFile('document.pdf');
const document = await engine
.openDocumentFromBuffer({
id: 'sample',
content: pdfBuffer,
})
.toPromise();
// Render page - returns Buffer instead of Blob
const imageBuffer = await engine
.renderPage(document, document.pages[0])
.toPromise();
await writeFile('output.webp', imageBuffer);
await engine.closeDocument(document).toPromise();
}
Why Use Web Workers?
Web workers provide significant advantages for PDF processing:
- Non-blocking UI - PDF rendering happens off the main thread
- Better performance - Dedicated thread for intensive WASM operations
- Memory isolation - WASM memory is contained within the worker
- Error isolation - Worker crashes don’t affect the main application
Last updated on June 20, 2025