基础方法:canvas.toDataURL
将页面中已有的 <img> 元素转为 Base64:
function imgToBase64(img, type = 'image/png') {
const canvas = document.createElement('canvas');
canvas.width = img.naturalWidth;
canvas.height = img.naturalHeight;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
return canvas.toDataURL(type); // 'data:image/png;base64,...'
}
// 等待图片加载后调用
const img = document.querySelector('img');
img.onload = () => {
const base64 = imgToBase64(img);
console.log(base64);
};
// 图片已加载时直接调用
if (img.complete) {
const base64 = imgToBase64(img);
}
naturalWidth/naturalHeight 是图片的原始尺寸,避免取到 CSS 设置的显示尺寸。
跨域图片:crossOrigin=‘anonymous’
图片来自不同域名时,需要设置 crossOrigin 才能在 canvas 中使用:
async function urlToBase64(url) {
const img = new Image();
img.crossOrigin = 'anonymous';
img.src = url;
await new Promise((resolve, reject) => {
img.onload = resolve;
img.onerror = reject;
});
const canvas = document.createElement('canvas');
canvas.width = img.naturalWidth;
canvas.height = img.naturalHeight;
canvas.getContext('2d').drawImage(img, 0, 0);
return canvas.toDataURL('image/png');
}
服务端必须在响应头中返回 Access-Control-Allow-Origin: *,否则 canvas 被标记为”污染(tainted)“,调用 toDataURL() 会报错:
SecurityError: Failed to execute 'toDataURL' on 'HTMLCanvasElement':
Tainted canvases may not be exported.
跨域无 CORS 头:fetch + FileReader
当目标服务器没有设置 CORS 头时,可以走服务端代理,或在同源页面中用 fetch 请求(如果存在跨域会被拦截)。另一种方案是在已有权限的上下文(如油猴脚本设置 @grant GM_xmlhttpRequest)中绕过同源限制:
// 同源或有权限的上下文
async function urlToBase64ViaFetch(url) {
const res = await fetch(url);
const blob = await res.blob();
return new Promise((resolve) => {
const reader = new FileReader();
reader.onloadend = () => resolve(reader.result);
reader.readAsDataURL(blob);
});
}
指定输出格式和质量
canvas.toDataURL('image/png'); // PNG,无损
canvas.toDataURL('image/jpeg', 0.8); // JPEG,质量 80%
canvas.toDataURL('image/webp', 0.9); // WebP(非所有浏览器支持)
JPEG 不支持透明通道,带透明背景的图片转 JPEG 后透明部分会变黑,建议用 PNG。
