Compress image using JavaScript directly from the browser

外包流浪者
• 阅读 1932

You might be working on a project which has an image upload feature that takes images from the user and uploads it to your storage server. Once you have implemented it then you start thinking of optimizing it, so different factors like the format, quality, resolution, size of the image etc… come into consideration.

Later you decide to compress the images to save your storage space, so you implement an image compression feature in the back-end. Now you have saved your storage space. Don’t stop there because you can optimize more, save more resources like bandwidth and CPU cycles. If you have a server with limited resources and has many tasks to run then you are just adding more CPU load.

What if you can save your storage space, bandwidth and reduce server load at the same time. Yes, it is possible, the answer is “Compression at the client side using JavaScript”. Now let’s implement it.

Take advantage of the HTML5 Canvas that is used to draw graphics on a web page. Canvas is just a container for your graphics, JavaScript is used to draw.

Steps

  • Create an instance of JavaScript FileReader API.

    const reader = new FileReader();
    
  • Read the input image using FileReader.

    reader.readAsDataURL(sourceImage);
    
  • Create an instance of Image.

    const img = new Image();
    
  • Set the result of the FileReader as source for the image.

    img.src = event.target.result;
    
  • Create a HTML5 Canvas element

    const elem = document.createElement('canvas');
    
  • Set the width and height of the canvas to match the new dimensions of the image.

    elem.width = width;
    elem.height = height;
    
  • Create an object that is used to draw graphics on the canvas.

    const ctx = elem.getContext('2d')
    

The getContext() method returns an object with the properties and methods required for drawing graphics on the canvas. The ‘2d‘ parameter limits us for drawing only 2D graphics.

  • Now draw the image on the canvas by specifying the position, width and height of the image.

ctx.drawImage(img, 0, 0, width, height);
Export the canvas as a blob or DataURL by specifying MIME type, image quality.

    const data = ctx.canvas.toDataURL(img, mime, quality);   

or

    ctx.canvas.toBlob((blob) => {
        console.log(blob); //output image as a blob
        const file = new File([blob], fileName, {
            type: mime,
            lastModified: Date.now()
        }); //output image as a file
    }, mime, quality);
    

mime is the “mime type” of the image, like ‘image/jpeg’, ‘image/png’ .

Value of quality ranges from 0 to 1. It is the quality of the output image. If you don’t specify the mime and quality in the toBlob() method then default quality will be set and the mime type will be ‘image/png’.

The final code

/*
<!-- HTML Part -->
<input id="file" type="file" accept="image/*">
<script>
    document.getElementById("file").addEventListener("change", function (event) {
    compress(event);
});
</script>
*/

compress(e) {
    const width = 500;
    const height = 300;
    const fileName = e.target.files[0].name;
    const reader = new FileReader();
    reader.readAsDataURL(e.target.files[0]);
    reader.onload = event => {
        const img = new Image();
        img.src = event.target.result;
        img.onload = () => {
                const elem = document.createElement('canvas');
                elem.width = width;
                elem.height = height;
                const ctx = elem.getContext('2d');
                // img.width and img.height will contain the original dimensions
                ctx.drawImage(img, 0, 0, width, height);
                ctx.canvas.toBlob((blob) => {
                    const file = new File([blob], fileName, {
                        type: 'image/jpeg',
                        lastModified: Date.now()
                    });
                }, 'image/jpeg', 1);
            },
            reader.onerror = error => console.log(error);
    };
}

Note:

If you want to maintain the aspect ratio of the output image then you can set either the width or height as constant and calculate the other dimension.

const width = 600;
const scaleFactor = width / img.width;
elem.width = width;
elem.height = img.height * scaleFactor;
ctx.drawImage(img, 0, 0, width, img.height * scaleFactor);

Here we kept width as constant and calculated the scaling factor. To find the relative height just multiply the scaling factor to the original height.

For browsers that don’t support “toBlob” method

Use this polyfill “https://developer.mozilla.org...” .

Modify the toBlob parameters as shown otherwise you will get “function expected” error.

//toBlob polyfill
if (!HTMLCanvasElement.prototype.toBlob) {
  Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', {
    value: function (callback, type, quality) {
      var dataURL = this.toDataURL(type, quality).split(',')[1];
      setTimeout(function() {
        var binStr = atob( dataURL ),
            len = binStr.length,
            arr = new Uint8Array(len);
        for (var i = 0; i < len; i++ ) {
          arr[i] = binStr.charCodeAt(i);
        }
        callback( new Blob( [arr], {type: type || 'image/png'} ) );
      });
    }
  });
}
// toBlob usage
ctx.canvas.toBlob(function (blob) {
 console.log(blob); //access blob here
 }, mimeType, quality);
点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Karen110 Karen110
3年前
一篇文章带你了解JavaScript日期
日期对象允许您使用日期(年、月、日、小时、分钟、秒和毫秒)。一、JavaScript的日期格式一个JavaScript日期可以写为一个字符串:ThuFeb02201909:59:51GMT0800(中国标准时间)或者是一个数字:1486000791164写数字的日期,指定的毫秒数自1970年1月1日00:00:00到现在。1\.显示日期使用
美凌格栋栋酱 美凌格栋栋酱
6个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
待兔 待兔
1年前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Stella981 Stella981
3年前
JavaScript的 基本数据类型
第一:Javascript对象是第二:Javascript中第三:Javascript的对象是数据;第四:JavaScript中的对象可以简单理解成"名称:值"对(name:value)。名称(name):"名称"部分是一个JavaScript字符串参考https://www
Wesley13 Wesley13
3年前
JS中有趣的知识
1.分号与换行functionfn1(){return{name:'javascript'};}functionfn2(){return{name:'javascript'
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Stella981 Stella981
3年前
HIVE 时间操作函数
日期函数UNIX时间戳转日期函数: from\_unixtime语法:   from\_unixtime(bigint unixtime\, string format\)返回值: string说明: 转化UNIX时间戳(从19700101 00:00:00 UTC到指定时间的秒数)到当前时区的时间格式举例:hive   selec
Python进阶者 Python进阶者
1年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这