Search code examples
javascriptimagecross-browsercompression

How to compress an image via Javascript in the browser?


TL;DR;

Is there a way to compress an image (mostly jpeg, png and gif) directly browser-side, before uploading it ? I'm pretty sure JavaScript can do this, but I can't find a way to achieve it.


Here's the full scenario I would like to implement:

  • the user goes to my website, and choose an image via an input type="file" element,
  • this image is retrieved via JavaScript, we do some verification such as correct file format, maximum file size etc,
  • if every thing is OK, a preview of the image is displayed on the page,
  • the user can do some basic operations such as rotate the image by 90°/-90°, crop it following a pre-defined ratio, etc, or the user can upload another image and return to step 1,
  • when the user is satisfied, the edited image is then compressed and "saved" locally (not saved to a file, but in the browser memory/page),-
  • the user fill a form with data like name, age etc,
  • the user click on the "Finish" button, then the form containing datas + compressed image is sent to the server (without AJAX),

The full process up to the last step should be done client side, and should be compatible on latest Chrome and Firefox, Safari 5+ and IE 8+. If possible, only JavaScript should be used (but I'm pretty sure this is not possible).

I've not code anything right now, but I've thought about it already. File reading locally is possible via File API, image previewing and editing could be done using Canvas element, but I can't find a way to do the image compression part.

According to html5please.com and caniuse.com, supporting those browser is quite hard (thanks to IE), but could be done using polyfill such as FlashCanvas and FileReader.

Actually, the goal is to reduce file size, so I see image compression as a solution. But, I know that uploaded images are going to be displayed on my website, every time at the same place, and I know the dimension of this display area (eg. 200x400). So, I could resize the image to fit those dimensions, thus reducing file size. I have no idea what would be the compression ratio for this technique.

What do you think ? Do you have any advice to tell me ? Do you know any way to compress an image browser-side in JavaScript ? Thanks for your replies.


Solution

  • In short:

    1. Read the files using the HTML5 FileReader API with .readAsArrayBuffer
    2. Create a Blob with the file data and get its url with window.URL.createObjectURL(blob)
    3. Create new Image element and set it's src to the file blob url
    4. Send the image to the canvas. The canvas size is set to desired output size
    5. Get the scaled-down data back from canvas via canvas.toDataURL("image/jpeg",0.7) (set your own output format and quality)
    6. Attach new hidden inputs to the original form and transfer the dataURI images basically as normal text
    7. On backend, read the dataURI, decode from Base64, and save it

    Source: code.