Open-source project
nodeca/pica avatar
nodeca/pica

pica: High-Quality Browser Image Resizing with WebAssembly and Web Workers

Resize image in browser with high quality and high speed

4,154 stars257 forksTypeScriptMIT

At a glance

What is it?
pica is a browser-side image resizing library that produces output without visible pixelation by using the mks2013 Lanczos-based filter. It selects the best available browser technology automatically: WebAssembly, Web Workers, createImageBitmap, or pure JavaScript. The library has no external dependencies and installs via npm as the pica package.
Who is it for?
pica fits web applications that need client-side image resizing before upload, such as reducing file size or generating thumbnails without a server round-trip. The library is not recommended for professional image work because the canvas API limits channel precision to 8 bits per channel with no gamma correction.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 46 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What problem pica solves and who it serves

Resizing a large image to a thumbnail in the browser using a plain canvas drawImage call produces blocky, pixelated output because the browser's built-in scaling algorithm is not optimized for quality. pica solves this by applying a Lanczos-based resampling filter (mks2013 by default) that produces output comparable to what a server-side image processing library would generate.

The README lists three practical uses: reducing upload sizes for large images before they are sent to a server, offloading image processing from the server to the client, and generating thumbnails entirely in the browser. Applications that accept image uploads are the primary target: instead of sending a 10 MB photo to a server for resizing, pica resizes it client-side before the upload begins. The library has no external dependencies, which keeps the dependency tree clean for library authors and projects with strict bundle size requirements.

Installing pica and a first resize

Install from npm:

sh
npm install pica

The library exports both a factory function and a named class. The recommended usage with ESM:

js
import pica from 'pica';
const resizer = pica();

// Resize from Canvas/Image to another Canvas
resizer.resize(from, to)
  .then(result => console.log('resize done!'));

// Resize & convert to blob
resizer.resize(from, to)
  .then(result => resizer.toBlob(result, 'image/jpeg', 0.90))
  .then(blob => console.log('resized to canvas & created blob!'));

The `from` argument can be a Canvas, Image, or ImageBitmap. The `to` argument must be a destination canvas with non-zero dimensions already set. The Promise resolves with the destination canvas. CommonJS usage replaces the import with `const resizer = require('pica')()`. The named Pica class is also available as `import { Pica } from 'pica'; new Pica()`.

How pica selects rendering backends

pica's feature detection is built into its default configuration. The features list defaults to `['js', 'wasm', 'ww']`, meaning it tries WebAssembly first (for performance), uses Web Workers for non-blocking processing, and falls back to pure JavaScript if neither is available. A fourth option, `'cib'` for createImageBitmap, exists but is disabled by default.

The README explains why createImageBitmap is disabled: Chrome's implementation is buggy when used as a downscaler, and the result quality is unpredictable. createImageBitmap is still used internally for non-blocking image decode when available, but not for the actual resize step. Enabling `'cib'` in the features array is possible but the README warns that results will vary by browser. The default configuration without `'cib'` produces consistent, predictable output across browsers.

Images are processed in tiles (1024x1024 by default) rather than all at once. This limits peak memory consumption regardless of the source image dimensions.

The resize API: filters, unsharp masking, and cancel

The mks2013 filter is the default and recommended choice. It performs both resizing and sharpening in a single pass, and the README advises against changing it for typical use cases. The `filter` option accepts the filter name as a string; a separate file in the source (resize_filter_info.ts) documents the available filter names.

For workflows that need additional sharpening control, the resize call accepts unsharpAmount (a value above 100 to 200 is the README's suggestion), unsharpRadius (0.5 to 2.0; values below 0.5 disable unsharp masking), and unsharpThreshold (0 to 255). These are optional and independent of the filter selection. Since mks2013 already does optimal sharpening, the README notes these are not typically needed.

The cancelToken option accepts a Promise. Rejecting that Promise cancels the current operation, which is useful in interactive interfaces where a user might resize a new image before the previous one finishes. Processing multiple images sequentially rather than in parallel is the README's recommendation for optimizing CPU and memory use.

Known limitations and the professional image caveat

Several constraints come from the browser environment rather than from pica's design. Cross-domain images require proper CORS headers (Access-Control-Allow-Origin) due to JavaScript security restrictions; local files are exempt. iOS imposes canvas memory limits that can cause failures on very large images. The README links to a separate wiki page describing this in detail.

The quality ceiling is set by the canvas API's 8-bit-per-channel limit. Professional images are often edited at 12 or 16 bits per channel with gamma correction taken into account. The README states directly that the lack of gamma correction access causes some quality loss and that pica is not recommended for professional-quality image resizing. For visible-to-the-eye consumer photos, the quality loss is described as not noticeable.

For JPEG sources, the README recommends using the companion library image-blob-reduce instead of pica directly. image-blob-reduce handles EXIF metadata preservation and correct orientation from the camera, which pica does not address.

Migrating from pica v9 to v10

The v10 release changed several API conventions that require code updates from v9 users. First, legacy browser support including IE was dropped; only modern browsers are supported. Second, using `new` on the default export (`new (require('pica'))()`) no longer works; the default export is now a factory function, so the correct call is `pica()` or `require('pica')()`. The named Pica class continues to work with `new`.

Third, the `createCanvas` option was removed; overriding canvas creation is now done by exposing a custom OffscreenCanvas globally. Fourth, the positional `quality` argument to resize (e.g., `pica.resize(from, to, 3)`) was deprecated in favor of the `filter` option. The object form `{ quality: 3 }` still works but is deprecated. Finally, multiple Pica instances no longer share a worker pool implicitly; applications that relied on shared pools must be refactored to create a single instance and reuse it.

Comparison with server-side resizing and the split build option

Sharp is a well-known Node.js image processing library that runs server-side using the libvips C library. It operates at full bit depth and supports color profiles. pica runs in the browser where neither libvips nor color profile access is available, so the two tools serve different deployment constraints rather than competing directly. When the goal is reducing upload size before a request leaves the browser, pica is the right layer; when the goal is producing a final, color-managed output, server-side processing remains more capable.

For projects with strict Content Security Policy settings that block inline Worker code, pica provides a split build. The main entry (pica/dist/pica_main.mjs) is imported separately from the worker (pica/dist/pica_worker.js), and the workerURL option points to the worker file:

js
import createPica from 'pica/dist/pica_main.mjs';

const resizer = createPica({
  workerURL: new URL('pica/dist/pica_worker.js', import.meta.url)
});

This separates the worker code into its own file, which produces a smaller main bundle and satisfies stricter CSP rules.

Editorial conclusion

pica fits web applications that need client-side image resizing before upload, such as reducing file size or generating thumbnails without a server round-trip. The library is not recommended for professional image work because the canvas API limits channel precision to 8 bits per channel with no gamma correction. For JPEG sources that need EXIF metadata preserved or correct orientation handling, the companion library image-blob-reduce is the right tool rather than pica directly. The last push was on 2026-08-15.

Frequently asked questions

How do I use pica to resize an image and get a blob?

Call resizer.resize(from, to) to resize to a destination canvas, then chain resizer.toBlob(result, 'image/jpeg', 0.90) to convert the canvas to a Blob. The pica.toBlob() method includes a shim for browsers that do not support canvas.toBlob() natively.

What resize filter does pica use by default?

pica uses the mks2013 filter by default. The README describes it as performing both resizing and sharpening in a single pass and states it is optimal for general use. Changing the filter is possible via the filter option in the resize call but is not recommended for typical image thumbnailing.

Does pica work correctly with JPEG images?

pica can resize from a JPEG-sourced Canvas or Image, but it does not handle EXIF metadata, orientation flags, or gamma correction for JPEG sources. The README explicitly recommends using the companion library image-blob-reduce for JPEG resize workflows that need correct orientation and preserved EXIF data.

Official sources

  1. Issues
  2. License: MIT
  3. nodeca/pica on GitHub
  4. Project website
  5. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/nodeca-pica.svg)](https://hysenlabs.com/projects/nodeca-pica)