Tiled Rasterization for Large DOM Captures

tinchox62 pts0 comments

Tiled Rasterization for Large DOM Captures | SnapDOM

GitHub★ 8K

SnapDOM Blog<br>Tiled rasterization for large DOM captures<br>SnapDOM 2.24 can capture a document once, then rasterize it as a mosaic of small canvases. The important part is when the cut happens: before the browser decodes a single pixel.

Zumerlab · August 11, 2026

TL;DR<br>A very tall DOM capture can serialize to SVG just fine and still fail when the browser tries to decode that SVG into one enormous bitmap. SnapDOM's new toCanvas({ crop }) windows the SVG before image decode. Capture once, move that window across result.meta, and you can preserve the requested resolution while each tile fits the browser's raster limits—without ever allocating the full-page canvas. It solves the raster ceiling; it does not make cloning an enormous DOM free.

The screenshot was fine. The bitmap wasn't.

There are two very different sizes hiding inside a “full-page screenshot.” The first is the serialized capture: an SVG containing a styled DOM clone inside . The second is the bitmap a browser creates when that SVG is decoded for PNG, Canvas, JPEG or WebP.

The SVG can describe a page tens of thousands of pixels tall. The bitmap is where browsers push back. A common practical ceiling is 16,384 pixels on one side, with an area limit as well; the exact failure point varies by engine and machine. Go past it and img.decode() may reject with the remarkably unhelpful EncodingError: The source image cannot be decoded, or the canvas allocation may fail later.

SnapDOM already protects ordinary exports from that crash by downscaling oversized raster output. That is the right fallback when the caller asked for one image. It is the wrong trade when the pixels are the product: a deep-zoom viewer, a page renderer, a tiled upload or a print pipeline should not have to throw resolution away simply because one bitmap is the wrong container.

Cut the SVG, not the canvas

The obvious mosaic algorithm is also the broken one: render one giant canvas, then use drawImage() to cut it into smaller canvases. By the time the slicing loop starts, the browser has already had to decode and allocate the giant bitmap. The failure happens before the workaround gets a turn.

toCanvas({ crop }) moves the cut earlier. SnapDOM rewrites the serialized SVG's root width, height and viewBox to describe only the requested window, and then gives it to Image.decode(). The browser never sees a full-height raster source.

Capture once Clone, style and serialize one canonical SVG.

Move the window Rewrite the viewBox to one tile's coordinates.

Decode small Rasterize only that tile, consume it, repeat.

This work lives entirely in the exporter. The hot capture path still walks and clones the DOM once; asking for ten tiles does not repeat style collection, font embedding or image inlining ten times.

Try the mosaic

The report below is 640 × 2,400 CSS pixels. That is deliberately smaller than a browser limit so the demo stays polite, but it uses the same path as a 40,000-pixel document: one SVG capture, ten 320 × 480 crop windows, ten independent canvases. Scroll the source, then build the mosaic.

Annual revenue$18.4m ↑ 24.8%

Active teams12,840 ↑ 18.1%

Net retention117% ↑ 6.2 pts

Performance<br>Recurring revenue by quarter

Where growth came from<br>Four regions, four different jobs

North America Enterprise expansion made existing accounts the largest contributor to net new revenue.

Europe Localized onboarding shortened time-to-value across the mid-market segment.

Asia Pacific Partner-led launches opened three markets without adding a regional sales layer.

Latin America Self-serve adoption doubled after local currency pricing reached the checkout.

The year in four moves<br>Four releases that moved adoption

JAN 18New workspace model Teams could finally organize projects without duplicating permissions and billing.

APR 04Usage-based plans Smaller customers could start earlier and grow without a contract migration.

JUL 22Regional data storage European deployments moved from exception handling to the standard path.

NOV 09Partner API Implementation partners shipped repeatable integrations instead of one-off scripts.

Build 10-tile mosaic<br>One capture · no full-page canvas

The gaps, borders and responsive scaling make the tiles visible here. At their native 320 × 480 size with no decoration, the ten canvases reconstruct the source.

The whole implementation is a loop

crop uses SVG viewBox coordinates, so the reliable bounds come from the capture rather than from rereading the live element. This version hands each canvas to a callback immediately; a production exporter can encode, upload or write the tile before requesting the next one.

async function tileCapture(capture, options, consume) {<br>const {<br>tileWidth = 2048,<br>tileHeight = 2048,<br>scale = 1,<br>dpr = 1<br>} = options

const { contentX, contentY, w0, h0 } = capture.meta

for (let y = 0, row = 0; y {<br>const blob = await new Promise(resolve => canvas.toBlob(resolve,...

capture canvas browser snapdom decode bitmap

Related Articles