本文首发于:https://github.com/bigo-frontend/blog/ 欢迎关注、转载。
前言
先介绍一下js文件类型的知识点,后面要多次转换文件类型。
一.什么是Blob、File、DataURL
Blob 类型
Blob 类型是 File 文件类型的父类,它表示一个不可变、原始数据的类文件对象。
如何得到 blob 对象?
new Blob(array, options)
let hiBlob = new Blob([`<h1>Hi gauseen!<h1>`], { type: 'text/html' })
如上代码,就创建了一个 blob 对象,并声明了 text/html 类型 ,就像是创建一个 .html 文件。只不过它存在于浏览器的内存里。
File 类型
File 包含文件的相关信息,可以通过 js 来访问其内容
如何获取 file 对象?
1.new File(bits, name[, options])
// 1. 参数是字符串组成的数组
let hiFile = new File([`<h1>Hi gauseen!<h1>`], 'fileName', { type: 'text/html' })
// 2. blob 转 file 类型
let hiBlob = new Blob([`<h1>Hi gauseen!<h1>`], { type: 'text/html' })
let hiFile = new File([ hiBlob ], 'fileName', { type: 'text/html' })
如上代码,通过 File 构造函数,创建一个 file 对象,与上面的提到的 blob 类似。可以将 blob 转成 file 类型,这意味着上面获取的 blob,可以转成 file 类型。
2.inputElement.files
通过标签获取 file 对象
// input 上传文件时触发 change 事件
$('input').addEventListener('change', e => {
let file = e.target.files[0]
console.log('file: ', file)
})
3.DragEvent.dataTransfer.files
通过拖、放获取 file 对象
DataURL(base64)
DataURL,前缀为 data: 协议的 URL,可以存储一些小型数据
语法:data:[][;base64]
如下,黑色 1 像素示例:
data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=
上面提到的 Blob File 类型,如何“消费”它们呢?接着向下看
1.FileReader
允许 Web 应用程序异步读取存储在用户计算机上的文件(blob 或 file)。
// 将 blob 或 file 转成 DataURL(base64) 形式
fileReader(someFile).then(base64 => {
console.log('base64: ', base64)
})
function fileReader (blob) {
return new Promise((resolve, reject) => {
let reader = new FileReader()
reader.onload = (e) => {
resolve(e.target.result)
}
reader.readAsDataURL(blob)
})
}
2.convasElement.toDataURL()
可以通过 canvas 图像处理能力,将图片转成 dataURL 形式。在上面 Blob 部分讲解中,代码已实现。
二.DataURL、File、Blob互转
DataURL转Blob对象
// DataURL转Blob对象
export function dataURLToBlob(dataurl, mine = 'image/jpeg'): Blob {
const arr = dataurl.split(",");
const mimeType = mine || arr[0].match(/:(.*?);/)[1];
const bstr = atob(arr[1]);
let n = bstr.length;
const u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], { type: mimeType });
}
DataURL转File对象
// DataURL转File对象
function dataURLtoFile(dataurl, filename, mine = 'image/jpeg') {
const arr = dataurl.split(',');
const mimeType = mine || arr[0].match(/:(.*?);/)[1];
const bstr = atob(arr[1])
let n = bstr.length;
const u8arr = new Uint8Array(n);
while(n--){
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], filename, {type:mimeType});
}
更多转换方式:https://blog.csdn.net/hahahhahahahha123456/article/details/80605836
三.gif截取插件SuperGif
原理:图象标识符(Image Descriptor)
一个GIF文件内可以包含多幅图象,一幅图象结束之后紧接着下是一幅图象的标识符,图象标识符以0x2C(’’,’’)字符开始, 定义紧接着它的图象的性质,包括图象相对于逻辑屏幕边界的偏移量、图象大小以及有无局部颜色列表和颜色列表大小, 由10个字节组成
开源插件:https://github.com/buzzfeed/libgif-js
四.antd upload组件处理
项目框架使用了antd,故需要在上传回调时进行首帧截取。
upload组件回调参数返回File类型
- file转换为dataUrl
- 新建img实例接收dataUrl数据
- 初始化SuperGif实例
- 截取首帧图片,返回dataUrl数据
- dataUrl转换为file数据
- 返回给业务接口,上传图片
export function getGIFFirstFrame(file): Promise<File> {
return new Promise((resolve) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
const img = new Image();
// @ts-ignore
img.src = reader.result;
img.onload = () => {
// @ts-ignore
const rub = new SuperGif({ gif: img });
rub.load(function () {
if (rub.get_length() === 0) {
return;
}
// 获取gif实例的首帧
rub.move_to(0);
// canvas生成base64图片数据
const dataurl = rub.get_canvas().toDataURL("image/jpeg", 0.8);
const filename = file.name.replace('.gif', '.jpg');
resolve(dataURLtoFile(dataurl, filename));
return;
});
};
};
});
}
欢迎大家留言讨论,祝工作顺利、生活愉快!
我是bigo前端,下期见。