前端压缩图片上传方案

思路:

  1. 用H5 FileReader 获取图片,以DataURL的形式读入页面,获取图片的base64编码信息
  2. 用canvas对图片进行压缩处理(包括压缩,旋转)
  3. 把用canvas api toDataURL ,把canvas转换成base64图片编码

talk is cheap ,let s see the code

1. FileReader获取图片的base64编码信息

  $(document).on("change", "#upload-photo-pic", function (e) {

            var file = this.files[0];

            var fileReader=new FileReader();

          //将文件以Data URL形式读入页面

           fileReader.readAsDataURL(file);

            fileReader.onload = function(e) {

                var imageUrl=e.target.result;

          //  借用canvas对base64图片进行压缩

               canvasPress(imageUrl);

        }

}

2.用canvas对图片进行压缩处理(包括压缩,旋转)

用canvas对图片进行处理前,先要通过以下三个步骤读图进canvas

上传图片太大了,要压缩,当然压缩的不是画质,而是照片的宽度(现在用单反或手机拍的,大则10几M,宽度7000px左右),我这边根据我的实际使用场景,如果图片宽度大于1200px,则统一把图片压缩成宽为1200px的图,缩放后1200*1800的图片,大小为2.8M左右。具体操作:

if(image.width>maxWidth){

​ image.height*=maxWidth/image.width;

​ image.width=maxWidth;

}

本以为压缩下就万事大吉了,但是,并没有(要解决一个倒图问题):用iphone拍照的时候,你可能横着拍,也可能竖着拍,还可能倒着拍,不同的拍照方式照片的exif信息会记录不同的 Orientation,所以要把Orientation这个值取到(exif图片信息读取https://github.com/exif-js/exif-js/),然后根据这个值去旋转图片(旋转https://imququ.com/post/how-to-auto-rotate-photo-in-js.html)。 (在android手机拍的照片在测试中没有出现以上的倒图问题)。

canvas旋转也要稍微注意下,它并不是给他一个参数,说转多少就多少,拿到图片你就可以直接用,我用 rotate进行旋转,如 ctx.rotate(90Math.PI/180),由于坐标系也发生旋转,所以在画图的时候,**\y***相对来说要有-height的偏移,如

ctx.drawImage(image, 0, -image.height, image.width, image.height);

 function canvasPress(imgurl){

//        如果图片宽度超过maxWidth,则宽度缩放至maxWidth

        var maxWidth=1200;

        var image = new Image();

        image.onload = function(){

            var canvas=document.getElementById("canvas-press");

            var ctx = canvas.getContext("2d");

            ctx.clearRect(0, 0, canvas.width, canvas.height);

//            缩放

            if(image.width>maxWidth){

                image.height*=maxWidth/image.width;

                image.width=maxWidth;

            }

            EXIF.getData(this, function(){

                var orientation=EXIF.getTag(this, 'Orientation');

                    switch(orientation){

                        case 6://需要顺时针(向左)90度旋转

                            // 重置canvas宽高

                            canvas.width = image.height;

                            canvas.height = image.width;

                            ctx.rotate(90*Math.PI/180);

//                            由于坐标系也发生旋转,所以是下面这样写的

                            ctx.drawImage(image, 0, -image.height, image.width, image.height);

                            break;

                        case 8://需要逆时针(向右)90度旋转

                            // 重置canvas宽高

                            canvas.width = image.height;

                            canvas.height = image.width;

                            ctx.rotate(-90*Math.PI/180);

//                            由于坐标系也发生旋转,所以是下面这样写的

                            ctx.drawImage(image, -image.width,0, image.width, image.height);

                            break;

                        case 3:

                            // 重置canvas宽高

                            canvas.width = image.width;

                            canvas.height = image.height;

                            ctx.rotate(180*Math.PI/180);

//                            由于坐标系也发生旋转,所以是下面这样写的

                            ctx.drawImage(image, -image.width, -image.height, image.width, image.height);

                            break;

                        default:

                            console.log('默认');

                            // 重置canvas宽高

                            canvas.width = image.width;

                            canvas.height = image.height;

                            ctx.drawImage(image, 0, 0, image.width, image.height);

                            break;

                    }

                //接下去调用截图插件

                setCroperInfo(canvas.toDataURL());

            });

        }

        image.src = imgurl;

    }

3.把用canvas api toDataURL

canvas.toDataURL()就可以直接拿到处理完毕的base64编码图片啦,然后你就可以按照自己想要的方式继续对图片进行处理了。

我在我的使用场景中,之后又调用了cropper对图片进行裁剪,然后传给后端进行保存。