> 위챗 애플릿 > 미니 프로그램 개발 > HTML5 이미지 압축 업로드 기능 심층 분석

HTML5 이미지 압축 업로드 기능 심층 분석

巴扎黑
풀어 주다: 2017-05-21 18:59:28
원래의
2518명이 탐색했습니다.

다음 편집기에서는 HTML5에서 구현된 이미지 압축 업로드 기능에 대한 심층적인 연구를 제공합니다. 편집자님이 꽤 좋다고 하셔서 지금 공유하고 싶습니다. 참고자료도 하나 드리고 싶습니다.

지난 글에서 모바일 단말기로 사진을 업로드하는 것은 지금도 꽤 비싼 것으로 알고 있습니다. 그리고 휴대폰의 픽셀은 점점 높아지고 있습니다. 사진 한 장에 몇 백만 달러가 들기 때문에 다칠 여유가 없습니다. 클라이언트는 쉽게 이미지를 압축한 다음 업로드할 수 있지만 애플리케이션이 여전히 브라우저에서 열릴 수 있습니다. PC에서의 이전 개발 사고 방식의 영향을 받아 Nima js가 어떻게 파일을 조작하고 이미지를 압축할 수 있는 권한을 가질 수 있습니까? 만약 그렇게 할 수 없다면 클라이언트에서 수정할 수 있습니까? 내가 말할 수 있는 것은 내가 아직도 약간 혼란스럽다는 것이다. HTML5의 영향으로 프론트 엔드는 점점 더 많은 일을 할 수 있게 되었고, 개발된 기능도 점점 더 높아지고 있습니다. H5 만세! 이것이 프론트엔드의 매력이기도 합니다. 과거에 불가능했다고 해서 지금도 불가능하지는 않습니다. 열심히 하세요, 사오니안!

js로 이미지를 압축하는 방법은 무엇인가요? ? ? 무의식적으로 처음에는 달성할 수 없다고 느꼈지만 나중에 정보를 읽고 조사한 결과 실현 가능하다는 것을 알게 되었습니다! 시작하세요!

H5 이전에는 어떻게 업로드했는지부터 먼저 말씀드리겠습니다. 평소에는 플러그인이나 플래시, 단순한 파일 형식을 사용했기 때문에 걱정이 덜하고 걱정이 더 많았습니다.

H5를 받은 이후로 상사는 더 이상 내 발전에 대해 걱정하지 않습니다.

지난 기사에서는 FileReader와 FormData를 사용하여 이미지를 업로드한다고 언급했습니다. 실제로 이 두 가지를 주로 사용하여 이미지를 미리 보고 업로드할 수 있습니다. 이미지 압축을 위해서는 캔버스를 사용해야 합니다. 바로 캔버스입니다!

일반적인 아이디어는 다음과 같습니다.

1. 그림과 캔버스 만들기


XML/HTML 코드클립보드에 콘텐츠 복사

  1. var image = new Image(),   
    canvas = document.createElement("canvas"),   
    ctx = canvas.getContext('2d');
    로그인 후 복사

2. FileReader를 통해 입력에서 선택한 이미지 주소를 얻어 새로 생성된 이미지 개체에 할당한 다음 이미지 개체를 캔버스에 던집니다.


XML/HTML 코드클립보드에 콘텐츠 복사

  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);
    로그인 후 복사

여기서 주의할 점은 캔버스가 캔버스에 이미지를 그릴 때 다음과 같이 캔버스의 크기를 결정하고 drawImage의 매개변수를 설정해야 한다는 점입니다.


XML/HTML 코드클립보드에 콘텐츠 복사

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

<span style="max-width:90%">dx<code><span style="font-family:NSimsun">dx</span>대상 캔버스의 X축에서 소스 이미지의 왼쪽 상단 모서리 위치입니다.

<span style="font-family:NSimsun">dy<code><span style="font-family:NSimsun">dy</span>Y-에서 소스 이미지의 왼쪽 상단 모서리 위치입니다. 대상 캔버스의 축.

<span style="font-family:NSimsun">dWidth<code><span style="font-family:NSimsun">dWidth</span>대상 캔버스에 그려지는 이미지의 너비입니다. 그려진 이미지의 크기를 조정할 수 있습니다. 지정하지 않으면 그릴 때 이미지 너비가 조정되지 않습니다.

<span style="font-family:NSimsun">dHeight<code><span style="font-family:NSimsun">dHeight</span>대상 캔버스에 그려지는 이미지의 높이입니다. 그려진 이미지의 크기를 조정할 수 있습니다. 지정하지 않으면 그림을 그릴 때 이미지 높이가 조정되지 않습니다.

<span style="font-family:NSimsun">sx<code><span style="font-family:NSimsun">sx</span>그림에 그려야 하는 소스 이미지의 직사각형 선택 상자 대상 컨텍스트 왼쪽 위 모서리의 X 좌표입니다.

<span style="font-family:NSimsun">sy<code><span style="font-family:NSimsun">sy</span>그림에 그려야 하는 소스 이미지의 직사각형 선택 상자 대상 컨텍스트 왼쪽 위 모서리의 Y 좌표입니다.

<span style="font-family:NSimsun">sWidth<code><span style="font-family:NSimsun">sWidth</span>그림에 그려야 하는 소스 이미지의 직사각형 선택 상자 대상 컨텍스트 너비. 지정하지 않으면 전체 직사각형은 좌표 sx 및 sy에서 시작하여 이미지의 오른쪽 하단 모서리에서 끝납니다.

<span style="font-family:NSimsun">sHeight<code><span style="font-family:NSimsun">sHeight</span>그림에 그려야 하는 소스 이미지의 직사각형 선택 상자 타겟 컨텍스트가 높습니다.

전체 이미지를 업로드하려면 dx, dy를 0으로 설정해야 하며, dWidth, dHeight를 원본 이미지의 너비와 높이로 설정해야 합니다. 이것이 원래 크기를 얻기 위해 이미지 객체가 다운로드될 때까지 기다려야 하는 이유입니다.

3. 사진 업로드


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)   
                    }   
    });
    로그인 후 복사

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

위 내용은 HTML5 이미지 압축 업로드 기능 심층 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿