Maison >Applet WeChat >Développement de mini-programmes >Analyse approfondie de la fonction de téléchargement de compression d'image HTML5

Analyse approfondie de la fonction de téléchargement de compression d'image HTML5

巴扎黑
巴扎黑original
2017-05-21 18:59:282556parcourir

L'éditeur suivant vous apportera une étude approfondie de la fonction de téléchargement de compression d'image implémentée en HTML5. L’éditeur pense que c’est plutôt bien, alors j’aimerais le partager avec vous maintenant. J'aimerais aussi vous donner une référence. Suivons l'éditeur et jetons un coup d'oeil

Dans le dernier article, nous évoquions le téléchargement de photos sur le terminal mobile. Nous savons que le trafic est encore assez cher maintenant, et les pixels des téléphones portables sont de plus en plus élevés. Une photo peut facilement coûter plusieurs M, donc je ne peux pas me permettre de me blesser. Bien que le client puisse facilement compresser les images puis les télécharger, notre application peut toujours être ouverte dans le navigateur. Que devons-nous faire ? Affecté par la pensée de développement précédente sur PC, Nima js n'a pas le pouvoir d'exploiter des fichiers et de compresser des images. Si cela ne peut pas être fait, votre client peut le réparer. Tout ce que je peux dire, c'est que je suis encore un peu confus. Sous l'influence du HTML5, le front-end peut faire de plus en plus de choses, et les fonctions développées sont de plus en plus performantes. Vive le H5 ! C'est aussi le charme du front-end. Ce qui était impossible dans le passé ne veut pas dire que c'est impossible maintenant ou dans le futur. Travaillez dur, Sao Nian !

Comment compresser des images avec js ? ? ? Inconsciemment, j'ai senti que c'était impossible à réaliser au début, mais plus tard, j'ai lu les informations et fait des recherches, et j'ai découvert que c'était faisable ! Commencez-le !

Parlons d'abord de la façon dont nous téléversions avant H5. Nous utilisions généralement des plug-ins, du flash ou simplement un formulaire de fichier, donc il y avait moins de soucis et plus de soucis.

Depuis que j'ai le H5, mon patron ne se soucie plus de mon évolution.

Le dernier article mentionnait que FileReader et FormData sont utilisés pour télécharger des images. En fait, nous pouvons essentiellement prévisualiser et télécharger des images principalement en utilisant ces deux-là. Pour réaliser la compression d'image, nous devons utiliser du canevas, oui, c'est du canevas !

L'idée générale est :

1. Créer une image et une toile


Code XML/HTMLCopier le contenu dans le presse-papiers

  1. var image = new Image(),   
    canvas = document.createElement("canvas"),   
    ctx = canvas.getContext('2d');

2. Nous obtenons l'adresse de l'image sélectionnée dans l'entrée via FileReader et l'attribuons à l'objet image nouvellement créé, puis jetons l'objet image sur le canevas.


Code XML/HTMLCopier le contenu dans le presse-papiers

  1. var file = obj.files[0];   
                            var reader = new FileReader();//读取客户端上的文件   
                            reader.onload = function() {   
                                var url = reader.result;//读取到的文件内容.这个属性只在读取操作完成之后才有效,并且数据的格式取决于读取操作是由哪个方法发起的.所以必须使用reader.onload,   
                                image.src=url;//reader读取的文件内容是base64,利用这个url就能实现上传前预览图片   
                                ...   
                            };   
                            image.onload = function() {   
                                var w = image.naturalWidth,   
                                    h = image.naturalHeight;   
                                canvas.width = w;   
                                canvas.height = h;   
                                ctx.drawImage(image, 0, 0, w, h, 0, 0, w, h);   
                                fileUpload();   
                            };   
                            reader.readAsDataURL(file);

Ce qu'il faut noter ici, c'est que lorsque Canvas dessine une image sur la toile, vous devez déterminer la taille de la toile et définir les paramètres de drawImage, comme suit :


Code XML/HTMLCopier le contenu dans le presse-papiers

  1. void ctx.drawImage( image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);

<span style="font -family:NSimsun">dx<code><span style="font-family:NSimsun">dx</span>La position du coin supérieur gauche de l'image source sur l'axe X du canevas cible.

<span style="font-family:NSimsun">dy<code><span style="font-family:NSimsun">dy</span>La position du coin supérieur gauche de l'image source sur le Y- axe du canevas cible.

<span style="font-family:NSimsun">dWidth<code><span style="font-family:NSimsun">dWidth</span>La largeur de l'image dessinée sur le canevas cible. Permet la mise à l'échelle des images dessinées. Si elle n’est pas spécifiée, la largeur de l’image ne sera pas mise à l’échelle lors du dessin.

<span style="font-family:NSimsun">dHeight<code><span style="font-family:NSimsun">dHeight</span>La hauteur de l'image dessinée sur la toile cible. Permet la mise à l'échelle des images dessinées. Si elle n’est pas spécifiée, la hauteur de l’image ne sera pas mise à l’échelle lors du dessin.

<span style="font-family:NSimsun">sx<code><span style="font-family:NSimsun">sx</span>La boîte de sélection rectangulaire de l'image source qui doit être dessinée dans le contexte cible La coordonnée X du coin supérieur gauche.

<span style="font-family:NSimsun">sy<code><span style="font-family:NSimsun">sy</span>La boîte de sélection rectangulaire de l'image source qui doit être dessinée dans le contexte cible La coordonnée Y du coin supérieur gauche.

<span style="font-family:NSimsun">sWidth<code><span style="font-family:NSimsun">sWidth</span>La zone de sélection rectangulaire de l'image source qui doit être dessinée dans le largeur du contexte cible. S'il n'est pas spécifié, le rectangle entier commence aux coordonnées sx et sy et se termine dans le coin inférieur droit de l'image.

<span style="font-family:NSimsun">sHeight<code><span style="font-family:NSimsun">sHeight</span>La zone de sélection rectangulaire de l'image source qui doit être dessinée dans le contexte cible élevé.

Pour télécharger l'image complète, dx, dy doivent être définis sur 0, et dWidth et dHeight doivent être définis sur la largeur et la hauteur de l'image originale. C'est pourquoi nous devons attendre que l'objet image soit téléchargé pour retrouver sa taille d'origine. C'est critique !

3. Téléchargement de photos


XML/HTML Code复制内容到剪贴板

  1. function fileUpload() {   
         var data = canvas.toDataURL("image/jpeg", quality);   
         //dataURL 的格式为 “data:image/png;base64,****”,逗号之前都是一些说明性的文字,我们只需要逗号之后的就行了   
        datadata = data.split(&#39;,&#39;)[1];   
        data = window.atob(data);   
        var ia = new Uint8Array(data.length);   
        for (var i = 0; i < data.length; i++) {   
              ia[i] = data.charCodeAt(i);   
        };   
         //canvas.toDataURL 返回的默认格式就是 image/png   
        var blob = new Blob([ia], {   
         type: "image/jpeg"   
        });   
        var fd = new FormData();   
            fd.append(&#39;myFile&#39;, blob);   
        var xhr = new XMLHttpRequest();   
        xhr.addEventListener("load", opts.success, false);   
        xhr.addEventListener("error", opts.error, false);   
        xhr.open("POST", opts.url);   
        xhr.send(fd);   
     }

这里用的关键方法是canvas.toDataURL


XML/HTML Code复制内容到剪贴板

  1. canvas.toDataURL(type, encoderOptions);  

官方的说明是The <span style="font-family:NSimsun">HTMLCanvasElement.toDataURL()</span> method returns a data URI containing a representation of the image in the format specified by the <span style="font-family:NSimsun">type</span> parameter (defaults to PNG). The returned image is in a resolution of 96 dpi.实际上就是读取canvas画布上图片的数据。其默认是png格式,如果第一个参数type是image/jpeg的话,第二个参数encoderOptions就可以用来设置图片的压缩质量,经过测试,如果是png格式,100%的宽高经过该方法还有可能使图片变大~~~~适得其反,所以我们可以在canvas.drawImage的时候适当设置sWidth和sHeight,比如同比例缩小1.5倍等,图片质量其实并不太影响查看,尤其对尺寸比较大的图片来说。

上面还有比较陌生的方法atob,其作用是做解码,因为图片格式的base64.


XML/HTML Code复制内容到剪贴板

  1. var encodedData = window.btoa("Hello, world"); // encode a string   

  2. var decodedData = window.atob(encodedData); // decode the string  

该方法解码出来可能是一堆乱码,Uint8Array返回的是8进制整型数组。

Blob是存储二进制文件的容器,典型的Blob对象是一个图片或者声音文件,其默认是PNG格式。


XML/HTML Code复制内容到剪贴板

  1. var blob = new Blob([ia], {   

  2.      type: "image/jpeg"   

  3.     });  

最后通过ajax将Blob对象发送到server即可。

整个流程大致如上,但是~~~实现以后测试跑来说:“你不是说图片压缩了吗,为什么图片还是上传那么慢!”,哥拿起手机对妹纸演示了一下,明明很快嘛,于是反道“是你手机不行或者网络不好吧,你下载图片看明明变小了,比之前肯定快,你看我秒传”。呵呵,说归说,还是偷偷检查代码,在浏览器中打时间log,对比没压缩之前的,尼玛!!!居然才快了几百毫秒!!折腾了半天,之前的代码也重构了,玩我呢。

细心的大神看了上面的代码估计能猜出问题在哪,没错,获取本地图片长宽尺寸的时候出了问题。

我去,获取本地4M大小的图片尺寸花了3174ms!!,图片越大时间也越久~


JavaScript Code复制内容到剪贴板

  1. image.onload = function() {   
            var w = image.naturalWidth,   
              h = image.naturalHeight;   
            canvas.width = w / 1.5;   
            canvas.height = h / 1.5;   
            ctx.drawImage(image, 0, 0, w, h, 0, 0, w / 1.5, h / 1.5);   
            Upload.fileUpload(type);   
    };

浏览器在本地取图片的时候是没法直接像file.size一样获取其长宽的,只能通过FileReader拿到内容后赋值给新建的image对象,新建的image对象下载需要时间!怎么破?不就是获取本地图片的尺寸吗,难道没有别的办法了?

于是想到了之前研究过的快速获取图片长宽的博文,点击进入 ,demo地址:http://jsbin.com/jivugadure/edit?html,js,output,定时去查询图片加载过程中的高度或者宽度,不用等整个图片加载完毕。

测了下,还是不行,因为定时查询这种方法对常规的server返回的图片有作用,这里图片地址是base64,貌似时间还更久了~哭。


小结一下:

1、用HTML5来压缩图片上传是可行的,在移动端我们不用依赖客户端或者插件,目前主流浏览器支持程度已经很高了。

2、压缩图片一方面是想减少用户上传等待的时间,另外也减少用户为此牺牲的流量,从整体时间来看,因为获取图片尺寸导致多一次下载需要耗时,其实压不压缩时间差别并不是特别大。除非大神们找到合适的方法能够直接获取图片的尺寸,麻烦也告知我一声,万分感谢;

3、既然时间成本差不多,但是我们压缩了图片,减少了图片的大小,减少了流量的消耗,存储空间以及下次获取该图片的时间,所以还是值得的。

 补充源代码:


JavaScript Code复制内容到剪贴板

  1. (function($) {   
        $.extend($.fn, {   
            fileUpload: function(opts) {   
                this.each(function() {   
                    var $self = $(this);   
                    var quality = opts.quality ? opts.quality / 100 : 0.2;   
                    var dom = {   
                        "fileToUpload": $self.find(".fileToUpload"),   
                        "thumb": $self.find(".thumb"),   
                        "progress": $self.find(".upload-progress")   
                    };   
                    var image = new Image(),   
                        canvas = document.createElement("canvas"),   
                        ctx = canvas.getContext(&#39;2d&#39;);   
                    var funs = {   
                        setImageUrl: function(url) {   
                            image.src = url;   
                        },   
                        bindEvent: function() {   
                            console.log(dom.fileToUpload)   
                            dom.fileToUpload.on("change", function() {   
                                funs.fileSelect(this);   
                            });   
                        },   
                        fileSelect: function(obj) {   
                            var file = obj.files[0];   
                            var reader = new FileReader();   
                            reader.onload = function() {   
                                var url = reader.result;   
                                funs.setImageUrl(url);   
                                dom.thumb.html(image);   
                            };   
                            image.onload = function() {   
                                var w = image.naturalWidth,   
                                    h = image.naturalHeight;   
                                canvas.width = w;   
                                canvas.height = h;   
                                ctx.drawImage(image, 0, 0, w, h, 0, 0, w, h);   
                                funs.fileUpload();   
                            };   
                            reader.readAsDataURL(file);   
                        },   
                        fileUpload: function() {   
                            var data = canvas.toDataURL("image/jpeg", quality);   
                            //dataURL 的格式为 “data:image/png;base64,****”,逗号之前都是一些说明性的文字,我们只需要逗号之后的就行了 
                            data = data.split(&#39;,&#39;)[1];   
                            data = window.atob(data);   
                            var ia = new Uint8Array(data.length);   
                            for (var i = 0; i < data.length; i++) {   
                                ia[i] = data.charCodeAt(i);   
                            };   
                            //canvas.toDataURL 返回的默认格式就是 image/png 
                            var blob = new Blob([ia], {   
                                type: "image/jpeg"
                            });   
                            var fd = new FormData();   
                            fd.append(&#39;myFile&#39;, blob);   
                            var xhr = new XMLHttpRequest();   
                            xhr.addEventListener("load", opts.success, false);   
                            xhr.addEventListener("error", opts.error, false);   
                            xhr.open("POST", opts.url);   
                            xhr.send(fd);   
                        }   
                    };   
                    funs.bindEvent();   
                });   
            }   
        });   
    })(Zepto);

调用方式:


JavaScript Code复制内容到剪贴板

  1. $(".fileUpload").fileUpload({   
                    "url": "savetofile.php",   
                    "file": "myFile",   
                    "success":function(evt){   
                        console.log(evt.target.responseText)   
                    }   
    });

希望大家能找到更好的办法,多多交流!感谢!

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn