图片上传与预览及压缩

图片上传与预览及压缩

  介绍一下如何用input标签实现图片上传和在网页上实现图片预览,使用canvas的toDataURL()方法进行压缩以及把base64转化成二进制文件数据进行上传。
  可以点击这里看看效果。

  目录:


input标签

//html代码
<div class="image-warpper">
    <img id="preview-image" src="img/icon_add.png" class="hide">
    <input type="file" class="file-input" name="file-input" accept="image/gif,image/jpeg,image/jpg,image/png,image/svg" value="">
</div>

  这里用了img标签用于图片预览,使用input标签用于上传图片,所以将其 type 属性设置为“file”,设置其 accept 属性规定能够通过文件上传进行提交的文件类型,我们规定它能接受图片格式为 gif 、 jpeg 、 jpg 、 png 和 svg 的图片。

值得注意的是,一开始我 accept 属性设置为 “accept=”image/*”,因为这样可以不限制图像的格式,但是在实际使用中发现,这段代码在Chrome和Safari等Webkit浏览器下却出现了响应滞慢的问题,要等一段时间才能弹出文件选择对话框,所以就换成上面的写法,这样就解决了响应滞慢的问题。


美化图片上传样式

/* css代码(由Sass编译过来的) */
.image-warpper {
  position: relative;
  width: 100px;
  height: 100px;
  border: solid 1px #b3b3b3;
  -webkit-border-radius: 4px;
  -moz-border-radius: 4px;
  border-radius: 4px;
  margin: 0 auto;
  cursor: pointer;
  text-align: center;
  line-height: 130px;
  background: url(../img/icon_add.png) no-repeat;
  -webkit-background-size: 100%;
  -moz-background-size: 100%;
  background-size: 100%; }
  .image-warpper input {
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    z-index: 100;
    cursor: pointer;
    -webkit-appearance: none;
    -webkit-opacity: 0;
    -moz-opacity: 0;
    -o-opacity: 0;
    -ms-opacity: 0;
    opacity: 0;
    filter: alpha(opacity=0); }
  .image-warpper img {
    position: absolute;
    max-width: 100%;
    max-height: 100%;
    z-index: 10;
    top: 50%;
    left: 50%;
    -webkit-transform: translate(-50%, -50%);
    -moz-transform: translate(-50%, -50%);
    transform: translate(-50%, -50%); }

.hide {
  display: none; }

  不得不说html原来的input标签样式实现无法接受,所以我们可以把它设置为透明的。
  来看看效果吧。
  图片上传前:
  图片上传前的样式
  图片预览效果:
  图片预览效果图


为input标签绑定onchange事件

//js代码(使用jQuery)
$(".file-input").on("change", function(){
    //获取input标签的兄弟节点(用于图片预览)
    var $preview = $(this).siblings("img");
    //获取用户上传的图片
    var files = !!this.files ? this.files : [];

    //当没有上传图片或者浏览器不支持FileReader的时候
    if (!files.length || !window.FileReader) {
        //add your codes here...
        return false;
    };

    //当上传的文件格式是image的时候
    if (/image\/\w+/.test(files[0].type)){
        var reader = new FileReader();
        reader.readAsDataURL(files[0]);
        var fileType = files[0].type;
        reader.onloadend = function(){
            //实现预览
            //preview($preview, reader.result);
            //实现压缩
            //compress(reader.result, fileType);
        }

    }else{
        //当上传的文件不是图片的时候
        //add your codes here...
    }
});

  每次输入框发生改变的时候(即用户点击上传按钮),上传的图片会保存在input标签的“files”FileList文件列表对象里面,因为我们只上传了一张图片,所以上传的图片就是files的第一个元素(即files[0])。我们可以看一下files[0]到底是什么:
files[0]
  首先验证一下用户是否上传了图片和验证一下浏览器是否支持FileReader对象,不支持的话——是时候换一个浏览器了。

FileReader 对象允许Web应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 File 或 Blob 对象指定要读取的文件或数据。其中File对象可以是来自用户在一个元素上选择文件后返回的FileList对象.

  接着用正则表达式判断一下上传的文件的类型是否图片类型,如果是,则使用 FileReader 的 readAsDataURL() 方法读取图片。

该方法会读取指定的 Blob 或 File 对象,读取操作完成的时候,readyState 会变成已完成(DONE),并触发 loadend 事件,同时 result 属性将包含一个data:URL格式的字符串(base64编码)以表示所读取文件的内容。(关于FileReader对象的知识可以看看这里)。


实现图片预览

//js代码(使用jQuery)
function preview($preview, image){
    $preview.attr("src",image).show().removeClass("hide");
    $preview.closest('.image-warpper').css({'background':'#f5f5f5','border':'2px dashed #ccc'})
}

  预览图片其实很简单,把使用 FileReader 的 readAsDataURL() 方法获取到的 data:URL 格式的字符串当成参数传给 preview 函数(就是这里的“image”),然后赋值给 img 标签(这里的 $preview 节点)的 src 属性就可以了,然后使我们一开隐藏起来的用于预览 img 标签显示出来,再给最外层的 div 加点样式就大功告成了。

  • attr(name|properties|key,value|fn) 设置或返回被选元素的属性值。
  • show([speed,[easing],[fn]]) 显示隐藏的匹配元素。
  • removeClass([class|fn]) 从所有匹配的元素中删除全部或者指定的类。
  • closest(expr|object|element) 从元素本身开始,逐级向上级元素匹配,并返回最先匹配的元素。
  • css(name|pro|[,val|fn]) 访问和设置匹配元素的样式属性。

压缩图片

function compress(uncompressed, fileType){
    var image= new Image();
    image.src = uncompressed;
    image.onload = function(){
        var canvas = document.createElement('canvas');

        //如果图片大于四百万像素,计算压缩比并将大小压至400万以下
        var ratio;
        if ((ratio = this.width * this.height / 4000000)>1) {
            ratio = Math.sqrt(ratio);
            this.width /= ratio;
            this.height /= ratio;
        }else {
            ratio = 1;
        }

        canvas.width = this.width;
        canvas.height = this.height;

        var ctx = canvas.getContext('2d');
        ctx.drawImage(this, 0, 0, canvas.width, canvas.height);
        //压缩图片(压缩质量可以根据实际情况调整)
        var newImage = canvas.toDataURL(fileType, 0.8);

        //转化成二进制文件数据并存入 FormData
        var fd = new FormData();
        var blob = dataURItoBlob(newImage);
        fd.append('file', blob);
    }
}

    //base64 转 二进制文件
    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});
    }

  首先使用 canvasdrawImage(imageObject, x, y, width, height)方法在画布上绘制图片,值得注意的是, drawImage() 的第一个参数是一个 Image,而并不是直接传入图片的 src 。
  当 Image 对象加载完成之后,会触发 onload 事件,我们将在 onload 事件中绘制图片。
  在绘制图片之前我们首先对把超过400万,像素的图片压缩到400万像素以下,然后调用 drawImage() 方法绘制图片,绘制完图片之后,我们就可以压缩图片了。

因为在 IOS 中 canvas 的大小有限制,即如果 canvas 的大小大于大概五百万像素(即宽高乘积)的时候,不仅图片画不出来,其他什么东西也都是画不出来的,所以我们需要先把图片按比例压缩到400万像素以下。

  最后调用toDataURL(type, encoderOptions)方法对图片进行压缩,第一个参数是压缩的类型,第二个参数是图片的质量。
  但是它返回的依旧是一个 base64 编码的图片,所以我们还需要使用 dataURItoBlob 函数把它转化成二进制文件数据(当然,我们也可以直接上传base64编码的图片,即系直接上传 dataURI ),得到 Blob 对象之后我们就可以把它 append 进FormData 对象里面了,如果我们需要上传该图片,我们就可以使用 AjaxFormData 把图片 POST 到服务器端了。

  HTMLCanvasElement.toDataURL() 方法返回一个包含图片展示的 data URI ,在指定图片格式为 image/jpeg 或 image/webp的情况下,可以从 0 到 1 的区间内选择图片的质量。如果超出取值范围,将会使用默认值 0.92。其他参数会被忽略。(关于toDataURL()方法的知识可以看看这里
  Blob对象表示不可变的类似文件对象的原始数据,它能存储着大量的二进制数据。(关于Blob对象的知识可以看看这里
  利用 FormData 对象,我们可以通过 JavaScript 用一些键值对来模拟一系列表单控件,我们还可以使用 XMLHttpRequest 的 send() 方法来异步的提交表单。与普通的 Ajax 相比,使用 FormData 的最大优点就是我们可以异步上传二进制文件。(关于FormData对象的知识可以看看这里


不同压缩的图片质量之间的对比

  也许我们会怀疑 HTMLCanvasElement.toDataURL() 方法对图片的压缩是否有效果,或者压缩的程度能不能满足我们的需求,我们可以看看两者之间的对比。

canvas.toDataURL(fileType, 1);

  当图片质量(encoderOptions )赋值为1的时候,我们输出它:
  图片质量最佳时
  这时图片是这样的:
  最佳质量的图片

canvas.toDataURL(fileType, 0.1);

  然而,当图片质量赋值为0.1的时候,我们再次输出它:
  图片质量最差时
  这时的图片时这样的:
  最差质量的图片


  对比之后,我们可以看到图片的size明显变小,而且图片的清晰度明显下降了,所以通过HTMLCanvasElement.toDataURL() 方法的确能满足我们对图片进行压缩的要求。
  因此,在实际应用中,我们可以根据我们的需求调整图片质量(encoderOptions )的值来实现对图片的压缩。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值