二进制流图片转 base64 或 blob 地址
前不久做了一个在前端展示小程序二维码的需求,怎料后台给出的接口并没有返回图片 url 地址,而是直接以二进制流的形式返回了一张图片。
base64 编码
我们知道 img 标签的 src 属性通常接收的值是一个路径地址,既然没有路径那我们就考虑另外一种方法,即 base64 编码数据显示图片。
来分析一下我们要做到把二进制流转换成 base64 编码都需要做哪些事情:
一般情况下后台返回的响应数据类型是 json,现在我们需要通过 responseType:arraybuffer
指定二进制流对应的响应类型 arraybuffer
。
ArrayBuffer
本质上是类型化数组,它作为内存区域,可以存放多种类型的数据。但 ArrayBuffer
不能直接操作,而是要通过类型数组对象或 DataView
对象来操作,它们会将缓冲区中的数据表示为特定的格式,并通过这些格式来读写缓冲区的内容。这些类型数组对象我们称为“视图”。有以下类型:
Int8Array:8 位有符号整数,长度 1 个字节。
Uint8Array:8 位无符号整数,长度 1 个字节。
Int16Array:16 位有符号整数,长度 2 个字节。
Uint16Array:16 位无符号整数,长度 2 个字节。
Int32Array:32 位有符号整数,长度 4 个字节。
Uint32Array:32 位无符号整数,长度 4 个字节。
Float32Array:32 位浮点数,长度 4 个字节。
Float64Array:64 位浮点数,长度 8 个字节。
// 创建一个指向后台返回的二进制流的 Uint8 视图
new Uint8Array(response.data)
这里我们在二进制流上建立一个 Uint8 的视图来对接收到的二进制流进行操作,将其转化为字符串。这就到了 String.fromCharCode()
方法登场的时间了。
fromCharCode()
可接受一个指定的 Unicode
值,然后返回一个字符串。而其实上面得到的视图是一组字节数组,和一般的数组基本无异。之前有看到别人在处理视图转成字符串用了 reduce()
方法:
new Uint8Array(response.data).reduce((data, byte) => data + String.fromCharCode(byte), '')
利用了 reduce()
方法累加的作用将视图中的值一个一个的转成字符串然后拼接起来。 reduce()
方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。array.reduce(function(total, currentValue, currentIndex, arr), initialValue)
参数 | 描述 |
---|---|
total | 必需。初始值, 或者计算结束后的返回值。 |
currentValue | 必需。当前元素 |
currentIndex | 可选。当前元素的索引 |
arr | 可选。当前元素所属的数组对象 |
initialValue | 可选。传递给函数的初始值 |
但其实 fromCharCode()
可以同时接受多个 Unicode
值,利用 ES6 的 ...
扩展运算符可以将上面获得的类型化数组作为参数序列一次性将它们转化为字符串
String.fromCharCode(...new Uint8Array(response.data))
这样是不是优雅多了,现在我们已经得到了由初始的二进制流转化成的字符串,最后只要通过 btoa()
这个方法将字符串转化为 base64 编码的字符串再拼接在 data:image/jpeg;base64,
后面就可以放入 src 属性中使用了。
最终的完整处理方式如下:
let imgUrl = 'data:image/jpeg;base64,' + btoa(String.fromCharCode(...new Uint8Array(response.data)))
blob 对象
转来转去我们总算是如愿的得到了我们想要的结果,但是在隐约中仿佛想起见过 blob:***
这样的图片地址,研究了一下不禁大拍脑门,之前的实现过程真的是绕了好大的弯,其实只要简简单单的两个语句就可以轻松实现这个需求:
var blob = new Blob([response.data], {type: "image/jpeg"});
var imUrl = URL.createObjectURL(blob);
Blob 对象表示一个不可变、原始数据的类文件对象,是一个可以存储二进制文件的容器。
var blob = new Blob( array, options );
- array 是一个由 ArrayBuffer,ArrayBufferView,Blob,DOMString 等对象构成的 Array,或者其他类似对象的混合体,它将会被放进 Blob
- options 提供了一个 type 属性,代表了将会被放入到 blob 中的数组内容的 MIME 类型,默认为
""
后台给我们返回的数据刚好是 ArrayBuffer
,不用任何操作直接放进 Blob
对象,并指定图片 MIME
类型,我们就创建了一个存放这张图片的 Blob
对象,再通过 URL.createObjectURL()
方法创建一个指向 Blob
对象的 URL,就可以直接拿来用了。
结语
这一次的探究找寻到的两种解决方案虽然难易程度相差比较大,但是过程中学习到的知识点还是很多的。可能如果先知道了第二种方法也就不会花时间去了解第一种方法的实现原理了。所以,相信过程吧,总不会是白忙活的。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
上一篇: 对原型及原型链的简单理解
下一篇: 彻底找到 Tomcat 启动速度慢的元凶
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论