千家信息网

web前端图片压缩、方向纠正、预览、上传插件的方法是什么

发表于:2025-01-16 作者:千家信息网编辑
千家信息网最后更新 2025年01月16日,这篇文章主要讲解了"web前端图片压缩、方向纠正、预览、上传插件的方法是什么",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"web前端图片压缩、方向纠正
千家信息网最后更新 2025年01月16日web前端图片压缩、方向纠正、预览、上传插件的方法是什么

这篇文章主要讲解了"web前端图片压缩、方向纠正、预览、上传插件的方法是什么",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"web前端图片压缩、方向纠正、预览、上传插件的方法是什么"吧!

实现原理

压缩图片并且上传主要用到filereader、canvas 以及 formdata 这三个h6的api和插件EXIF.js。逻辑并不难。整个过程就是:

(1)用户使用input file上传图片的时候,用filereader读取用户上传的图片数据(base64格式)
  (2)把图片数据传入img对象,然后将img绘制到canvas上,用EXIF.js对图片方向进行纠正,再调用canvas.toDataURL对图片进行压缩,获取到压缩后的base64格式图片数据,转成二进制
  (3)获取到压缩后的图片二进制数据,预览。
  (4)将压缩后的图片二进制数据塞入formdata,再通过XmlHttpRequest提交formdata

如此四步,就完成了图片的压缩、方向纠正、预览和上传。

插件设计思考

考虑到在实际项目中,可能用不同的开发框架(vue.js/JQ/react.js/angular.js/anu.js等),图片预览的UI样式也可能不同,图片数据上传方法可能不同。因为图片压缩和方向纠正这两块的逻辑多变性比较低,我们这里把图片压缩和方向纠正抽离出来,封装为一个插件库。

【一】获取图片数据

先是获取图片数据,也就是监听input file的change事件,然后获取到用来压缩上传的文件对象files,将files传到【图片压缩、方向纠正插件】中进行处理。

这时候根据每个人的需求,也可以预览未压缩的图片。

//监听上传组件input的onchange事件,压缩图片,纠正图片方向,同时获取压缩后的图片filechooser.onchange = function () {    var fileList = this.files;        //预览压缩前的图片    var files = Array.prototype.slice.call(fileList);    files.forEach(function (file, i) {        var reader = new FileReader();        reader.onload = function () {            var li = document.createElement("li")            li.style.backgroundImage = 'url('+this.result+')';            document.querySelector('.img_list').appendChild(li)        }        reader.readAsDataURL(file);    });    //处理图片列表,getCompressiveFileList接受处理后的图片数据列表    //下面两行代码为图片压缩、方向纠正插件的用法,具体实现细节请继续往下阅读 ~_~ ↓↓↓    var process = window.lzImgProcess();    process(fileList, getCompressiveFileList);}

【二】图片压缩、方向纠正插件实现

上面做完图片数据的获取后,就可以做process压缩图片的方法了。而压缩图片也并不是直接把图片绘制到canvas再调用一下toDataURL就行的。

在IOS中,canvas绘制图片是有两个限制的:

首先是图片的大小,如果图片的大小超过两百万像素,图片也是无法绘制到canvas上的,调用drawImage的时候不会报错,但是你用toDataURL获取图片数据的时候获取到的是空的图片数据。

再者就是canvas的大小有限制,如果canvas的大小大于大概五百万像素(即宽高乘积)的时候,不仅图片画不出来,其他什么东西也都是画不出来的。

应对上面两种限制,我把图片宽度、高度压缩控制在1000px以内,这样图片最大就不超过两百万像素了。在前端开发中,1000px*1000px基本可以满足绝大部分的需求了。当然了还有更完美的瓦片式绘制的方法,我们这里就说瓦片式绘制方法了。

如此一来就解决了IOS上的两种限制了。

除了上面所述的限制,还有两个坑,一个就是canvas的toDataURL是只能压缩jpg的(这句话的详细解释可以看下面的Tip讲解),当用户上传的图片是png的话,就需要转成jpg,也就是统一用canvas.toDataURL('image/jpeg', 0.5) , 类型统一设成jpeg,而压缩比就自己控制了。

另一个就是如果是png转jpg,绘制到canvas上的时候,canvas存在透明区域的话,当转成jpg的时候透明区域会变成黑色,因为canvas的透明像素默认为rgba(0,0,0,0),所以转成jpg就变成rgba(0,0,0,1)了,也就是透明背景会变成了黑色。解决办法就是绘制之前在canvas上铺一层白色的底色。

在压缩图片之前,我们判断图片角度,如果图片角度不正确,还需要用EXIF.js把图片角度纠正过来。

压缩完图片,把base64的图片数据转成二进制数据存储到暂存区中,等待被getBlobList获取使用。

Tip: canvas的toDataURL是只能压缩jpg这句话我可能说的不清楚,我想表达的意思是这个api无论是jpeg还是png,最后导出的时候,都跟jpeg没啥差别了。因为png图片的透明性质在canvas中是无效的,会被canvas添加默认的黑色背景,我在文中讲解的时候,用白色背景处理了,所以最后导出的图片,无论你设置的是png还是jpeg都跟jpeg没啥区别了,因为无法保持png的透明度性质了

(function(window) {    /**     *      * 作者:混沌传奇     *      * 邮箱地址:iot-pro_lizeng@foxmail.com     *      * 日期:2017-10-26     *      * 插件功能:压缩图片&&纠正图片方向&&返回二进制(Blob)图片元数据组成的列表     *      */    window.lzImgProcess = function () {        var Orientation = '', //图片方向角            blobList = [], //压缩后的二进制图片数据列表            canvas = document.createElement("canvas"), //用于压缩图片(纠正图片方向)的canvas            ctx = canvas.getContext('2d'),            file_type = 'image/jpeg', //图片类型            qlty = 0.5, //图片压缩品质,默认是0.5,可选范围是0-1的数字类型的值,可配置            imgWH = 1000; //压缩后的图片的最大宽度和高度,默认是1000px,可配置        /**         * @actionName process,          *        方法功能:压缩图片&&纠正图片方向&&返回二进制(Blob)图片元数据         *          * @param fileList,传入函数的文件列表对象,fileList对象是来自用户在一个元素上选择文件后返回的FileList对象         *        注意:图片类型必须是jpeg||png         *        比如:          *              function loadImageFile() {         *                //获取返回的fileList对象         *                var fileList = document.getElementById("uploadImage").files;         *              }         * @param getBlobList [Blob],获取压缩结果的钩子函数,接受一个参数。         *        功能:在图片压缩完毕后,获取压缩后的二进制图片数据对象组成的数组,参数即:压缩后的二进制图片数据(blob)组成的list         *                 * @param quality,传入函数的图片压缩比率(品质),可选范围0-1的数字类型的值,默认是0.5         *         * @param WH,传入函数的图片压缩后的最大图片宽度和高度,默认是1000,单位是px,可自由配置。         *        注意:最好不要超过1000,数字过大,容易导致canvas压缩失败。由于没做瓦片处理,所以有这个限制。1000*1000的图片在前端中,基本也够用了。         *                 */        function process (fileList, getBlobList, quality, WH) {            blobList = []; //初始化blobList            // 判断参数fileList的长度是否大于0            if (!fileList.length){                console.log('警告:传进方法process的参数fileList长度必须大于零!!!')                return;            }            //如果quality参数有值,则把quality赋值给qlty(图片压缩的品质)            if(quality)                qlty = quality;            //如果WH参数有值,则把WH赋值给imgWH(压缩后的图片的最大宽度和高度)            if(WH&&WH<1000&&WH>0){                imgWH = WH;            }            // 把传进来的fileList转为数组类型            var files = Array.prototype.slice.call(fileList);                        files.forEach(function (file, i) {                if (!/\/(?:jpeg|png)/i.test(file.type)){                    console.log('警告:图片必须是jpeg||png类型!!!');                    return;                }                // file_type = file.type;                                var reader = new FileReader();                // 获取图片压缩前大小,打印图片压缩前大小                var size = file.size/1024 > 1024 ? (~~(10*file.size/1024/1024))/10 + "MB" :  ~~(file.size/1024) + "KB";                // console.log('size:', size)                reader.onload = function () {                    var img = new Image();                    img.src = this.result;                    // 图片加载完毕之后进行压缩                    if (img.complete) {                        callback();                    } else {                        img.onload = callback;                    }                    function callback() {                        //获取照片方向角属性,用户旋转控制                          EXIF.getData(img, function() {                            // alert(EXIF.pretty(this));                            EXIF.getAllTags(this);                               // alert(EXIF.getTag(this, 'Orientation'));                            Orientation = EXIF.getTag(this, 'Orientation');                             console.log('Orientation:', Orientation)                            if(Orientation == ""||Orientation == undefined||Orientation == null){                                Orientation = 1;                            }                        });                        //获取压缩后的图片二进制数据                        var data = GetImgCompress(img);                        //将二进制数据塞入到二进制数据列表中                        blobList.push(data);                        //将压缩后的二进制图片数据对象(blob)组成的list通过钩子函数返回出去                        if(blobList.length===files.length){                            if(getBlobList)                                getBlobList(blobList);                        }                                                img = null;                    }                };                reader.readAsDataURL(file);            })        }        /**         * @actionName GetImgCompress,         *     功能:判断上传图片的方向,如果不是正确的,进行修正,并对图片进行压缩,压缩完后,返回压缩后的二进制图片数据         *              * @param img, 用来压缩的图片对象         *          * @returns 返回的压缩后的二进制图片数据         */        function GetImgCompress(img){            //如果方向角不为1,都需要进行旋转            if(Orientation != 1){                switch(Orientation){                    case 6://需要顺时针90度旋转                        rotateImg(img,'right',canvas);                        break;                    case 8://需要逆时针90度旋转                        rotateImg(img,'left',canvas);                        break;                    case 3://需要180度旋转                        rotateImg(img,'right2',canvas);//转两次                        break;                }            }else{                //不做旋转                rotateImg(img,'no',canvas);            }            var ndata;                        ndata = canvas.toDataURL(file_type, qlty);                        //打印压缩前后的大小,以及压缩比率            // var initSize = img.src.length;            // console.log('压缩前:' + initSize);            // console.log('压缩后:' + ndata.length, 'base64数据', ndata);            // console.log('压缩率:' + ~~(100 * (initSize - ndata.length) / initSize) + "%");            //将压缩后的base64数据转为二进制数据            ndata = dataURItoBlob(ndata);            //清除canvas画布的宽高            canvas.width = canvas.height = 0;                        return ndata;        }        /**         * @actionName rotateImg,         *     功能:对图片旋转处理         *              * @param img, 用来矫正方向的图片对象         *          * @param direction, 旋转方向         *         * @param canvas, 用来绘制图片的cavas画布对象         */        function rotateImg(img, direction,canvas) {                            //最小与最大旋转方向,图片旋转4次后回到原方向                var min_step = 0;            var max_step = 3;            if (img == null)return;                //img的高度和宽度不能在img元素隐藏后获取,否则会出错                var height = img.height;                var width = img.width;            if(width>imgWH || height>imgWH){                var ratio = ~~(height/width*10)/10;                if(width>height){                    width = imgWH;                    height = imgWH*ratio;                }else{                    height = imgWH;                    width = height/ratio;                }                img.width = width;                img.height = height;            }            var step = 2;                if (step == null) {                    step = min_step;                }            if (direction == 'no'){                step = 0;                } else if (direction == 'left') {                    step++;                    //旋转到原位置,即超过最大值                    step > max_step && (step = min_step);                } else if (direction == 'right') {                          step--;                    step < min_step && (step = max_step);                } else {                    //旋转180度            }            //旋转角度以弧度值为参数                var degree = step * 90 * Math.PI / 180;             switch (step) {                case 0:                    canvas.width = width;                        canvas.height = height;                       // 铺底色                    ctx.fillStyle = "#fff";                    ctx.fillRect(0, 0, width, height);                    ctx.drawImage(img, 0, 0, width, height);                       break;                    case 1:                    canvas.width = height;                        canvas.height = width;                       // 铺底色                    ctx.fillStyle = "#fff";                    ctx.fillRect(0, 0, height, width);                    ctx.rotate(degree);                        ctx.drawImage(img, 0, -height, width, height);                        break;                case 2:                    canvas.width = width;                        canvas.height = height;                       // 铺底色                    ctx.fillStyle = "#fff";                    ctx.fillRect(0, 0, width, height);                    ctx.rotate(degree);                        ctx.drawImage(img, -width, -height, width, height);                        break;                    case 3:                    canvas.width = height;                        canvas.height = width;                       // 铺底色                    ctx.fillStyle = "#fff";                    ctx.fillRect(0, 0, height, width);                    ctx.rotate(degree);                        ctx.drawImage(img, -width, 0, width, height);                        break;            }        }        /**         * dataURL to blob, ref to https://gist.github.com/fupslot/5015897         * @param dataURI,图片的base64格式数据         * @returns {Blob}         */        function dataURItoBlob(dataURI) {            var byteString = atob(dataURI.split(',')[1]);            var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];            var ab = new ArrayBuffer(byteString.length);            var ia = new Uint8Array(ab);            for (var i = 0; i < byteString.length; i++) {                ia[i] = byteString.charCodeAt(i);            }            return new Blob([ab], {type: mimeString});        }        /**         * 返回一个process方法         *          * process方法:用来压缩图片数据,在压缩图片的同时,默认会调用correctOrientation方法纠正图片方向。         *          */        return process;    }})(window)

Exif.js 提供了 JavaScript 读取图像的原始数据的功能扩展,例如:拍照方向、相机设备型号、拍摄时间、ISO 感光度、GPS 地理位置等数据。
Exif.js官方github 仓库地址: github.com/exif-js/exi…

【三】获取压缩后的图片二进制数据,预览图片

完成图片压缩后,就可以获取压缩后的图片二进制数据了,把获取到的图片二进制数据存起来;获取到数据后,可以拿来预览。

由于实际项目中,每个项目的UI样式设计可能不一样,开发者可以根据自己的UI样式来预览图片。

//获取压缩后的图片function getCompressiveFileList(fileList) {    blobFileList = fileList;    // console.log('fileBlobList:', fileList);    fileList.forEach(function (blob) {        var reader = new FileReader();        reader.onload = function () {            var li = document.createElement("LI")            li.style.backgroundImage = 'url('+this.result+')';            document.querySelector('.imgCompress_list').appendChild(li)        }        reader.readAsDataURL(blob);    })}

【四】提交图片数据到后台

new一个formdata对象,将上一步获取到的 blobFileList 图片二进制数据 append 到 formdata中,用任意你喜欢的ajax库进行上传。当然也可以用原生ajax上传。

//将压缩后的二进制图片数据流append到formdata对象中上传到后台服务器//注意:上传的是formdata对象,后台接口接收的时候,也要从formdata对象中读取二进制数据流function formUpData(blobFiles){    var formData = new FormData();    formData.append("files", blobFiles);        var xhr = new XMLHttpRequest();        //链接你自己上传图片接口即可,这里的接口地址,是我写的示例,不可真实使用,讲解意义更大    xhr.open('post', 'http://xxx/welcome/index/');    xhr.onreadystatechange = function () {        if (xhr.readyState == 4 && xhr.status == 200) {                console.log('上传成功!');        }    };    xhr.send(formData);}

感谢各位的阅读,以上就是"web前端图片压缩、方向纠正、预览、上传插件的方法是什么"的内容了,经过本文的学习后,相信大家对web前端图片压缩、方向纠正、预览、上传插件的方法是什么这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!

图片 数据 方向 二进制 对象 方法 插件 时候 参数 大小 类型 前端 最大 功能 就是 处理 限制 函数 宽度 底色 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 c 服务器集群 泰拉瑞亚免费的官方服务器 服务器密码忘记了如何进pe解锁 国家网络安全知识内容 flask取数据库平均数 医保网络安全管理制度有哪些 学软件开发就业怎么样 数据库和三级学的东西不一样 电脑dnf服务器不可用怎么办 沧州卓迅网络技术 流媒体服务器部署架构 聚焦五大 网络安全 黄山进销存软件开发平台 政府补助能从国泰安数据库获得吗 常态化网络安全宣传教育 服务器主频怎么估算 局域网怎么制作电影服务器 数据库表只取一条数据 幻塔无法连接服务器该如何解决 网络安全的话怎么画 新一代的IP网络技术的名称 公开肿瘤基因表达谱数据库 厚坤互联网科技有限公司 数据库项目设计说明书模板 流媒体服务器部署架构 增补数据存入数据库 日本网络技术发展 生死狙击2服务器下次开服时间 罗斯文2013数据库下载 山东省网络安全人才实训基地
0