JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 10
  • Score
    100M100P100Q78906F
  • License MIT

High-performance image resize for browsers and Node.js. Rust/WASM accelerated, zero dependencies, pure JS fallback.

Package Exports

  • quickpix
  • quickpix/decode
  • quickpix/easy
  • quickpix/encode
  • quickpix/fallback
  • quickpix/metadata
  • quickpix/pipeline-worker
  • quickpix/pipeline-worker.js
  • quickpix/resize-worker
  • quickpix/resize-worker.js
  • quickpix/utils

Readme

quickpix

npm version npm bundle size zero dependencies license

한국어

High-performance image resize for browsers and Node.js. Rust/WASM accelerated with pure JS fallback. Zero dependencies.

npm install quickpix

Quick Start — High-Level API (QuickPixEasy)

For most use cases, QuickPixEasy is all you need. Blob/File in → resize → Blob out, in a single call.

import { QuickPixEasy } from "quickpix";

const qp = new QuickPixEasy({
  filter: "lanczos",           // resize filter (default: bilinear)
  outputMimeType: "image/jpeg",
  outputQuality: 0.85,
  preserveMetadata: true,      // preserve EXIF/ICC/IPTC metadata
  autoRotate: true,            // auto-correct EXIF orientation (default: true)
});

Resize Blob/File

const input = document.querySelector('input[type="file"]');
const file = input.files[0];

// Exact dimensions
const resized = await qp.resizeBlob(file, 1200, 800);

// Width only — height auto-calculated (aspect ratio preserved)
const resized2 = await qp.resizeBlob(file, 1200, null);

// Height only — width auto-calculated
const resized3 = await qp.resizeBlob(file, null, 800);

// Max dimension — longest side fits within limit
const resized4 = await qp.resizeBlob(file, null, null, { maxDimension: 4096 });

// resizeFile is an alias for resizeBlob
const resized5 = await qp.resizeFile(file, 1200, null);

Create Thumbnails

Automatically preserves aspect ratio. The longest side fits within maxDimension.

// 6000x4000 image → 200x133 thumbnail
const thumbnail = await qp.createThumbnail(file, 200);

// Also accepts Canvas, ImageData, HTMLImageElement
const thumb2 = await qp.createThumbnail(canvasElement, 150);

Draw to Canvas

const canvas = document.getElementById("preview");
canvas.width = 800;
canvas.height = 600;

await qp.resizeToCanvas(file, canvas, { filter: "lanczos" });

Batch Parallel Processing

Processes multiple images concurrently using a Web Worker pool. Each image runs the full decode→resize→encode pipeline in a separate worker.

const results = await qp.batchResize([
  { source: photo1, maxDimension: 800 },
  { source: photo2, width: 600, height: 400 },
  { source: photo3, maxDimension: 200 },
]);
// results = [Blob, Blob, Blob]

Metadata Preservation

By default, Canvas API strips all EXIF, ICC profiles, and other metadata. Set preserveMetadata: true to re-inject the original JPEG metadata into the output.

// Preserve metadata (EXIF date, GPS, camera info, ICC color profile, etc.)
const withMeta = await qp.resizeBlob(photo, 1200, 800, {
  preserveMetadata: true,
  outputMimeType: "image/jpeg",
});

// Strip metadata (default — better for privacy)
const stripped = await qp.resizeBlob(photo, 1200, 800, {
  preserveMetadata: false,
});

EXIF Orientation Auto-Correction

Smartphone photos store rotation info in EXIF. With autoRotate: true (default), images are automatically corrected to the right orientation.

// autoRotate: true (default) — portrait photos display correctly
const rotated = await qp.resizeBlob(phonePhoto, 800, 600);

// autoRotate: false — keep original pixel orientation
const raw = await qp.resizeBlob(phonePhoto, 800, 600, { autoRotate: false });

Fit Modes

// contain (default): fit within 800x600, preserve aspect ratio
const a = await qp.resizeBlob(photo, 800, 600, { fit: "contain" });

// cover: fill 800x600 completely, preserve aspect ratio (may crop)
const b = await qp.resizeBlob(photo, 800, 600, { fit: "cover" });

// fill: stretch to exactly 800x600, ignore aspect ratio
const c = await qp.resizeBlob(photo, 800, 600, { fit: "fill" });

Cleanup

qp.destroy(); // terminate worker pool and release resources

Options Reference

Option Default Description
filter "bilinear" Resize filter (nearest, bilinear, box, hamming, lanczos)
maxWorkers navigator.hardwareConcurrency Max worker pool size
idleTimeout 30000 Auto-terminate idle workers (ms)
outputMimeType "image/png" Output image format
outputQuality 0.92 JPEG/WebP quality (0–1)
useWasm true Enable WASM acceleration
preserveMetadata false Preserve EXIF/ICC/IPTC metadata
autoRotate true Auto-correct EXIF orientation
workerURL null Optional override: worker URL or factory for environments that cannot resolve import.meta.url worker imports
requireWorker false If true, throws when worker pipeline is unavailable instead of falling back to main thread
wasmPath null Override WASM module URL

Low-Level API (QuickPix)

For direct RGBA buffer manipulation or fine-grained control.

import { QuickPix } from "quickpix";

const qp = new QuickPix({ useWasm: true, filter: "lanczos" });

const src = new Uint8ClampedArray(640 * 480 * 4);
const out = await qp.resizeBuffer(src, 640, 480, 320, 240, {
  filter: "lanczos",
});

console.log(out.width, out.height, out.data.length); // 320 240 307200

Bundler-safe worker setup (Next, Vite, Rollup, esbuild, webpack, Turbopack)

QuickPix and QuickPixEasy now try worker imports from multiple internal candidate paths first, so most projects work without workerURL.

import { QuickPix, QuickPixEasy } from "quickpix";

const qp = new QuickPix();
const qpe = new QuickPixEasy();

If your bundler still fails to locate workers, pass workerURL in manually and keep requireWorker: true for hard-fail behavior:

import { QuickPix, QuickPixEasy } from "quickpix";
import resizeWorkerURL from "quickpix/resize-worker.js?url";
import pipelineWorkerURL from "quickpix/pipeline-worker.js?url";

const qp = new QuickPix({
  workerURL: resizeWorkerURL,
  requireWorker: true,
});

const qpe = new QuickPixEasy({
  workerURL: pipelineWorkerURL,
  requireWorker: true,
});

Example bundler templates are in examples/bundlers.

Supported Filters

Filter Description Speed Quality
nearest Nearest neighbor Fastest Low
bilinear 2x2 linear interpolation (default) Fast Medium
box Box average Medium Medium
hamming Hamming window Slow High
lanczos Lanczos3 sinc-based Slowest Best

Metadata Module

Standalone module for direct EXIF/ICC/IPTC manipulation.

import { readOrientation, extractSegments, injectSegments } from "quickpix/metadata";

const buffer = await file.arrayBuffer();
const orientation = readOrientation(buffer);
const segments = extractSegments(buffer);
const restored = await injectSegments(resizedJpegBlob, segments);

Install & Build

npm install quickpix

# Development (build from source)
npm install
npm run build:wasm    # Rust → WASM (requires wasm-pack)
npm run test:js
npm run test:rust

Benchmarks

npm run bench           # performance
npm run bench:compare   # vs pica
npm run bench:memory    # memory profiling
npm run bench:native    # vs sharp (libvips)
npm run bench:quality   # quality comparison

Browser Compatibility

Feature Chrome 69+ Firefox 105+ Safari 16.4+
Pipeline worker (optimal) Yes Yes Yes
JS fallback All browsers All browsers All browsers

Automatically falls back to main-thread processing when OffscreenCanvas is unavailable.

License

MIT