JS将图片URL转base64
·
Yin灏
背景介绍
最近有个需求是将部分 DOM 生成图片上传到服务器,这里就直接用之前项目使用的 html-to-image。
然而,这次与上次不同的是有一个图片;其实,html-to-image 也支持了存在图片的 DOM 生成截图(embed-images)。
出现意外
不出意外的就该出意外了:
很容易理解,就是跨域了请求了。注意,这里本来之前使用 img 标签是能正常请求的,并且也不用加 crossorigin 属性。 在调用 html-to-image 中加上 mode: ’no-cors’依然不行。
进入正题吧
然后就想自己搞转 base64 吧,各种百度谷歌出来了
const image2Base64 = (url: string) =>
new Promise((resolve, reject) => {
if (!url) {
resolve("");
return;
}
const img = new Image();
img.crossOrigin = "anonymous";
img.src = url;
img.onload = () => {
const canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
const ctx = canvas.getContext("2d");
ctx?.drawImage(img, 0, 0);
const data = canvas.toDataURL();
resolve(data);
};
img.onerror = () => {
reject("");
};
});
特别需要注意的是:img 标签属性是 crossorigin,new Image 需使用 crossOrigin。 如果不设置 crossOrigin 会造成另一个问题:
在用 canvas 调用 toDataURL 方法中出错了。
然后又是各种百度谷歌,发现 MDN 有个权威又无语的解释:
提炼一下哈:指定 crossorigin 的图像,在 canvas 调用中不会出现 tainted 错误。
其实上面已经能解决大多数的问题了:
对,没猜错,事情没有绝对的,还是有个例的:
不知是这个图片服务器咋设置的,各种吧啦吧啦沟通也不给设置跨域白名单啥的,只能自己想办法了。
nodejs 中间层转
const http = require("http");
http.get(url, (res) => {
const chunks = [];
let size = 0;
res.on("data", (chunk) => {
chunks.push(chunk);
size += chunk.length;
});
res.on("end", () => {
const data = Buffer.concat(chunks, size);
const base64Data = data.toString("base64");
return base64Data;
});
});
结果,完美解决。
总结
- 使用 crossOrigin 能解决大多数情况
- 如果能在图片服务器加跨域白名单最好
- 终极大招就是 nodejs 转
- nodejs 弊端:对于图片无法使用 CDN,对服务器压力增大,慎用