前端 Canvas 导出带水印图片跨域问题

前端 Canvas 绘制跨域图片 (如第三方图片、CDN 图片、不同域名图片)并导出时,浏览器会触发Canvas 污染(tainted canvas) 安全限制,导致:

  • toDataURL() / toBlob() 直接报错
  • 无法导出图片、无法下载、无法上传

核心原因:Canvas 加载了未授权的跨域图片,浏览器禁止读取 / 导出画布内容。


一、根本原因(一句话)

图片域名 ≠ 你的网页域名,且图片服务器未开启跨域允许 + 前端未配置跨域加载 → Canvas 被标记为 "污染",禁止导出。

二、最简单、最通用的解决方案(前端 + 服务端 两步)

1. 前端代码:给图片添加跨域属性(必须)

javascript 复制代码
// 1. 创建图片对象
const img = new Image();

// 2. ✅ 关键:开启跨域加载(必须放在 src 赋值之前)
img.crossOrigin = 'anonymous'; 

// 3. 设置图片地址
img.src = 'https://第三方域名/你的图片.jpg';

// 4. 图片加载完成后绘制 Canvas
img.onload = function () {
  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d');
  
  canvas.width = img.width;
  canvas.height = img.height;
  
  // 绘制底图
  ctx.drawImage(img, 0, 0);
  
  // 绘制水印(文字/图片水印都可以)
  ctx.font = '24px Arial';
  ctx.fillStyle = 'rgba(255,255,255,0.5)';
  ctx.fillText('我的水印', 50, 50);

  // ✅ 现在可以正常导出,不会跨域报错
  const base64 = canvas.toDataURL('image/png'); 
  
  // 下载图片
  const a = document.createElement('a');
  a.href = base64;
  a.download = 'watermark.png';
  a.click();
};

2. 服务端配置:给图片资源开启跨域(必须)

必须让图片所在的服务器返回跨域头:

javascript 复制代码
Access-Control-Allow-Origin: *
常见服务器配置示例
Nginx
javascript 复制代码
location ~* \.(png|jpg|jpeg|gif|webp)$ {
    add_header Access-Control-Allow-Origin *;
}
CDN(阿里云 / 腾讯云 / 七牛云)

直接在控制台开启 跨域配置 CORS ,添加 * 或你的域名即可。

本地开发

使用本地图片 / 同域名图片,不会出现跨域。

三、如果服务端不改配置?(叼他)

让后端把图片返回 Base64 字符串,前端直接绘制 Base64,完全没有跨域。

javascript 复制代码
// 后端返回的 base64 字符串
const base64Img = 'data:image/png;base64,iVBORw0KGgo...';

const img = new Image();
img.src = base64Img; // 无跨域
img.onload = () => {
  ctx.drawImage(img, 0, 0);
  // 正常导出
};

总结

  1. 核心问题:跨域图片污染 Canvas,导致无法导出
  2. 标准方案:前端 crossOrigin="anonymous" + 服务端开启 CORS
  3. 服务端不可改:用 Base64 或 后端代理
  4. 避坑:crossOrigin 必须放在 src 之前
相关推荐
红尘散仙12 小时前
谁说终端只能敲键盘?我用 Rust 给小说阅读器加上了鼠标
前端·后端·rust
陈随易13 小时前
C++26 草案被否,二十八年来头一回
前端·后端·程序员
ZhengEnCi13 小时前
Agent 工具怎么折叠海量输出才「爽」:Trae、Claude Code 的渐进式披露设计原理
前端·agent
IT_陈寒16 小时前
Redis内存暴涨,没想到是AOF重写捣的鬼
前端·人工智能·后端
ikoala16 小时前
让 Codex 自己查账:一个省 token 的小技巧
前端·后端·ai编程
ikoala17 小时前
AI 写页面像说明书,修 Bug 像贴膏药?把这两句话写进 AGENTS.md
前端·javascript·ai编程
去伪存真19 小时前
AI Agent Harness 深度测评与技术选型实战
前端·agent
FRing031 天前
vue2干货总结7(自定义指令、插槽、单页应用程序、路由的使用(VueRouter))
开发语言·前端·vue.js·vue2
疯华整猫1 天前
被杀掉之后:我把 Android 的「唤起 + 常驻」重做了一遍
前端·面试·架构
IT_陈寒1 天前
Java开发实战:从入门到精通
前端·人工智能·后端