Canvas压缩图片

117 阅读1分钟

笔者记录一下自己在项目中遇到的难题

不同的手机,拍照的图片大小不同,有的一张照片就是好几兆。对于一些后台来说,并不需要如此高质量的图片,这个时候,我们如果进行一个上传压缩,节省了带宽,加快了上传和反馈舒服,这就是一件双赢的事情。 上传图片,早些年使用flash,或者JavaScript实现,但是flash渐渐退出舞台,JavaScript运行的速度较慢且压缩效果不是特别明显,一般100kb,也只能压缩小10多kb。性价比较低。 h5中推出了Canvas天生就对图像有灵活处理的能力,故最终敲定使用js配合Canvas进行压缩图片,再上传服务器的方案。

  1. 先通过input拿到本地图片地址。
  2. 使用FileRead对象中的readAsDataURL读取图片的数据格式为base64,然后新建一个Img元素,让img的src属性指向图片的base64。
  3. 使用canvas对象中的drawImage(),对图片进行绘制
  4. 最后使用canvas对象中的toDataURL(),指定压缩图片为什么格式,指定图片的压缩质量。
  5. 直接上传服务器或转换为Blob格式再上传。

直接上代码:


    <input id="file" type="file">

    <script type="text/javascript">
        let fileDom = document.querySelector('#file');
        // 压缩图片需要的一些元素和对象
        let reader = new FileReader();
        //创建一个img对象
        let img = new Image();
        // 选择的文件对象
        let file = null;
        // 缩放图片需要的canvas
        let canvas = document.createElement('canvas');
        //指定绘制图像为2d
        let context = canvas.getContext('2d');
        // base64地址图片加载完毕后
        img.onload = function () {
            // 图片原始尺寸
            let originWidth = this.width;
            let originHeight = this.height;
            // 最大尺寸限制,可通过国设置宽高来实现图片压缩程度
            let maxWidth = 800;
            let maxHeight = 800;
            // 目标尺寸
            let targetWidth = originWidth;
            let targetHeight = originHeight;
            // 图片尺寸超过400x400的限制
            if (originWidth > maxWidth || originHeight > maxHeight) {
                if (originWidth / originHeight > maxWidth / maxHeight) {
                    // 更宽,按照宽度限定尺寸
                    targetWidth = maxWidth;
                    targetHeight = Math.round(maxWidth * (originHeight / originWidth));
                } else {
                    targetHeight = maxHeight;
                    targetWidth = Math.round(maxHeight * (originWidth / originHeight));
                }
            }
            // canvas对图片进行缩放
            canvas.width = targetWidth;
            canvas.height = targetHeight;
            // 清除画布
            context.clearRect(0, 0, targetWidth, targetHeight);
            // 图片压缩
            context.drawImage(img, 0, 0, targetWidth, targetHeight);
            /*第一个参数是创建的img对象;第二个参数是左上角坐标,后面两个是画布区域宽高*
            //压缩后的图片base64 url
            /*canvas.toDataURL(mimeType, quality),mimeType 默认值是'image/png';
              qualityArgument表示导出的图片质量,只要导出为jpg和webp格式的时候此参数才有效果,默认值是0.92
              我测试了一下,发现当quality的值为0.2到0.5时,可以保证图片的失真率比较小,且有明显的压缩图片的效果*/
            let newUrl = canvas.toDataURL('image/jpeg', 0.2);//base64 格式      
        };
        // 文件base64化,以便获知图片原始尺寸
        reader.onload = function (e) {
            img.src = e.target.result;
        };
        fileDom.addEventListener('change', function (event) {
            file = event.target.files[0];
            // 选择的文件是图片
            if (file.type.indexOf("image") == 0) {
                reader.readAsDataURL(file);
            }
        });
    </script>
</body>

一句话总结:canvas结合js重新描述 一个 2d 图片,然后给canvas画布进行等比例缩小或剪裁,并传入压缩质量参数来进行指定压缩。

base64转Blob格式

            // 获取blob对象
            let data = canvas.toDataURL('image/jpeg', 0.2)
            data = data.split(',')[1]
            data = window.atob(data)
            let ia = new Uint8Array(data.length)
            for (let i = 0; i < data.length; i++) {
                ia[i] = data.charCodeAt(i)
            }
            return new Blob([ia], {
                type: 'image/png'
            })
        }
        const blob = getBlob(canvas)
        // 生成和上传文件流
        const blobToFile = new window.File([blob], this.currentImage.fileName, {
            type: 'image/*'
        })