Interactive PNG & JPEG Stitching

Experiment with modern browser helpers, progress callbacks, and canvas-aware workflows powered by image-stitch. Each demo shows the exact code you can drop into your own app—now with both PNG (lossless) and JPEG (lossy) outputs.

Pick your output format

Choose between lossless PNG or lossy JPEG for every interactive example. JPEGs support adjustable quality to balance fidelity and file size.

Horizontal sprite strip

Combine three pngsuite samples into a single row. Useful for spritesheets and UI icon strips.

import { concatToBuffer } from "image-stitch"; const names = ["basi0g08.png", "basi2c08.png", "basi4a16.png"]; const buffers = await Promise.all( names.map((name) => fetch(`images/${name}`).then((res) => res.arrayBuffer())) ); const output = await concatToBuffer({ inputs: buffers, layout: { columns: 3 } });

Result

Horizontal stitched output

Vertical film strip

Let image-stitch handle varying heights automatically. Smaller inputs are padded with transparent pixels.

import { concatToBuffer } from "image-stitch"; const names = ["basi2c08.png", "basi0g08.png"]; const buffers = await Promise.all( names.map((name) => fetch(`images/${name}`).then((res) => res.arrayBuffer())) ); const output = await concatToBuffer({ inputs: buffers, layout: { rows: 2 } });

Result

Vertical stitched output

Auto-wrapping grid with progress

Limit the maximum width to wrap rows automatically. The onProgress callback fires after each tile finishes decoding so you can power loading indicators.

import { concatToBuffer } from "image-stitch"; const output = await concatToBuffer({ inputs: imageBuffers, layout: { width: 256 }, onProgress(current, total) { console.log(`Decoded ${current} of ${total} tiles`); } });

Result

Grid stitched output

Canvas collage helper

Use concatCanvases to stitch existing <canvas> elements directly. Choose a Blob for downloads or render into another canvas for on-screen previews.

import { concatCanvases } from "image-stitch/browser"; const stitched = await concatCanvases({ canvases, layout: { rows: 2, columns: 2 }, output: "canvas", onProgress(current, total) { console.log(`Rendered ${current}/${total}`); } });

Result

Bring your own images & blobs

Drop in up to eight PNG or JPEG files (16-bit PNG color is supported!) and stitch them in your browser. Files are handled as Blob inputs—no need to convert to ArrayBuffers manually.

import { concatToBuffer } from "image-stitch"; const files = Array.from(fileInput.files ?? []); const output = await concatToBuffer({ inputs: files, layout: { columns: 4, wrapBehavior: "wrap" } });

Result

Custom stitched output

Streaming output in Node.js

Need a back-end friendly flow? Use concatToStream to pipe stitched PNG or JPEG data straight into HTTP responses or file writers without buffering everything in memory.

import { concatToStream } from "image-stitch"; import { createWriteStream } from "node:fs"; import { pipeline } from "node:stream/promises"; await pipeline( concatToStream({ inputs: spriteParts, layout: { columns: 4 }, onProgress(current, total) { console.info(`Completed ${current}/${total} tiles`); } }), createWriteStream("spritesheet.png") );

The async generator variant concatStreaming(options) works in any runtime that understands for await...of.