compressorjs vs browser-image-compression
Client-Side Image Compression in Web Applications
compressorjsbrowser-image-compression

Client-Side Image Compression in Web Applications

browser-image-compression and compressorjs are both JavaScript libraries designed to compress images directly in the browser before uploading or displaying them. They help reduce bandwidth usage, improve upload speeds, and optimize storage by resizing and re-encoding images using canvas-based techniques. Both support common image formats like JPEG and PNG, and allow developers to control quality, dimensions, and file size constraints through configuration options.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
compressorjs245,7465,730154 kB123 years agoMIT
browser-image-compression01,655863 kB643 years agoMIT

Client-Side Image Compression: browser-image-compression vs compressorjs

Both browser-image-compression and compressorjs let you shrink images in the browser using the <canvas> API—avoiding server round trips and saving bandwidth. But they differ in how they handle sizing, file limits, and developer ergonomics. Let’s compare them head-to-head.

📏 Sizing Strategy: Pixels vs File Size

browser-image-compression lets you set both pixel dimensions and a target file size. If the output exceeds your file limit, it automatically retries with lower quality until it fits.

import imageCompression from 'browser-image-compression';

const options = {
  maxSizeMB: 1,
  maxWidthOrHeight: 1920,
  useWebWorker: true
};

const compressedFile = await imageCompression(file, options);
// Result is guaranteed ≤ 1MB

compressorjs focuses on pixel dimensions and quality percentage, but doesn’t enforce file size limits. You can check the result size afterward, but there’s no auto-adjustment.

import Compressor from 'compressorjs';

new Compressor(file, {
  quality: 0.6,
  maxWidth: 1920,
  success(result) {
    console.log('Size:', result.size); // May still be >1MB
  }
});

💡 Use browser-image-compression when your backend enforces strict file size limits (e.g., “max 2MB”). Use compressorjs when you only care about visual quality and dimensions.

🔄 API Style: Promises vs Callbacks

browser-image-compression uses async/await with promises, fitting naturally into modern JavaScript workflows.

try {
  const output = await imageCompression(inputFile, options);
  uploadToServer(output);
} catch (error) {
  handleError(error);
}

compressorjs relies on callbacks (success, error), which can lead to nested logic in complex flows.

new Compressor(file, {
  success(result) {
    uploadToServer(result);
  },
  error(err) {
    handleError(err);
  }
});

💡 If you’re already using async/await heavily, browser-image-compression reduces mental overhead. If you’re in a callback-heavy codebase (e.g., legacy jQuery apps), compressorjs may feel more familiar.

🖼️ Aspect Ratio and Cropping

browser-image-compression preserves aspect ratio by default when you set maxWidthOrHeight. It doesn’t support cropping—you get the full scaled image.

// Scales proportionally to fit within 800px
const options = { maxWidthOrHeight: 800 };

compressorjs also preserves aspect ratio by default, but offers an aspectRatio option to force specific ratios (e.g., 16:9). However, it doesn’t crop—it just scales to fit the bounding box.

// Scales to fit within 800px width, then forces height to match 16:9
new Compressor(file, {
  maxWidth: 800,
  aspectRatio: 16 / 9
});

⚠️ Neither library performs true cropping (i.e., cutting out parts of the image). For that, you’d need additional tools like cropperjs.

⚙️ Advanced Options and Metadata

browser-image-compression exposes detailed control over:

  • Web Worker usage (useWebWorker)
  • MIME type override (mimeType)
  • Initial quality step and iteration (initialQuality, maxIteration)

But it doesn’t return metadata about the compression process.

compressorjs provides less granular control but includes before/after file stats in the success callback:

new Compressor(file, {
  success(result, { size, naturalWidth, naturalHeight }) {
    console.log(`Compressed from ${file.size} to ${result.size}`);
  }
});

This makes it easier to show users how much space they saved.

🧪 Error Handling and Browser Support

Both libraries rely on the HTML5 Canvas API and Blob support, so they work in all modern browsers (IE10+ for compressorjs, IE11+ for browser-image-compression due to Promise usage).

browser-image-compression throws errors as exceptions, which you catch with try/catch.

compressorjs calls the error callback for issues like invalid files or unsupported formats.

🛠️ Real-World Usage Scenarios

Scenario 1: User Avatar Upload (Strict Size Limit)

You need avatars ≤ 500KB and ≤ 400×400px.

  • Best choice: browser-image-compression
  • Why? Guarantees file size compliance without manual retries.
const compressed = await imageCompression(file, {
  maxSizeMB: 0.5,
  maxWidthOrHeight: 400
});

Scenario 2: Photo Gallery with Quality Preview

Users upload vacation photos; you want to show “Saved 2.1MB!” after compression.

  • Best choice: compressorjs
  • Why? Built-in size comparison simplifies UI feedback.
new Compressor(file, {
  quality: 0.7,
  success(result, { size }) {
    showSavings(file.size - size);
  }
});

Scenario 3: Form with Multiple Image Fields

A job application form requires three document scans (max 1MB each).

  • Best choice: browser-image-compression
  • Why? Promise-based API makes parallel compression clean:
const [id, resume, cert] = await Promise.all([
  imageCompression(idFile, opts),
  imageCompression(resumeFile, opts),
  imageCompression(certFile, opts)
]);

📌 Summary Table

Featurebrowser-image-compressioncompressorjs
File size enforcement✅ Auto-adjusts quality to fit❌ Manual check only
API style✅ Promise/async-await❌ Callbacks
Aspect ratio control❌ Proportional scaling only✅ Force ratio (no crop)
Compression metadata❌ Not provided✅ Original vs compressed
Web Worker support✅ Optional❌ Not supported

💡 Final Recommendation

  • Need guaranteed file size limits?browser-image-compression
  • Prefer callbacks and want size stats?compressorjs

Both are actively maintained and production-ready. Choose based on whether your priority is enforcing constraints (browser-image-compression) or simplicity with feedback (compressorjs).

How to Choose: compressorjs vs browser-image-compression

  • compressorjs:

    Choose compressorjs if you prefer a more concise API with built-in support for maintaining aspect ratio via aspectRatio and need quick access to metadata like original vs compressed file size. Its callback-style interface works well in event-driven workflows, and it provides straightforward options for basic compression tasks without complex file-size targeting.

  • browser-image-compression:

    Choose browser-image-compression if you need fine-grained control over file size limits (e.g., 'max 1MB') and want automatic scaling based on both dimensions and file size. It’s well-suited for forms where users must meet strict upload requirements, and its promise-based API integrates cleanly with modern async/await patterns.

README for compressorjs

Compressor.js

Coverage Status Downloads Version Gzip Size

JavaScript image compressor. Uses the Browser's native canvas.toBlob API to do the compression work, which means it is lossy compression, asynchronous, and has different compression effects in different browsers. Generally use this to precompress a image on the client side before uploading it.

Table of contents

Main

dist/
├── compressor.js        (UMD)
├── compressor.min.js    (UMD, compressed)
├── compressor.common.js (CommonJS, default)
└── compressor.esm.js    (ES Module)

Getting started

Install

npm install compressorjs

Usage

Syntax

new Compressor(file[, options])

file

The target image file for compressing.

options

  • Type: Object
  • Optional

The options for compressing. Check out the available options.

Example

<input type="file" id="file" accept="image/*">
import axios from 'axios';
import Compressor from 'compressorjs';

document.getElementById('file').addEventListener('change', (e) => {
  const file = e.target.files[0];

  if (!file) {
    return;
  }

  new Compressor(file, {
    quality: 0.6,

    // The compression process is asynchronous,
    // which means you have to access the `result` in the `success` hook function.
    success(result) {
      const formData = new FormData();

      // The third parameter is required for server
      formData.append('file', result, result.name);

      // Send the compressed image file to server with XMLHttpRequest.
      axios.post('/path/to/upload', formData).then(() => {
        console.log('Upload success');
      });
    },
    error(err) {
      console.log(err.message);
    },
  });

});

⬆ back to top

Options

You may set compressor options with new Compressor(file, options). If you want to change the global default options, You may use Compressor.setDefaults(options).

strict

  • Type: boolean
  • Default: true

Indicates whether to output the original image instead of the compressed one when the size of the compressed image is greater than the original one's, except the following cases:

  • The retainExif option is set to true.
  • The mimeType option is set and its value is different from the mime type of the image.
  • The width option is set and its value is greater than the natural width of the image.
  • The height option is set and its value is greater than the natural height of the image.
  • The minWidth option is set and its value is greater than the natural width of the image.
  • The minHeight option is set and its value is greater than the natural height of the image.
  • The maxWidth option is set and its value is less than the natural width of the image.
  • The maxHeight option is set and its value is less than the natural height of the image.

checkOrientation

  • Type: boolean
  • Default: true

Indicates whether to read the image's Exif Orientation value (JPEG image only), and then rotate or flip the image automatically with the value.

Notes:

  • Don't trust this all the time as some JPEG images have incorrect (not standard) Orientation values.
  • If the size of the target image is too large (e.g., greater than 10 MB), you should disable this option to avoid an out-of-memory crash.
  • The image's Exif information will be removed after compressed, so if you need the Exif information, you may need to upload the original image as well.

retainExif

  • Type: boolean
  • Default: false

Indicates whether to retain the image's Exif information after compressed.

maxWidth

  • Type: number
  • Default: Infinity

The max-width of the output image. The value should be greater than 0.

Avoid getting a blank output image, you might need to set the maxWidth and maxHeight options to limited numbers, because of the size limits of a canvas element, recommend to use 4096 or lesser.

maxHeight

  • Type: number
  • Default: Infinity

The max height of the output image. The value should be greater than 0.

minWidth

  • Type: number
  • Default: 0

The min-width of the output image. The value should be greater than 0 and should not be greater than the maxWidth.

minHeight

  • Type: number
  • Default: 0

The min-height of the output image. The value should be greater than 0 and should not be greater than the maxHeight.

width

  • Type: number
  • Default: undefined

The width of the output image. If not specified, the natural width of the original image will be used, or if the height option is set, the width will be computed automatically by the natural aspect ratio.

height

  • Type: number
  • Default: undefined

The height of the output image. If not specified, the natural height of the original image will be used, or if the width option is set, the height will be computed automatically by the natural aspect ratio.

resize

  • Type: string
  • Default: "none"
  • Options: "none", "contain", and "cover".

Sets how the size of the image should be resized to the container specified by the width and height options.

Note: This option only available when both the width and height options are specified.

quality

  • Type: number
  • Default: 0.8

The quality of the output image. It must be a number between 0 and 1. If this argument is anything else, the default values 0.92 and 0.80 are used for image/jpeg and image/webp respectively. Other arguments are ignored. Be careful to use 1 as it may make the size of the output image become larger.

Note: This option only available for image/jpeg and image/webp images.

Check out canvas.toBlob for more detail.

Examples:

QualityInput sizeOutput sizeCompression ratioDescription
02.12 MB114.61 KB94.72%-
0.22.12 MB349.57 KB83.90%-
0.42.12 MB517.10 KB76.18%-
0.62.12 MB694.99 KB67.99%Recommend
0.82.12 MB1.14 MB46.41%Recommend
12.12 MB2.12 MB0%Not recommend
NaN2.12 MB2.01 MB5.02%-

mimeType

  • Type: string
  • Default: 'auto'

The mime type of the output image. By default, the original mime type of the source image file will be used.

convertTypes

  • Type: Array or string (multiple types should be separated by commas)
  • Default: ['image/png']
  • Examples:
    • ['image/png', 'image/webp']
    • 'image/png,image/webp'

Files whose file type is included in this list, and whose file size exceeds the convertSize value will be converted to JPEGs.

convertSize

  • Type: number
  • Default: 5000000 (5 MB)

Files whose file type is included in the convertTypes list, and whose file size exceeds this value will be converted to JPEGs. To disable this, just set the value to Infinity.

Examples:

convertSizeInput size (type)Output size (type)Compression ratio
5 MB1.87 MB (PNG)1.87 MB (PNG)0%
5 MB5.66 MB (PNG)450.24 KB (JPEG)92.23%
5 MB9.74 MB (PNG)883.89 KB (JPEG)91.14%

beforeDraw(context, canvas)

  • Type: Function
  • Default: null
  • Parameters:
    • context: The 2d rendering context of the canvas.
    • canvas: The canvas for compression.

The hook function to execute before drawing the image into the canvas for compression.

new Compressor(file, {
  beforeDraw(context, canvas) {
    context.fillStyle = '#fff';
    context.fillRect(0, 0, canvas.width, canvas.height);
    context.filter = 'grayscale(100%)';
  },
});

drew(context, canvas)

  • Type: Function
  • Default: null
  • Parameters:
    • context: The 2d rendering context of the canvas.
    • canvas: The canvas for compression.

The hook function to execute after drawing the image into the canvas for compression.

new Compressor(file, {
  drew(context, canvas) {
    context.fillStyle = '#fff';
    context.font = '2rem serif';
    context.fillText('watermark', 20, canvas.height - 20);
  },
});

success(result)

  • Type: Function
  • Default: null
  • Parameters:
    • result: The compressed image (a File (read only) or Blob object).

The hook function to execute when successful to compress the image.

error(err)

  • Type: Function
  • Default: null
  • Parameters:
    • err: The compression error (an Error object).

The hook function executes when fails to compress the image.

⬆ back to top

Methods

abort()

Abort the compression process.

const compressor = new Compressor(file);

// Do something...
compressor.abort();

No conflict

If you have to use another compressor with the same namespace, just call the Compressor.noConflict static method to revert to it.

<script src="other-compressor.js"></script>
<script src="compressor.js"></script>
<script>
  Compressor.noConflict();
  // Code that uses other `Compressor` can follow here.
</script>

Browser support

  • Chrome (latest)
  • Firefox (latest)
  • Safari (latest)
  • Opera (latest)
  • Edge (latest)
  • Internet Explorer 10+

Contributing

Please read through our contributing guidelines.

Versioning

Maintained under the Semantic Versioning guidelines.

License

MIT © Chen Fengyuan

⬆ back to top