Giter Club home page Giter Club logo

compressorjs's Introduction

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:

Quality Input size Output size Compression ratio Description
0 2.12 MB 114.61 KB 94.72% -
0.2 2.12 MB 349.57 KB 83.90% -
0.4 2.12 MB 517.10 KB 76.18% -
0.6 2.12 MB 694.99 KB 67.99% Recommend
0.8 2.12 MB 1.14 MB 46.41% Recommend
1 2.12 MB 2.12 MB 0% Not recommend
NaN 2.12 MB 2.01 MB 5.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.

For image file type support, see the Image file type and format guide.

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:

convertSize Input size (type) Output size (type) Compression ratio
5 MB 1.87 MB (PNG) 1.87 MB (PNG) 0%
5 MB 5.66 MB (PNG) 450.24 KB (JPEG) 92.23%
5 MB 9.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

compressorjs's People

Contributors

chriszou avatar dependabot[bot] avatar fengyuanchen avatar foochifa avatar zcf0508 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

compressorjs's Issues

[Error]Safari: The operation is insecure.

Thanks for xkeshi, this tool works well on chrome, but in safari throws an error on this line:
canvas.toBlob(resolve, options.mimeType, options.quality);

anyone has any idea about this ? Here is my code:

const file = (<HTMLInputElement>document.getElementById('pic' + target)).files[0];
const compress = new ImageCompressor(file, {
        convertSize: 1000000,
        maxWidth   : 768,
        maxHeight  : 768,});

Feature request - give heavier tasks a separate thread

First of all great job on creating this image-compressor, I love it!

I was wondering if it could be made even more efficient by putting the heavier tasks of compressing an image in a separate thread (for example with webworkers, though this example can be a lot of work with workers having no access to the DOM).

The reason for this idea is that when using this compressor in a web based application I noticed that the page freezes temporarily when processing an image on a phone and with very large images even a computer can freeze for a few seconds.

I hope this is an idea interesting enough to be worth pursuing!

Unable to install

I have shared hosted and cannot npm install. What other options are available?

Options can be improved

There are some issues in the part of the code which handles resizing:

  • options.height is ignored when options.width is set;
  • and images smaller than options.height and/or options.height can be either upscaled or not compressed (because the comparison in line 107);

Note that, because the comparison in line 107, seems resizing is only a method to try to make a image smaller, not a requirement. I think there should be at least a note in readme about that.

In lines 94 and 96 the format of the resulting image is the same format of the original image. So the format is a choice of the end user (it can be even a BMP image). Would be better if it was an option.

Finally, is complicated to add a size limit option? Too large files can be compressed into a lossy format (like imgur, which converts PNGs larger than 5MB to JPEG).

What does convertSize do?

First off, thanks for sharing this lib!

I wonder what convertSize does? Does it have something to do with compression and how is it then different from the quality option?

Thanks

Compress multiple images

I am compressing multiple images.

I have up to 25 images in a array.
I loop through all images then call new ImageCompressor() for each image. Is there any other way to compress multiple images at? I dont feel like my way is very thread safe

[iOS]Safari: The operation is insecure

I used in iphone safari , iOS 11.2,
but throw this error, I've tried to solve this error,
I add this code to image-compressor.esm.js in line 627

image.setAttribute('crossOrigin', 'anonymous');

the error gone

image orientation?

Have you considered adding a check for image orientation? Or an option to leave exif data? I am doing more image work on the server with sharp, which has an autorotate feature, but the if I run the file through this on the client first, sharp will have no exif data to autorotate with. This is mostly an issue with images people upload via their iphone.

A similar package to this, import loadImage from 'blueimp-load-image', has a rotate feature.

I'll look at exif-js or something else to maybe pre-pre-process it, but it'd be awesome to just pass in an extra option to image-compressor.

Image Compressor Safari(?)

I can't get this to work on Safari at all.
Safari seemingly executes new ImageCompressor(file, { [options], succes(){...}, error(){...} });
Then, Safari simply continues executing the code after as if new ImageCompressor returned already. No success code is executed. no error code is executed.

Again, this is no problem on other browsers/devices.
I don't know what the cause of the issue is. Any help is appreciated. Code below.

Small black line in picture's bottom after compression

I use this library to compress images to a max file size of 70kb before uploading it to AWS S3. I do it twice: one time for my main higher quality image and another time to generate a thumbnail of the same image.

In some cases, randomly and after conversion, the images comes out with a small black line in the bottom of the image. There's one example in here: https://s3-sa-east-1.amazonaws.com/carpediemxp-test-0000001/partners-pictures-thumb/5b528fc884f90700148ec69a

In most cases this does not happen, but when it does, it's really annoying, because images are the main attractions of my web service.

I suspect this may happen because of image dimensions floating point approximations while converting the image from one size to another, but I don't know how to fix this.

Is there any way to fix this problem and keep my images without those black lines?

Thanks in advance!

Returned type is not detectable

After compressing, image result returns Blob or File just like docs says!
There doesn't seem to be an option for result type on docs. Is there a way to detect or infer type rather than below snippet?

result.__proto__.constructor.name

Why this code doesn't compress the image?

minWidth e minHeight are not working

new ImageCompressor(event.target.files[0], {
    maxWidth: 300,
    maxHeight: 300,
    success(result) {
        new S3('guizion-futtari', this).uploadFile('translator-profile', result, (url) => {
            self.photoUrl = url
            console.log(url)
            self.updateUser()
        }, (error) => {
            console.error(error)
            self.loading = false
        })
    },
    error(e) {
        console.log(e.message)
    },
})

bug in v1.1.1 removing browser and adding unpkg is causing a not a constructor error

In v1.1.1

I saw that you removed "browser": "dist/image-compressor.js",
and added "unpkg": "dist/image-compressor.js",

This gives me the error
ImageCompressor is not a constructor when I use it like this:

window.ImageCompressor = require('image-compressor.js');
var imageCompressor = new ImageCompressor();

However if I add the line "browser": "dist/image-compressor.js", to image-comrpressors package.json file the code works fine

I am using this package in a laravel/webpack project

Make size smaller by converting to grayscale

For a given fixed size and fixed quality (let's say 0.8), is it possible to reduce file size even further / save even more kB by saivng the image as grayscale JPG?

How to do that @xkeshi?

What additional % reduction can we hope by discarding color and going grayscale (in general)?

How get original name from fromData?

I can get file image data
but i can't get original name image.

You can help me to get original name from image file?
I send data with formData.append('file', result, result.name);

Thank you

Note about: quality / compression setting

As, in general, it is a good thing to compress images, it may be counter productive in some cases.
Compressing images before uploading is useful if the images later on are served 'as-is' by a website, for example. But it isn't, if the images are sources for creation of image variations, like with a CMF or CMS. For the later, it is best usage to upload the images, (that serve as original source for variation creation), in the best possible quality. (uncompressed!)

Why is this correct?
If you create variations, the images get loaded into memory, unpacked / uncompressed, and get compressed on save again. This makes every previuos compression useless. But it isn't only useless, it also has some disadvantages, when working with previously compressed images.

Please try and compare two images:

  • A = uncompressed uploaded source, filesize = 2 MB (for example)
  • B = compressed uploaded same source, filesize = 1.1 MB (for example)

Workflow for both images is to create a halfsized variation, with e.g. PHP and GD-Library, save it, or save it and additionally pass it through a server side compressor, like image-optim.

Result will be:

  • A: filesize, for example, 0.6 MB
  • B: filesize, for example, 0.7 MB

Regardless if there is an extra compression tool involved or not, the final filesize of the B-file will be always greater then that of the A-file. Also the visual quality of the B image is of lesser quality, means it will have more (JPEG) artifacts.

So, when using this library for images uploaded into a CMF / CMS for later variation creation, everytime a quality setting of 1 should be used. This is highly recommended!

The strong and very useful part of the library in case of CMF / CMS is the possibilty to resize the images before uploading, means, they should not exceed some maximum dimensions in most cases! This helps in saving bandwidth and time for uploading the images and also in server-side saving of time and cpu- and memory-usage later on with every variation creation in the CMF / CMS!

What if it is used in multiple uploads?

can you help me?

var files = [];
var formData = new FormData();

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

if (!file) {
   return;
}
  
var filesLength = file.length;

for (var i = 0; i < filesLength; i++) {
    new ImageCompressor(file[i], {
      quality: .6,
      maxWidth: 2000,
      maxHeight: 2000,
      success(result) {
        formData.append('files[]', result, result.name);
      },
      error(e) {
        console.log(e.message);
      },
    });
  }
});

$( "#upload" ).click(function() {
  axios.post('path', formData).then(() => {
        console.log('Upload success!');
  });
});

From the script above, I can get the picture. but can not get his name.
Can you help me? :D

Error: The first argument must be a File or Blob object.

Hi,

I'm working on Angular 4, Ionic 3, Cordova application.

I'm getting this error when passing a File to new ImageCompressor(file, options)

This is my implementation:

window.resolveLocalFileSystemURL(path, (fileEntry) => {
      fileEntry.file((file) => {
        console.log(file)

          new ImageCompressor(file, {
            quality: 0.6,
            success: (result) => {
              console.log(result, result.size)
            },
            error: err => {
              console.log(err)
            }
          })
      })
    }, err => {
      console.log(err)
    });

I even tried reading this file as ArrayBuffer (readAsArrayBuffer(file)), which returns a blob and passing the same to ImageCompressor, but it did not help.

The console.log(file) returns me this:

File
end: 285885
lastModified: 1515080323747.9968
lastModifiedDate: 1515080323747.9968
localURL: "cdvfile://localhost/temporary/cdv_photo_016.jpg"
name: "cdv_photo_016.jpg"
size: 285885
start: 0
type: "image/jpeg"

It'll be great if you can let me know, where I'm going wrong?

Thanks,

Images after compressing cannot be uploaded to Firebase

Hello, I have an issue with compressing images before uploading to Firebase. Firstly, my original code to upload a list of images to Firebase works (below)

        const images = await FirebaseSevice.uploadMissionImage(imageFiles);

However, I need to compress images before uploading to improve the performance of my application, so I use this library but I cannot upload processed images to Firebase. My code uses xkeshi/image-compressor

      const IM = new ImageCompressor();
      let processed = [];
      for (let image of imageFiles) {
        IM.compress(image)
          .then((result) => {
            console.log(result);
            processed.push(result);
          });
      }
      const images = await FirebaseSevice.uploadMissionImage(processed);

PS: FirebaseSevice.uploadMissionImage() takes a array of files as a parameter
Do you have any solution for this case?
Thanks.

iOS 9 Invalid attempt to spread non-iterable instance

I'm submitting a...


[ ] Regression (a behavior that used to work and stopped working in a new release)
[x ] Bug report 
[ ] Feature request
[ ] Documentation issue or request

Current behavior

iOS9 设备上的 Safari 始终报 “Invalid attempt to spread non-iterable instance” 错误

调试后发现 _arrayWithoutHoles 方法中的 Array.isArray() 返回 false,移除这个判断后不报错了,怀疑是 iOS9 的把数组误判断为不是数组。

改成这样后功能正常了:

function _toConsumableArray(arr) {
  return _iterableToArray(arr) || _arrayWithoutHoles(arr) || _nonIterableSpread();
}

function _arrayWithoutHoles(arr) {
  for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];

  return arr2;
}

Expected behavior

Minimal reproduction of the problem with instructions

What is the motivation / use case for changing the behavior?

Environment


Compressor.js version: X.Y.Z


Browser:
- [ ] Chrome (desktop) version XX
- [ ] Chrome (Android) version XX
- [ ] Chrome (iOS) version XX
- [ ] Firefox version XX
- [ ] Safari (desktop) version XX
- [x] Safari (iOS) version XX
- [ ] IE version XX
- [ ] Edge version XX

Others:

RangeError: Offset is outside the bounds of the DataView

Hi, i'm coming up with this error when i using image-crompressor with ngModel value (other cases work normal)
ERROR RangeError: Offset is outside the bounds of the DataView at DataView.getUint8 (<anonymous>) at getOrientation (image-compressor.esm.js:352) at FileReader.reader.onload (image-compressor.esm.js:611) at ZoneDelegate.invoke (zone.js:388) at Object.onInvoke (core.js:4760) at ZoneDelegate.invoke (zone.js:387) at Zone.runGuarded (zone.js:151) at FileReader.eval (zone.js:129)

and at GetOrientation leads me to
if (dataView.getUint8(0) === 0xFF && dataView.getUint8(1) === 0xD8) { var length = dataView.byteLength; var offset = 2;

Do you have any idea how to fix this? Thank you

npm 1.1.4

Hello, could you push the new release on NPM please ?

Filename always returns blob

after append data to multipart it always return data with filename "blob" without any extension. how to send filename as original filename in result object.

Failed to load the image

I got this error message,when i compressed image on one android mobile phone.
The code runs rightly with other phones.

to base64?

Could you export the result to base64?

IE11 - Invalid argument 'url'. Failed to revoke Blob URL: '..' with checkOrientation as true

I'm using the following config for compress:

var imageCompressorOptions = {
checkOrientation: true,
minWidth: 0,
minHeight: 0,
quality: 0.5,
mimeType: "",
convertSize: 5000000
};

And the following check:
if (URL) {
URL.revokeObjectURL(image.src);
}
Should be:
if (URL && !options.checkOrientation) {
URL.revokeObjectURL(image.src);
}
The same as is that check when need to create a blob URL.

Receiving an error when i have options.checkOrientation set and the image isn't loaded via url

When i set the options to checkOrientation to false and the browser supports both URL/FileReader then the URL option is always used, even if the passed file cannot be resolved via an url, which results then in an error due to URL.createObjectURL(file) generating an Blob with an empty data.url. I think that this is not supposed to happen. If i have checkOrientation set to true, then everything works as it should.

Passed File:

lastModified:1492945785394
lastModifiedDate:Sun Apr 23 2017 13:09:45 GMT+0200 (W. Europe Daylight Time) {}
name:"79c628d31c50eb447a840f6e1ee9b6bb.jpg"
preview:"blob:http://localhost:5000/273d41e3-082a-4312-8109-210ee52ee4fc"
size:41563
type:"image/jpeg"
webkitRelativePath:""

Passed Data value generated from URL.createObjectURL(file):

blob:http://localhost:5000/295ce5f1-d966-4ada-a9a6-38f87692e12b

Simple example

Please provide a simple example using jQuery. It is difficult to follow your examples. Thanks

Cant change image name or convert into png image-compressor ignores options...

I cant change image name or convert into png

I am using

const imageCompressor = new ImageCompressor();

imageCompressor.compress(file, {
          mimeType: 'image/jpeg',
          quality: 0.7,
          maxWidth: 1280,
          maxHeight: 900,
          checkOrientation: true,
          mimeType: 'image/jpeg',
})
  .then((result) => {
    result.name = 'specific-name.jpg';
    // ...
  });

The image I am trying is a 398 × 326 .png but always retuns as png image and name doesnt get changed either..

But it works on a .jpg image, and if I try to convert bigger .png image (1920 × 1200) it also works. Is seems really odd to me.

I have also tried convertSize: 1, in order to force convertion but with no luck..

Test image:

111111111111

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.