[Canvas] 手机拍照后,等比例压缩并上传图片

现在的手机拍照效果越来越好,随之而来的是图片大小的上升,动不动就几MB甚至十几MB,直接上传原图,速度慢容易上传失败,而且后台对请求体的大小也有限制,后续加载图片展示也会比较慢。

如果前端对图片进行压缩后上传,可以解决这些问题。下面函数实现了对图片的压缩,
原理是在画布上绘制缩放后的图片,最终从画布导出压缩后的图片。方法中有两处可以对图片进行压缩控制:一处是控制图片的缩放比;另一处是控制导出图片的质量。

一、控制导出图片的质量

html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JS图片压缩</title>
</head>
<body> 
<input type="file" accept="image/jpg,image/jpeg,image/png" name="file" onchange="selectImg(this)">
<br>
<img id="showImg" src="" alt="" width="">

<script src="js/jquery-3.3.1.min.js"></script>
<script>
    function selectImg(file) {
        if (!file.files || !file.files[0]) {
            return;
        }
        //定以一个读取文件的对象
        var reader = new FileReader();
        console.log("图片原始大小:" + file.files[0].size / 1024/1024 + "MB");
        reader.onload = function ($event) {
            //获取的是图片的base64代码
            var replaceSrc = $event.target.result;
            console.log(replaceSrc);//原本的Base64
            compressedImg(replaceSrc,function (base) {
                document.getElementById("showImg").src = base;
                console.log(base);//压缩后的Base64
                console.log("压缩后:" + base.length / 1024/1024 + "MB");
            });
            // 再将获取值赋给img标签
            $('#showImg').attr("src", replaceSrc);
        };
        reader.readAsDataURL(file.files[0]);
    }

    //图片压缩代码
    function compressedImg(src, callback) {
        var img = new Image();
        img.src = src;
        img.onload = function () {
            var that = this;
            // 默认按比例压缩
            var w = that.width,
                h = that.height;
            var quality = 0.7;  // 默认图片质量为0.7
            //生成canvas
            var canvas = document.createElement('canvas');
            var ctx = canvas.getContext('2d');
            // 创建属性节点
            var anw = document.createAttribute("width");
            anw.nodeValue = w;
            var anh = document.createAttribute("height");
            anh.nodeValue = h;
            canvas.setAttributeNode(anw);
            canvas.setAttributeNode(anh);
            ctx.drawImage(that, 0, 0, w, h);
            // quality值越小,所绘制出的图像越模糊
            var base64 = canvas.toDataURL('image/jpeg', quality);
            // 回调函数返回base64的值
            callback(base64);
        }
    }

</script> 
</body>
</html> 

二、控制图片的缩放比

 $("#idCardFront").on("change", function () {
            var file = document.getElementById("idCardFront");
            var src = app.getObjectURL(file.files[0]); //获取文件信息 
            console.log(file.files[0]); 
            app.idCardFrontLocal = src; 
            var reader = new FileReader();
            reader.readAsDataURL(file.files[0]);
            reader.onload = function () {
                var img = new Image();
                img.src = this.result;
                img.onload = function () {
                    $.showLoading();
                    var canvas = document.createElement('canvas');
                    context = canvas.getContext('2d');
                    var imageWidth = undefined;
                    var imageHeight = undefined;
                    if (img.width >= 4000) {
                        imageWidth = img.width / 6; //压缩后图片的大小
                        imageHeight = img.height / 6;
                    } else if (img.width >= 3000) {
                        imageWidth = img.width / 5; //压缩后图片的大小
                        imageHeight = img.height / 5;
                    } else if (img.width >= 2000) {
                        imageWidth = img.width / 3; //压缩后图片的大小
                        imageHeight = img.height / 3;
                    } else if (img.width >= 1000) {
                        imageWidth = img.width / 2; //压缩后图片的大小
                        imageHeight = img.height / 2;
                    } else {
                        imageWidth = img.width; //压缩后图片的大小
                        imageHeight = img.height;
                    }
                    data = '';
                    canvas.width = imageWidth
                    canvas.height = imageHeight
                    context.drawImage(img, 0, 0, imageWidth, imageHeight)
                    data = canvas.toDataURL('image/jpeg')
                    //压缩完成 
                    var uploadData = data.replace(/\r|\n/g, '')
                        .replace('data:image/jpg;base64,', '')
                        .replace('data:image/jpeg;base64,', '')
                        .replace('data:image/png;base64,', '');
                    var formData = new FormData();
                    formData.append("idCardFrontBase64", uploadData);
                    formData.append("xxdm", app.bmInfo.xxdm);
                    formData.append("sfzh", app.bmInfo.sfzh);
                    app.submit("./ajax/SignupHandler.ashx?action=UPLOADPIC&type=IDCARFRONT", formData);
                }
            };
        });

Vue项目中使用(控制导出图片的质量):

 compressImage(file,callback) {
	 var base64Code;
     var that=this;
     var reader = new FileReader();//定义一个读取文件的对象
     reader.readAsDataURL(file);//FileReader对象的readAsDataURL方法可以将读取到的文件编码成 Data URL
     reader.onload = function () {
         var img = new Image();
         img.src = this.result; 
         console.log(  img.src);
         console.log(that.getImgSize(img.src )+'KB');
         img.onload = function () {//必须等到图片load之后才能画到canvas中
             var canvas = document.createElement("canvas"),
                   context = canvas.getContext('2d');
             canvas.width = img.width;//定义画布的大小
             canvas.height = img.height;
             //拓展:如果要传文件
             // canvas.toBlob(function (blob) {     //用toBlob压缩图片
             //     console.log(blob);
             //     console.log('压缩后的图', blob.size);
             //     var newFile = new File([blob], file.name, { type: blob.type });//将压缩过后的图片转为文件,便于上传
             //     console.log(newFile);
             // });
             //在画布上绘制图像、画布或视频,绘制图像的某些部分,以及/或者增加或减少图像的尺寸
             context.drawImage(img, 0, 0, img.width, img.height);
             var quality=0.9;
             //quality为0-1 之间的数字,用于标识输出图片的质量,1 表示无损压缩
             //canvas.toDataURL("image/jpg",0.7)  
             base64Code= canvas.toDataURL('image/jpeg',quality); //画布保存 base64 编码内容
             // console.log(base64Code);
             return callback(base64Code); 
         }
     }
 },
uploaderChange1(e) {
	//点击上传控件
    console.log(e.target.files);
    var that = this;
    var src, url = window.URL || window.webkitURL || window.mozURL;
	//URL对象是硬盘(SD卡等)指向文件的一个路径,如果我们做文件上传的时候,想在没有上传服务器端的情况下看到上传图片的效果图的时候就可是以通过var url=window.URL.createObjectURL(obj.files[0]);
	//获得一个http格式的url路径,这个时候就可以设置到<img>中显示了。
	//window.webkitURL和window.URL是一样的,window.URL标准定义,window.webkitURL是webkit内核的实现(一般手机上就是使用这个),还有火狐等浏览器的实现
    var files = e.target.files;
     //拓展
    // if (url) {
    //     src = url.createObjectURL(files[0]);
    // } else {
    //     src = e.target.result;
    //     console.log(src);
    // } 
    // var reader = new FileReader(); 

    // reader.readAsDataURL(files[0]);
    // reader.onload = function (e) {
    //     base64Code = this.result; 
    //     that.xsz1=base64Code; 
    //     console.log(that.xsz1);
    // } 
    that.compressImage(files[0],function (base64Code) {
    //调用压缩方法,得到压缩后的base64
        console.log(base64Code);
      }); 
},

Vue项目中使用(控制导出图片的质量\控制图片的缩放比):

 /**
 * 压缩图片
 * @param file 输入图片
 * @returns  callback(base64Code)   返回压缩后的新图片base64Code
 */
compressImage(file,callback) {
     var base64Code;
     var that=this;
     var reader = new FileReader();//定义一个读取文件的对象
     reader.readAsDataURL(file);//FileReader对象的readAsDataURL方法可以将读取到的文件编码成 Data URL
     reader.onload = function () {
         var img = new Image();
         img.src = this.result; 
         console.log(  img.src);
         console.log(that.getImgSize(img.src )+'KB');
         img.onload = function () {//必须等到图片load之后才能画到canvas中
             var canvas = document.createElement("canvas"),
                 context = canvas.getContext('2d');
             // canvas.width = img.width;//定义画布的大小
             // canvas.height = img.height;
             // canvas.toBlob(function (blob) { //用toBlob压缩图片
             //     console.log(blob);
             //     console.log('压缩后的图', blob.size);
             //     var newFile = new File([blob], file.name, { type: blob.type });//将压缩过后的图片转为文件,便于上传
             //     console.log(newFile);
             // });
             
             //在画布上绘制图像、画布或视频,绘制图像的某些部分,以及/或者增加或减少图像的尺寸
             // context.drawImage(img, 0, 0, img.width, img.height); 
             var imageWidth = undefined;
             var imageHeight = undefined;
             if (img.width >= 4000) {
                 imageWidth = img.width / 6; //压缩后图片的大小
                 imageHeight = img.height / 6;
             } else if (img.width >= 3000) {
                 imageWidth = img.width / 5; //压缩后图片的大小
                 imageHeight = img.height / 5;
             } else if (img.width >= 2000) {
                 imageWidth = img.width / 3; //压缩后图片的大小
                 imageHeight = img.height / 3;
             } else if (img.width >= 1000) {
                 imageWidth = img.width / 2; //压缩后图片的大小
                 imageHeight = img.height / 2;
             } else {
                 imageWidth = img.width; //压缩后图片的大小
                 imageHeight = img.height;
             }
             canvas.width=imageWidth;
             canvas.height=imageHeight;
             context.drawImage(img,0,0,imageWidth,imageHeight);
             var quality=0.9;
             //quality为0-1 之间的数字,用于标识输出图片的质量,1 表示无损压缩
             //canvas.toDataURL("image/jpg",0.7)  
             base64Code= canvas.toDataURL('image/jpeg',quality); //画布保存 base64 编码内容
             // console.log(base64Code);
             return callback(base64Code); 
         }
     }
 },
uploaderChange1(e) { //  input change 事件
   console.log(e.target.files);
   var that = this;
   var src, url = window.URL || window.webkitURL || window.mozURL;
   var files = e.target.files; 
   that.compressImage(files[0],function (base64Code) {
   //调用压缩图片方法,callback中返回压缩后的base64Code,可赋值给预览<img :src="xsz1">,最后上传
       console.log(base64Code);
       that.xsz1=base64Code;
   }); 
},

拓展1:去掉base64Code的头部

 deleteBase64Head(base64url) {
  //获取base64Code,去掉头部  data:image/jpg;base64, 记得逗号!!
   var str = base64url.replace(/\r|\n/g, '').replace('data:image/jpg;base64,', '').replace('data:image/jpeg;base64,', '') .replace('data:image/bmp;base64,', '').replace('data:image/png;base64,', '');  
   return  str; 
},

拓展2:获取base64Code的大小

 getImgSize(base64url) {
   //获取base64图片大小,返回KB数字
    var str = base64url.replace('data:image/jpeg;base64,', ''); //这里根据自己上传图片的格式进行相应修改 
    var strLength = str.length;
    var fileLength = parseInt(strLength - (strLength / 8) * 2); 
    // 由字节转换为 KB
    var size = "";
    size = (fileLength / 1024).toFixed(2); //toFixed() 方法可把  Number 四舍五入为指定小数位数的数字。
    return parseInt(size); 
},

参考:
HTML5< canvas >参考手册
Canvas入门到高级详解(中)
input file图片压缩踩坑
前端canvas图片压缩原理解析
H5 和小程序拍照图片旋转、压缩和上传

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值