上传前加水印必须在浏览器端用canvas处理原始file/blob:先用filereader转base64,再用image加载并监听onload获取尺寸,绘制倾斜水印后通过canvas.toblob生成新blob,最后用new file包装为带原名和类型的file对象供上传。

上传前加水印,只能靠 JavaScript 在浏览器端用 Canvas 处理原始文件对象,不能依赖 img.src 或 DOM 渲染后的图片——因为那时文件还没发出去,你得在 File 或 Blob 阶段就完成绘制并生成新文件。
用 FileReader + Canvas 读取并绘制水印
用户选中文件后,不能直接把 input.files[0] 发给后端,得先转成 Image 对象,再画到 Canvas 上,最后导出为带水印的 Blob。关键点是必须等图片加载完成才能获取尺寸和绘图,否则 naturalWidth 是 0。
-
FileReader.readAsDataURL()读取后需用new Image()解析,不能跳过 onload - 水印文字建议用
ctx.rotate()倾斜 -30° 左右,避免遮挡主视觉区 - 字体大小推荐用
Math.max(24, canvas.width * 0.05)动态适配,防止小图上文字糊成一团 - 导出时用
canvas.toBlob(callback, 'image/jpeg', 0.9)比toDataURL()更省内存,尤其大图
img.crossOrigin 在上传前根本不用设
本地选中的 File 对象没有跨域问题,img.src = URL.createObjectURL(file) 加载的是 blob URL,不是远程地址,所以 img.crossOrigin = 'anonymous' 不仅无效,还可能触发控制台警告。只有当你要加载 https://xxx.com/a.jpg 这类外部链接时才需要它。
- 错误写法:
img.crossOrigin = 'anonymous'; img.src = URL.createObjectURL(file); - 正确顺序:先
URL.createObjectURL(file),再赋值给img.src,不设 crossOrigin - 如果后续还要支持“粘贴图片”或拖拽远程图片,那才要分场景加判断
生成带水印的 File 对象供上传
canvas.toBlob() 输出的是 Blob,但后端接口通常认 File(比如需要 file.name 和 file.lastModified)。你得手动把它包装回 File,否则上传字段可能丢文件名或类型。
- 用
new File([blob], originalFile.name, { type: 'image/jpeg' })包一层 - 注意 MIME 类型要匹配:JPG 图用
image/jpeg,PNG 图保留image/png,别硬转 - 如果原图是 WebP 或 AVIF,
canvas可能不支持导出,此时降级为image/png并提示用户 - 上传时直接传这个新
File对象,不要混用原始input.files[0]
真正难的不是画上去,而是水印位置和透明度要在不同分辨率图片上都可读又不抢戏;另外,手机端用户拍的竖图,水印如果固定居中,容易压在人脸眼睛上——得按 img.naturalWidth > img.naturalHeight 分情况偏移坐标。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











