利用canvas中toDataURL()将图片转为dataURL(base64)的方法详解


Posted in Javascript onNovember 20, 2017

将图片转为base64的好处

将图片转换为Base64编码,可以让你很方便地在没有上传文件的条件下将图片插入其它的网页、编辑器中。 这对于一些小的图片是极为方便的,因为你不需要再去寻找一个保存图片的地方。

将图片转换成base64编码的,在web网上一般用于小图片上,不仅可以减少图片的请求数量(集合到js、css代码中),还可以防止因为一些相对路径等问题导致图片404错误。

引言

假设一个应用场景:由于某些特殊原因从服务端请求到图片路径,要求通过该路径获取对应图片的 base64 dataURL。在这个场景中,我们首先推断该图片路径是可访问的,同时还需要一种将图片转换到 dataURL 的方法。

我们如何实现它呢?

dataURL

先大致回顾下正统的 dataURL 的语法,这有助于我们检验转换后的内容是否正确。一个完整的 dataURI 应该是这样的:

data:[<mediatype>][;base64],<data>

其中mediatype声明了文件类型,遵循MIME规则,如“image/png”、“text/plain”;之后是编码类型,这里我们只涉及 base64;紧接着就是文件编码后的内容了。我们常常在 HTML 里看到img标签的src会这样写:

src="data:image/gif;base64,R0lGODdhMAAwAPAAAAAAAP///ywAAAAAMAAwAAAC8IyPqcvt3wCcDkiLc7C0qwyGHhSWpjQu5yqmCYsapyuvUUlvONmOZtfzgFzByTB10QgxOR0TqBQejhRNzOfkVJ+5YiUqrXF5Y5lKh/DeuNcP5yLWGsEbtLiOSpa/TPg7JpJHxyendzWTBfX0cxOnKPjgBzi4diinWGdkF8kjdfnycQZXZeYGejmJlZeGl9i2icVqaNVailT6F5iJ90m6mvuTS4OK05M0vDk0Q4XUtwvKOzrcd3iq9uisF81M1OIcR7lEewwcLp7tuNNkM3uNna3F2JQFo97Vriy/Xl4/f1cf5VWzXyym7PHhhx4dbgYKAAA7"

这个img引用的就是以 base64 编码的 dataURL 了,只要浏览器支持,就可以被解码成 gif 图片并渲染出来。

.toDataURL()

FileReader对象也有类似的方法,比如.readAsDataURL() ,然而它只接受file或blob类型,而这两种类型一般只能通过<input[type=file]>元素的files属性获取,或者用Blob()构造函数手工创建一个新的对象。尴尬的是我们当前只有图片路径,受制于浏览器的安全策略, <input[type=file]>的files属性是只读的,而Blob()构造函数只接受文件内容,两种方式都无法通过图片路径直接获取。上文中假设的应用场景迫使我们必先考虑如何通过路径获取到图片内容。<img>是可以的,并且可以被绘制到<canvas>中,而<canvas>正巧拥有.toDataURL()方法。

万事具备,我们只需要把<img>获取到的图片放到<canvas>里再通过.toDataURL()方法转化下,就可以得到以 base64 编码的 dataURL。来看这个方法的语法:

canvas.toDataURL([type, encoderOptions]);

canvas是DOM元素<canvas>对象;参数type指定图片类型,如果指定的类型不被支持则以默认值image/png替代;encoderOptions可以为image/jpeg或image/webp类型的图片设置图片质量,取值0-1,超出则以默认值0.92替代。

需要注意的是:在转换成 dataURL 前必须先确保图片成功加载到,于是.toDataURL()方法应该写在<img>的onload异步事件中。现在就来实现一个功能函数:

function getBase64(url){
  //通过构造函数来创建的 img 实例,在赋予 src 值后就会立刻下载图片,相比 createElement() 创建 <img> 省去了 append(),也就避免了文档冗余和污染
  var Img = new Image(),
   dataURL='';
  Img.src=url;
  Img.onload=function(){ //要先确保图片完整获取到,这是个异步事件
   var canvas = document.createElement("canvas"), //创建canvas元素
    width=Img.width, //确保canvas的尺寸和图片一样
    height=Img.height;
   canvas.width=width;
   canvas.height=height;
   canvas.getContext("2d").drawImage(Img,0,0,width,height); //将图片绘制到canvas中
   dataURL=canvas.toDataURL('image/jpeg'); //转换图片为dataURL
  };
 }

一个可供随时调用的转换函数完成了,它会在图片被加载后返回一整个 dataURL 字符串。

完善

onload事件确保了转换任务在加载后执行,却又带来了新问题——dataURL 只有在图片加载完成后才会返回,我们无法确定图片什么时候完成加载。如果后续要对 dataURL 做相关处理(比如传递到其他服务器)的话,添加一个回调是必要的,这能确保后续处理任务在成功得到 dataURL 之后执行,我们需要修改getBase64()

function getBase64(url,callback){ //添加一个回调参数
  ...
  Img.onload=function(){
   ...
   canvas.getContext("2d").drawImage(Img,0,0,width,height);
   dataURL=canvas.toDataURL('image/jpeg');
   callback?callback(dataURL):null; //调用回调函数
  };
 }

在执行时添加回调:

getBase64('//upload.jianshu.io/users/upload_avatars/555630/fdd1b798e6b0.jpg',(dataURL)=>{
  console.log(dataURL);
 });

就是这样,如果不考虑兼容性的话,或许我们可以用 promise 和 generator 来实现,再添加一些错误处理就更完美了。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
javascript入门·对象属性方法大总结
Oct 01 Javascript
JQuery上传插件Uploadify使用详解及错误处理
Apr 27 Javascript
IE6下出现JavaScript未结束的字符串常量错误的解决方法
Nov 21 Javascript
jquery+json实现动态商品内容展示的方法
Jan 14 Javascript
利用Angularjs和bootstrap实现购物车功能
Aug 31 Javascript
JS高仿抛物线加入购物车特效实现代码
Feb 20 Javascript
vue-cli项目中使用公用的提示弹层tips或加载loading组件实例详解
May 28 Javascript
mpvue写一个CPASS小程序的示例
Sep 04 Javascript
Vue.js特性Scoped Slots的浅析
Feb 20 Javascript
使用webpack将ES6转化ES5的实现方法
Oct 13 Javascript
在react中使用vue的状态管理的方法示例
May 02 Javascript
Element-ui树形控件el-tree自定义增删改和局部刷新及懒加载操作
Aug 31 Javascript
Node.js 中使用 async 函数的方法
Nov 20 #Javascript
利用three.js画一个3D立体的正方体示例代码
Nov 19 #Javascript
IE11下使用canvas.toDataURL报SecurityError错误的解决方法
Nov 19 #Javascript
使用DataTable插件实现异步加载数据
Nov 19 #Javascript
原生JavaScript实现Ajax异步请求
Nov 19 #Javascript
gulp安装以及打包合并的方法教程
Nov 19 #Javascript
js实现rem自动匹配计算font-size的示例
Nov 18 #Javascript
You might like
解析php二分法查找数组是否包含某一元素
2013/05/23 PHP
CI框架使用composer安装的依赖包步骤与方法分析
2016/11/21 PHP
浅谈laravel 5.6 安装 windows上使用composer的安装过程
2019/10/18 PHP
Laravel 实现添加多语言提示信息
2019/10/25 PHP
在第一个input框内输入内容.textarea自动得到第一个文件框的值的javascript代码
2007/04/20 Javascript
jQuery 解析xml文件
2009/08/09 Javascript
JavaScript高级程序设计(第3版)学习笔记12 js正则表达式
2012/10/11 Javascript
JQuery的read函数与js的onload不同方式实现
2013/03/18 Javascript
鼠标拖动实现DIV排序示例代码
2013/10/14 Javascript
jQuery超赞的评分插件(8款)
2015/08/20 Javascript
详解闭包解决jQuery中AJAX的外部变量问题
2017/02/22 Javascript
Vue弹出菜单功能的实现代码
2018/09/12 Javascript
vue3实现v-model原理详解
2019/10/09 Javascript
[56:45]DOTA2上海特级锦标赛D组小组赛#1 EG VS COL第一局
2016/02/28 DOTA
[43:18]NB vs Infamous 2019国际邀请赛淘汰赛 败者组 BO3 第一场 8.22
2019/09/05 DOTA
简单的Python抓taobao图片爬虫
2014/10/26 Python
Python中使用gzip模块压缩文件的简单教程
2015/04/08 Python
python模拟enum枚举类型的方法小结
2015/04/30 Python
Python爬虫代理IP池实现方法
2017/01/05 Python
Python使用回溯法子集树模板获取最长公共子序列(LCS)的方法
2017/09/08 Python
Python 图像处理: 生成二维高斯分布蒙版的实例
2019/07/04 Python
详解Python中字符串前“b”,“r”,“u”,“f”的作用
2019/12/18 Python
Python图像处理库PIL的ImageGrab模块介绍详解
2020/02/26 Python
python tkinter之 复选、文本、下拉的实现
2020/03/04 Python
基于Pyinstaller打包Python程序并压缩文件大小
2020/05/28 Python
北美三大旅游网站之一:Travelocity
2017/08/12 全球购物
复古服装:RetroStage
2019/05/10 全球购物
应用化学专业职业生涯规划书
2013/12/31 职场文书
大三预备党员入党思想汇报
2014/01/08 职场文书
市三好学生主要事迹
2014/01/28 职场文书
化工操作工岗位职责
2014/04/29 职场文书
孝敬父母的活动方案
2014/08/28 职场文书
2014年乡镇领导个人整改措施
2014/09/19 职场文书
python实现黄金分割法的示例代码
2021/04/28 Python
总结高并发下Nginx性能如何优化
2021/11/01 Servers
Nginx图片服务器配置之后图片访问404的问题解决
2022/03/21 Servers