前端文件格式转换

Blob & File

BlobFile 都是是一个文件对象,File 在 Blob 的基础上进行了功能扩展,两者可以通过 new 实例的方式获取。

1
2
const blob = new Blob(blobParts, options);
const File = new File(fileBits, fileName, options)

在参数上,File 多了一个文件名的参数,另外在 options 里还多了一个可选的 lastModified 上次修改时间。

blob file

通过打印同一个图片的 Blob 和 File 更嫩直观的看出属性上的差异,另外还可以看到 File 继承了 Blob。

FileReader

读取文件对象的构造函数

1
const reader = new FileReader()

实例上有几个方法

  1. readAsDataURL(blob): 读取文件对象的内容,将内容用 data:URL 的形式表示,比较常用,例如读取图片文件复制给 img 的 src。
  2. readAsArrayBuffer(blob):将内容用 ArrayBuffer 的形式表示
  3. readAsText(blob):将内容用字符串形式表示
  4. abort(): 终止文件的读取

还有几个事件,也可以理解为读取文件的声明周期

  1. abort 终止时触发
  2. error 读取跑出错误触发
  3. load 读取成功触发
  4. loadend 读取完成时触发,无论成功还是失败
  5. loadstart 开始读取时触发
  6. progress 定期触发
1
2
3
4
5
const reader = new FileReader();
reader.onload = (res) => {
console.log(res);
};
reader.readAsDataURL(file);


可以看到使用 readAsDataURL 转换出的结果在 onload 事件入参的 target.result 属性

Base64

Base64 是将二进制转化成 ASCII 字符的编码方式

window.atob window.btoa

浏览器提供了两个方法用于 Base64 的编码和解码

URL.createObjectURL

URL 提供了一个静态方法 createObjectURL,通过该方法可以对象创建一个临时的 URL 用来访问,浏览器卸载时会自动释放这个 url,当然还可以通过 revokeObjectURL来手动卸载。

图片预览

1
2
3
const url = URL.createObjectURL(file);
window.open(url);
URL.revokeObjectURL(url);

通过 createObjectURL 给图片文件创建一个临时 url 然后在浏览器访问地址实现预览

下载

1
2
3
4
5
6
const url = URL.createObjectURL(file);
const a = document.createElement("a");
a.href = url;
a.download = "download.png";
a.click();
URL.revokeObjectURL(url);

实践

将 DOM 上的 svg 转换成各种格式文件

思路就是先拿到 DOM 节点,然后通过 XMLSerializer 的 serializeToString 方法将 DOM 节点转为 string

然后通过 window.btoa 进行编码,

拼接成 dataURL 的格式,就可以传给 image 的 src 了

通过 image 的加载使用 canvas 画图,借助 toBlob 方法就可以转成 Blob 的格式,Blob 再转换成 File 就非常简单了。

用以下代码需要有一个 svg

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
const svgNode = document.querySelector("svg");
const s = new XMLSerializer().serializeToString(svgNode);
// base64
const base64 = window.btoa(s)
// dataURL 格式
const encodedData = `data:image/svg+xml;base64,${base64}`;
const img = new Image();

img.onload = function () {
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
canvas.height = img.height;
canvas.width = img.width;
ctx.drawImage(img, 0, 0);
// Blog 格式
canvas.toBlob((blob) => {
// File 格式
const file = new File([blob], "image.png", { type: "image/png" });
console.log(file);
// 图片下载
const url = URL.createObjectURL(file);
const a = document.createElement("a");
a.download = "img.png";
a.href = url;
a.click();
});
};
img.src = encodedData;

修改上传图片的宽高

这个思路和上个差不多,区别在于拿到的是 File 格式文件,需要先使用 FileReader 读取,然后在 canvas 画图时要使用新的宽高,这样画出来的图才是新的宽高。

用以下代码需要有一个 type 为 file id 为 upload 的 input,一个 id 为 btn 的 button

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const newWidth = 200;
const newHeight = 200;
document.querySelector("#btn").addEventListener("click", () => {
const file = document.querySelector("#upload").files[0];
const reader = new FileReader();
const img = new Image();
reader.onload = (e) => {
img.src = e.target.result;
img.onload = () => {
const canvas = document.createElement("canvas");
canvas.width = newWidth;
canvas.height = newHeight;
const ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, newWidth, newHeight);
document.body.appendChild(canvas);
};
};
// 读取文件对象
reader.readAsDataURL(file);
});

canvas.drawImage

1
2
3
drawImage(image, dx, dy)
drawImage(image, dx, dy, dWidth, dHeight)
drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)

这个方法参数巨多,一般情况下只传三个就行了,但是遇到上文要修改图片宽高时,或者截取图片的某一部份时,其他参数就有作用了,下图来自MDN 可以很直观的看到各个参数的含义。


前端文件格式转换
https://l1ushun.github.io/2024/12/02/img-file/
作者
liu shun
发布于
2024年12月2日