Skip to content

Advanced Rendering

Beyond basic full-page rendering, @scaryterry/pdfium offers advanced controls for high-performance applications, such as map viewers, design tools, or large-format document viewers.

For large pages (e.g., engineering drawings) or when implementing zooming interfaces (like Google Maps), you often only need to render the visible portion of a page. Rendering the entire page at high zoom levels would consume excessive memory.

Use clipRect to render only a specific region of the page into your output bitmap.

using page = document.getPage(0);
// Define the visible viewport on the page (in PDF points)
const viewport = {
left: 100,
top: 100,
right: 300,
bottom: 300
};
// Render just that region into a 200x200 bitmap
const { data, width, height } = page.render({
scale: 1, // Scale relative to the page coordinates
width: 200,
height: 200,
clipRect: viewport
});
console.log(`Rendered region: ${width}x${height}`);
  • PDF Coordinates: Origin is usually bottom-left. clipRect uses these coordinates.
  • Device Coordinates: Origin is top-left of the bitmap.

When using clipRect, PDFium calculates the transformation matrix to map the specified clipRect from page space to the full bounds of the output bitmap.

Rendering complex PDF pages (especially those with large images or complex vector paths) can take time. Blocking the main thread without feedback is bad UX.

Use the onProgress callback to update your UI during the render process.

const { data } = page.render({
scale: 2,
onProgress: (progress) => {
// progress is a number between 0 and 1
console.log(`Rendering: ${Math.round(progress * 100)}%`);
updateProgressBar(progress);
}
});

Note: The callback is synchronous. If you need to yield to the event loop to keep the UI responsive in a single-threaded environment (like the browser main thread), consider running PDFium in a Worker (see the Worker Guide).

For extremely complex pages, even onProgress might not be enough if the render call blocks for too long between updates. PDFium supports Progressive Rendering, which allows you to pause and resume the rendering process.

import { ProgressiveRenderStatus } from '@scaryterry/pdfium';
// Start the render
using render = page.startProgressiveRender({ scale: 2 });
// Loop until done, yielding to the event loop
while (render.status === ProgressiveRenderStatus.ToBeContinued) {
// Perform a chunk of rendering
render.continue();
// Yield to let the browser paint/process events
await new Promise(resolve => setTimeout(resolve, 0));
}
if (render.status === ProgressiveRenderStatus.Done) {
// Get the final result
const { data, width, height } = render.getResult();
// ... display image ...
} else {
console.error('Render failed');
}

The ProgressiveRenderContext returned by startProgressiveRender() exposes:

Property / MethodTypeDescription
statusProgressiveRenderStatusCurrent state: ToBeContinued, Done, or Failed
widthnumberRendered width in pixels
heightnumberRendered height in pixels
continue()ProgressiveRenderStatusPerforms the next rendering chunk and returns the updated status
getResult()RenderResultReturns the final RGBA pixel data (only valid when status is Done)

The context implements Symbol.dispose, so use using for automatic cleanup.

onProgress callbackstartProgressiveRender()
ControlPDFium drives the loop — you receive callbacksYou drive the loop — call continue() at your pace
YieldingCannot yield between updatesCan yield (setTimeout, scheduler.yield()) between chunks
ComplexitySimple — one callback functionMore involved — manage a loop and context disposal
Use caseProgress bars, loggingKeeping UI responsive on the main thread

Use onProgress when you only need to report progress. Use startProgressiveRender() when you need to yield control between rendering chunks (e.g., to keep the browser responsive without a Worker).