compressorjs

A JavaScript image compressor that shrinks images in the browser with the Canvas API before you ever hit the network.

Library
npm
v1.3.0
5,765stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
71/100Good
Development Activity76
Maintenance56
Community52
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
76/100Good
Architecture78
Code Quality82
Innovation55
Learning Curve90

Compressor.js is a lightweight, dependency-light JavaScript library that compresses images entirely on the client side, using the browser’s native HTMLCanvasElement.toBlob() method to do the actual compression work. Rather than uploading a full-resolution photo and compressing it server-side, an app can shrink it in the browser first, cutting upload time and bandwidth cost before the request ever leaves the page.

The library wraps the compression pipeline in a single Compressor class: it validates the input File/Blob, reads EXIF orientation data from JPEGs so photos taken on a phone don’t come out rotated, draws the (optionally resized) image onto an in-memory canvas, and hands back a compressed File through a success callback. Because the compression is asynchronous and lossy by nature, and its output can vary slightly across browsers, it’s best suited as a pre-upload optimization step rather than a guarantee of an exact target size.

It is widely used as the compression step behind file-upload widgets and image-heavy forms — pair it with an <input type="file"> change handler and it silently compresses before the FormData POST. Fine-grained options (quality, maxWidth/maxHeight, convertSize, strict) let consumers dial in the size/quality tradeoff per use case, and beforeDraw/drew hooks expose the raw canvas context for custom pre-processing like watermarking or forced grayscale.

What You Get

  • A single Compressor class you instantiate with a File/Blob and an options object — no build step or server component required
  • Automatic EXIF orientation correction for JPEGs, so photos captured on mobile devices display right-side-up after compression
  • Fine-grained size controls (width, height, maxWidth/maxHeight, minWidth/minHeight, resize: contain|cover) for producing thumbnails or capped-dimension uploads
  • A strict mode that falls back to the original file when the ‘compressed’ output would actually be larger
  • Automatic PNG-to-JPEG conversion above a configurable size threshold (convertTypes/convertSize) to avoid oversized lossless images
  • beforeDraw/drew hooks that expose the raw CanvasRenderingContext2D for custom manipulation (watermarks, filters) mid-pipeline
  • Shipped UMD, CommonJS, and ES Module builds plus a bundled TypeScript declaration file

Common Use Cases

  • Compressing user-selected photos in a file-upload form before sending them via FormData to reduce upload time on slow connections
  • Generating capped-dimension thumbnails or avatar images client-side to keep storage and CDN costs down
  • Pre-processing camera-captured photos in mobile web apps where EXIF orientation would otherwise render images sideways
  • Reducing large PNG screenshots or exports to JPEG automatically when they exceed a size threshold before storage
  • Adding a lightweight watermark or grayscale filter via the beforeDraw/drew canvas hooks as part of the compression step

Under The Hood

Architecture The library centers on one Compressor class (src/index.js) that drives a linear, callback-based pipeline: init() validates the file and its MIME type, load() reads it via FileReader or URL.createObjectURL depending on whether EXIF/orientation handling is needed, draw() renders the (possibly resized and rotated) image onto an in-memory <canvas>, and done() normalizes the resulting Blob into a File and invokes the consumer’s success/error hooks. Sizing math, EXIF parsing, and MIME-type helpers are factored out into src/utilities.js, and environment-detection constants (window/browser presence) live in a small src/constants.js, keeping the core class focused on orchestration while leaving low-level byte manipulation (EXIF segment parsing, orientation matrices, data-URL conversion) in isolated, independently testable functions. There’s no dependency injection or plugin system — it’s a single-purpose orchestration class, and the tradeoff is that anyone needing to alter the pipeline (e.g., swap the resize algorithm) has to fork the class rather than compose around it.

Tech Stack Compressorjs is plain ES2015+ JavaScript with no runtime framework — its only two production dependencies are blueimp-canvas-to-blob (canvas-to-blob polyfill for older browsers) and is-blob (type guard). The build is handled by Rollup with a Babel transform (@rollup/plugin-babel, @babel/preset-env) to produce UMD, CommonJS, and ES Module bundles targeting the browserslist config, and a hand-written TypeScript declaration file (types/index.d.ts) is shipped alongside the plain-JS source rather than compiling from TypeScript directly. There is no backend, database, or deployment target beyond static bundles published to npm and a GitHub Pages demo site.

Code Quality Tests run in real browsers via Karma with Mocha as the test runner and Chai for assertions, driven headlessly through Puppeteer/Chrome, with coverage collected via karma-coverage-istanbul-reporter and reported to Codecov in CI — a comprehensive setup for a browser-only library that can’t easily run under Node-based test runners. Linting is enforced with ESLint (Airbnb base config) for JavaScript and Stylelint for the docs site’s CSS, wired into lint-staged/simple-git-hooks pre-commit checks and a GitHub Actions CI workflow that runs lint, build, and test on every push and PR. Naming and error handling are consistent throughout — errors are constructed as real Error objects and routed through a single fail() method rather than swallowed, and JSDoc comments annotate essentially every exported function and class method.

What Makes It Unique Its standout technical choice is fully client-side EXIF handling: it reads and strips orientation data with a hand-rolled JPEG/EXIF segment parser (resetAndGetOrientation, getExif, insertExif in utilities.js) so it can correct a photo’s rotation before drawing it to canvas, and optionally re-insert the original EXIF metadata into the compressed output afterward — a level of manual byte-level parsing that similar canvas-based compressors typically skip. Combined with its strict mode (returning the original file rather than a larger ‘compressed’ one) and automatic PNG→JPEG conversion above a size threshold, it optimizes for pragmatic, safe defaults over raw compression ratio.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search