blob的理解与canvas压缩图片上传

Blob是什么?

HTML5中的Blob对象除了存放二进制数据外还可以设置这个数据的MINE类型,这相当于对文件的储存,其它很多二进制对象也是从这个对象继承的。

var data='<b id="content" style="font-size:32px;color:red;">次碳酸钴</b>';
var blob=new Blob([data],{"type":"text/html"})
console.log(blob)

打印结果

这样我们就创建了一个Blob对象,第一个参数是一个数组,也必须是一个数组,第二个参数是对这个Blol对象的配置属性,目前就一个type也就是相关的MIME需要设置。然后可以创建出一个URL来访问它,使用URL对象的createObjectURL方法

var data='<b id="content" style="font-size:32px;color:red;">次碳酸钴</b>';
        var blob=new Blob([data],{"type":"text/html"})
        console.log(blob)
        window.onload=function(){
            var iframe=document.createElement("iframe");
            iframe.src=URL.createObjectURL(blob);
            document.body.appendChild(iframe);
        };

然后页面的显示


<iframe src="blob:http://localhost:8080/ccbb2543-0b24-410a-914c-89c2ec655d77"></iframe>
<iframe>标签就是就是在页面中重新再开辟一个地方,插入新的html,src属性就是链接。

iframe 的优缺点

优点:

重载页面时不需要重载整个页面,只需要重载页面中的一个框架页(减少数据的传输,减少网页的加载时间);
技术简单,使用方便,主要应用于不需要搜索引擎来搜索的页面;
方便开发,减少代码的重复率(比如页面的header,footer);

缺点:

会产生很多的页面,不易于管理;
不易打印;
多框架的页面会增加服务气得http请求;
浏览器的后退按钮无效等;

而我bb这里多我其实就是想写用canvas压缩图片上传 上面部分是了解一下Blob,下面才是重点

canvas压缩图片的核心API就是利用canvasdrawImage()方法,API如下:

context.drawImage(img, dx, dy);
context.drawImage(img, dx, dy, dWidth, dHeight);//本文例子用到的参数设置
context.drawImage(img, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);

参数设置

对于本文例子的压缩 只需要用到五个参数。举个例子,一张图片(假设图片对象是img)的原始尺寸是40003000,现在需要把尺寸限制为400300大小,很简单,原理如下代码示意:

var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
canvas.width = 400;
canvas.height = 300;
// 核心JS就这个
context.drawImage(img,0,0,400,300);//意思就是 从左上角0 0开始绘制一个宽度为400高度为300的canvas

所以 canvas的代码写了,我们就需要处理图片来源和图片去向两个问题

1.如何把系统中的图片呈现到浏览器上?

HTML5 file API可以让图片在上传之前直接在浏览器中显示,通常使用FileReader方法,代码示意如下:

var reader = new FileReader(), img = new Image();
// 读文件成功的回调
reader.onload = function(e) {
  // e.target.result就是图片的base64地址信息
  img.src = e.target.result;
};
eleFile.addEventListener('change', function (event) {
    reader.readAsDataURL(event.target.files[0]);
});

此段代码写完,那么context.drawImage()里面的img就有啦

2.canvas只是一块画布,那么如何把转换成img显示呢?

canvas提供了两个2D转换为图片的方法:canvas.toDataURL()canvas.toBlob()

canvas.toDataURL()方法

canvas.toDataURL(mimeType, qualityArgument)
可以把图片转换成base64格式信息,纯字符的图片表示法。
mimeType表示canvas导出来的base64图片的类型,默认是png格式,也即是默认值是'image/png',我们也可以指定为jpg格式'image/jpeg'或者webp等格式。file对象中的file.type就是文件的mimeType类型,在转换时候正好可以直接拿来用(如果有file对象)。qualityArgument表示导出的图片质量,只要导出为jpgwebp格式的时候此参数才有效果,默认值是0.92,是一个比较合理的图片质量输出参数,通常情况下,我们无需再设定。

canvas.toBlob()方法

canvas.toBlob(callback, mimeType, qualityArgument)
这个方法相比之前的方法的好处是异步,所以有一个callback回调。这个callback回调方法默认的第一个参数就是转换好的blob文件信息,本文demo的文件上传就是将canvas图片转换成二进制的blob文件,然后再ajax上传的,代码如下:

// canvas转为blob并上传
canvas.toBlob(function (blob) {
  // 图片ajax上传
  var xhr = new XMLHttpRequest();
  // 开始上传
  xhr.open("POST", 'upload.php', true);
  xhr.send(blob);    
});

所以 压缩的三个步骤就是:图片-》canvas压缩-》图片
完整代码:

HTML代码
<div>
    <input id="file" type="file">
    <img src=""/>
 </div>
JS代码
$(document).ready(function(){
        var eleFile=document.getElementById('file');
        //压缩图片需要的一些元素和对象
        var reader=new FileReader(),img=new Image();

        //选择的文件对象
        var file=null;

        //缩放图片需要用到的canvas
        var canvas=document.createElement('canvas');
        var context=canvas.getContext('2d');

        //base64地址图片加载完毕后
        img.onload=function(){
            //图片的原始尺寸
            var originWidth=this.width;
            var originHeight=this.height;
            //最大尺度的尺寸限制在 400*400
            var maxWidth=400,maxHeight=400;
            //目标尺寸
            var targetWidth=originWidth,targetHeight=originHeight;
            if(originWidth>maxWidth||originHeight>maxHeight){//如果原始尺寸大于了设定的最大尺寸
                if (originWidth / originHeight > maxWidth / maxHeight) {//图片原本的宽高比例大于了设定的宽高比例
                    //大于规定的比例 证明 原始宽度大于高度 -》所以按照高度除以宽度的比例去缩放高度
                    targetWidth = maxWidth;
                    targetHeight = Math.round(maxWidth * (originHeight / originWidth));
                } else {
                    //小于则表明 原始高度大于原始宽度 -》所以按照宽度除以高度的比例去缩放宽度
                    targetHeight = maxHeight;
                    targetWidth = Math.round(maxHeight * (originWidth / originHeight));
                }
            }
            // canvas对图片进行缩放
            canvas.width = targetWidth;
            canvas.height = targetHeight;
            // 清除画布
            context.clearRect(0, 0, targetWidth, targetHeight);
            // 图片压缩
            context.drawImage(img, 0, 0, targetWidth, targetHeight);
            // canvas转为blob并上传
            canvas.toBlob(function (blob) {//blob将base64编码的src 以二进制的形式存进了 Blob对象
                $('img').attr('src',window.URL.createObjectURL(blob) )//这样可以在页面上形成一个预览的效果
                // $('img').attr('src',HTMLMediaElement.srcObject(blob))//这个方法是MDN说会替代上面的方法 但是我在浏览器中使用还不支持(什么鬼???)
                // 图片ajax上传-》将blob二进制数据上传上去
                console.log(blob)




            }, file.type || 'image/png');

        }
        // 文件base64化,以便获知图片原始尺寸
        reader.onload = function(e) {
            img.src = e.target.result;//base64编码的src
            //通过编码之后 
        };
        eleFile.addEventListener('change', function (event) {
            file = event.target.files[0];
            // 选择的文件是图片
            if (file.type.indexOf("image") == 0) {
                reader.readAsDataURL(file);
            }
        });
    });
这就是被压缩的图片,原图是1024*727的尺寸

所以总体的思路就是获取到上传的img,通过canvas压缩之后,再传给后台,压缩之后放在页面形成一个预览效果,也就是用到window.URL.createObjectURL(blob)方法。其中最为关键的就是 如果原始的宽度大于高度(就需要用高度除以宽度的比例来缩放高度),反之一样。

本文涉及的几个重要API

window.URL.createObjectURL()

静态方法会创建一个 DOMString,其中包含一个表示参数中给出的对象的URL。这个 URL 的生命周期和创建它的窗口中的 document 绑定。这个新的URL 对象表示指定的 File 对象或 Blob 对象。简单的理解就是,可以在页面上预览本地上传的图片或者视频(将blob对象直接赋值给vedio标签,而不是source

reader.readAsDataURL()

通过这个API可以从浏览器中异步访问文件系统中的数据,结果用data:url的字符串形式表示。因此,FileReader接口可以读取文件中的数据,并将读取的数据放入到内存中去。通过FileReader接口中的readAsDataURL()方法可以获取API异步读取的文件数据,另存为数据URL;将该URL绑定到img标签的src属性上,就可以实现图片的上传预览效果了。

new FileReader()

FileReader主要用于将文件内容读入内存,通过一系列异步接口,可以在主线程中访问本地文件。

参考地址:https://www.zhangxinxu.com/wordpress/2017/07/html5-canvas-image-compress-upload/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容