Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

browser-image-compression

Donaldcwl752.7kMIT2.0.2TypeScript support: included

Compress images in the browser

image compression, browser, image processing, reduce resolution, reduce size

readme

Browser Image Compression

npm npm npm

Javascript module to be run in the web browser for image compression.

Features

  • You can use this module to compress jpeg, png, webp, and bmp images by reducing resolution or storage size before uploading to the application server to save bandwidth.
  • Multi-thread (web worker) non-blocking compression is supported through options.

Demo / Example

open https://donaldcwl.github.io/browser-image-compression/example/basic.html

or check the "example" folder in this repo

Usage

<input type="file" accept="image/*" onchange="handleImageUpload(event);">

async await syntax:

async function handleImageUpload(event) {

  const imageFile = event.target.files[0];
  console.log('originalFile instanceof Blob', imageFile instanceof Blob); // true
  console.log(`originalFile size ${imageFile.size / 1024 / 1024} MB`);

  const options = {
    maxSizeMB: 1,
    maxWidthOrHeight: 1920,
    useWebWorker: true,
  }
  try {
    const compressedFile = await imageCompression(imageFile, options);
    console.log('compressedFile instanceof Blob', compressedFile instanceof Blob); // true
    console.log(`compressedFile size ${compressedFile.size / 1024 / 1024} MB`); // smaller than maxSizeMB

    await uploadToServer(compressedFile); // write your own logic
  } catch (error) {
    console.log(error);
  }

}

Promise.then().catch() syntax:

<summary>Click to expand</summary>
  function handleImageUpload(event) {

    var imageFile = event.target.files[0];
    console.log('originalFile instanceof Blob', imageFile instanceof Blob); // true
    console.log(`originalFile size ${imageFile.size / 1024 / 1024} MB`);

    var options = {
      maxSizeMB: 1,
      maxWidthOrHeight: 1920,
      useWebWorker: true
    }
    imageCompression(imageFile, options)
      .then(function (compressedFile) {
        console.log('compressedFile instanceof Blob', compressedFile instanceof Blob); // true
        console.log(`compressedFile size ${compressedFile.size / 1024 / 1024} MB`); // smaller than maxSizeMB

        return uploadToServer(compressedFile); // write your own logic
      })
      .catch(function (error) {
        console.log(error.message);
      });
  }

Installing

Use as ES module:

You can install it via npm or yarn

npm install browser-image-compression --save
# or
yarn add browser-image-compression
import imageCompression from 'browser-image-compression';

(can be used in frameworks like React, Angular, Vue etc)

(work with bundlers like webpack and rollup)

(or) Load UMD js file:

You can download imageCompression from the dist folder.

Alternatively, you can use a CDN like delivrjs:

<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/browser-image-compression@2.0.1/dist/browser-image-compression.js"></script>

Support

If this project helps you reduce the time to develop, you can buy me a cup of coffee :)

Buy Me A Coffee

(powered by Stripe)

API

Main function

// you should provide one of maxSizeMB, maxWidthOrHeight in the options
const options: Options = { 
  maxSizeMB: number,            // (default: Number.POSITIVE_INFINITY)
  maxWidthOrHeight: number,     // compressedFile will scale down by ratio to a point that width or height is smaller than maxWidthOrHeight (default: undefined)
                                // but, automatically reduce the size to smaller than the maximum Canvas size supported by each browser.
                                // Please check the Caveat part for details.
  onProgress: Function,         // optional, a function takes one progress argument (percentage from 0 to 100) 
  useWebWorker: boolean,        // optional, use multi-thread web worker, fallback to run in main-thread (default: true)
  libURL: string,               // optional, the libURL of this library for importing script in Web Worker (default: https://cdn.jsdelivr.net/npm/browser-image-compression/dist/browser-image-compression.js)
  preserveExif: boolean,        // optional, use preserve Exif metadata for JPEG image e.g., Camera model, Focal length, etc (default: false)

  signal: AbortSignal,          // optional, to abort / cancel the compression

  // following options are for advanced users
  maxIteration: number,         // optional, max number of iteration to compress the image (default: 10)
  exifOrientation: number,      // optional, see https://stackoverflow.com/a/32490603/10395024
  fileType: string,             // optional, fileType override e.g., 'image/jpeg', 'image/png' (default: file.type)
  initialQuality: number,       // optional, initial quality value between 0 and 1 (default: 1)
  alwaysKeepResolution: boolean // optional, only reduce quality, always keep width and height (default: false)
}

imageCompression(file: File, options: Options): Promise<File>

Caveat

Each browser limits the maximum size of a browser Canvas object.
So, we resize the image to less than the maximum size that each browser restricts.
(However, the proportion/ratio of the image remains.)

Abort / Cancel Compression

To use this feature, please check the browser compatibility: https://caniuse.com/?search=AbortController

function handleImageUpload(event) {

  var imageFile = event.target.files[0];

  var controller = new AbortController();

  var options = {
    // other options here
    signal: controller.signal,
  }
  imageCompression(imageFile, options)
    .then(function (compressedFile) {
      return uploadToServer(compressedFile); // write your own logic
    })
    .catch(function (error) {
      console.log(error.message); // output: I just want to stop
    });

  // simulate abort the compression after 1.5 seconds
  setTimeout(function () {
    controller.abort(new Error('I just want to stop'));
  }, 1500);
}

Helper function

  • for advanced users only, most users won't need to use the helper functions
    imageCompression.getDataUrlFromFile(file: File): Promise<base64 encoded string>
    imageCompression.getFilefromDataUrl(dataUrl: string, filename: string, lastModified?: number): Promise<File>
    imageCompression.loadImage(url: string): Promise<HTMLImageElement>
    imageCompression.drawImageInCanvas(img: HTMLImageElement, fileType?: string): HTMLCanvasElement | OffscreenCanvas
    imageCompression.drawFileInCanvas(file: File, options?: Options): Promise<[ImageBitmap | HTMLImageElement, HTMLCanvasElement | OffscreenCanvas]>
    imageCompression.canvasToFile(canvas: HTMLCanvasElement | OffscreenCanvas, fileType: string, fileName: string, fileLastModified: number, quality?: number): Promise<File>
    imageCompression.getExifOrientation(file: File): Promise<number> // based on https://stackoverflow.com/a/32490603/10395024
    imageCompression.copyExifWithoutOrientation(copyExifFromFile: File, copyExifToFile: File): Promise<File> // based on https://gist.github.com/tonytonyjan/ffb7cd0e82cb293b843ece7e79364233

Browsers support

IE / Edge
IE / Edge
Firefox
Firefox
Chrome
Chrome
Safari
Safari
iOS Safari
iOS Safari
Opera
Opera
IE10, IE11, Edge last 2 versions last 2 versions last 2 versions last 2 versions last 2 versions

IE support

This library uses ES features such as Promise API, globalThis. If you need to support browsers that do not support new ES features like IE. You can include the core-js polyfill in your project.

You can include the following script to load the core-js polyfill:

<script src="https://cdnjs.cloudflare.com/ajax/libs/core-js/3.21.1/minified.min.js"></script>

Webp support

The webp compression is supported on major browsers. Please see https://caniuse.com/mdn-api_offscreencanvas_converttoblob_option_type_parameter_webp for browser compatibility.

Remarks for compression to work in Web Worker

The browser needs to support "OffscreenCanvas" API in order to take advantage of non-blocking compression. If the browser does not support "OffscreenCanvas" API, the main thread is used instead. See https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas#browser_compatibility for browser compatibility of "OffscreenCanvas" API.

Typescript type definitions

Typescript definitions are included in the package & referenced in the types section of the package.json

Remarks on Content Security Policy (CSP)

If your website has CSP enabled and you want to use Web Worker (useWebWorker: true), please add the following to the response header content-security-policy: script-src 'self' blob: https://cdn.jsdelivr.net

  • blob: is for loading Web Worker script
  • https://cdn.jsdelivr.net is for importing this library from CDN inside Web Worker script. If you don't want to load this library from CDN, you can set your self hosted library URL in options.libURL.

Contribution

  1. fork the repo and git clone it
  2. run npm run watch # it will watch code change in lib/ folder and generate js in dist/ folder
  3. add/update code in lib/ folder
  4. try the code by opening example/development.html which will load the js in dist/ folder
  5. add/update test in test/ folder
  6. npm run test
  7. push to your forked repo on github
  8. make a pull request to dev branch of this repo

changelog

2.0.1 (6 Mar 2023)

  • feature: preserve Exif metadata for JPEG #164
  • feature: support BMP image compression #181
  • optimized: solved error in sensible CSP environment #106
  • optimized: increase initial PNG color depth to improve output quality #180
  • fixed: circular dependency #34
  • fixed: export Options interface #157
  • fixed: black image output on iOS devices #169, #165, #166

v2.0.0 (13 Apr 2022)

  • feature: example html - added CSS animation for showing main thread status
  • feature: example html - added version switch
  • feature: support AbortController (abort / cancel during compression) #101
  • feature: options.alwaysKeepResolution (default: false) - keep the resolution (width and height) during compression and reduce the quality only (note that options.maxWidthOrHeight is still applied if set) #127
  • fixed: Main thread is blocked on Mac device for options.useWebWorker=true #139
  • updated: dropped core-js to reduce bundle size #138
  • updated: options.useWebWorker default set to true

v1.0.17 (15 Nov 2021)

  • feature: apply white background to transparent PNG > JPG conversion if options.fileType is image/jpeg or image/jpg #119
  • fixed: Fixed image cropped on Safari #118

    v1.0.16 (26 Sep 2021)

  • fixed: Fixed output white picture on iOS Safari for large image because of canvas max size #116
  • fixed: Fixed wrong image orientation on iOS device #118
  • feature: set white background for transparent png file with jpeg file extension #119

v1.0.15 (12 Aug 2021)

  • fixed: Fixed black Images and type error by considering Canvas maximum size supported by different browsers #84, #36
  • fixed: IE compatibility, include polyfill with core-js@3 e.g, globalThis, Promise #108, #110
  • fixed: Test suites in few projects may have error, added extra checking on whether File and FileReader exist in the Window object #92
  • fixed: issue with export causing compile error in typescript project #63

v1.0.14 (6 Jan 2021)

  • updated: use UZIP to compress PNG image instead of Canvas
  • fixed: PNG transparent background become black after compression #84, #76
  • fixed: progress jump back to 0 when Web Worker failback to main thread #90

v1.0.13 (8 Nov 2020)

  • added: new option for setting initial quality level #64, #78
  • fixed: options object being altered by the compress func #71
  • fixed: issue with output size of png compression #57

v1.0.12 (4 Jun 2020)

  • fixed: issue with SSR #58

v1.0.11 (8 May 2020)

  • fixed: issue with IE support #38 #23

v1.0.10 (7 May 2020)

  • fixed: issue in Web Worker when onProgress is undefined #50
  • fixed: handle behavior change of exif orientation in iOS 13.4.1 and Safari 13.1 Desktop #52
  • updated: typescript type definitions to resolve #54

v1.0.9 (25 Mar 2020)

  • updated: compression becomes less aggressive, output file is closer to the 'maxWidthOrHeight' and/or 'maxSizeMB' in config
  • fixed: file size increased in specific situation

v1.0.8 (16 Mar 2020)

  • added: support for Server Side Rendering (SSR)
  • updated: ts type file

v1.0.7 (15 Mar 2020)

  • added: onProgress function in options for compression progress updates
  • added: allow fileType override
  • added: ts type file
  • updated: useWebWorker default set to false
  • fixed: garbage clean canvas for safari
  • fixed: issue in Cordova support
  • fixed: issue in IE browser
  • fixed: other issues

v1.0.6 (5 Jul 2019)

  • fixed: exif orientation do not work in some situations

v1.0.5 (1 Jun 2019)

  • added: support for cordova project that uses cordova-plugin-file
  • optimized: follow image exif orientation even though image do not required to compress or resize
  • fixed: error may throw on iPhone Safari because of OffscreenCanvas cannot get 2d context
  • fixed: exif orientation do not work in some situations

v1.0.2 (8 Apr 2019)

  • fixed: bug related to image orientation and squeezing

v1.0.1 (8 Mar 2019)

  • fixed: bug related to wrong image output resolution in some cases

v1.0.0 (6 Feb 2019)

  • breaking change: change "imageCompression" function signature
  • optimized: use of OffscreenCanvas when support, fallback to document.createElement('canvas')
  • optimized: use createImageBitmap when support, fallback to FileReader readAsDataURL
  • added: support web worker
  • added: follows image exif orientation