H5响应式图片加水印需Canvas宽高严格匹配图片显示尺寸,监听resize等事件动态重绘;字号用img.width*0.03动态计算,右下角锚定并设textBaseline='bottom',globalAlpha控制透明度;跨域需设置crossOrigin和服务端CORS头,用requestAnimationFrame优化性能,封装支持多输入类型及定位模式的Promise函数。

在 H5 中实现响应式图片加水印,核心是让水印随图片尺寸、设备屏幕、横竖屏切换实时适配,并在 Canvas 中完成动态合成。这不是简单叠一层 CSS,而是要确保水印文字/图标始终清晰、位置合理、不拉伸不变形,且在不同手机上表现一致。
水印与图片同步缩放的关键逻辑
Canvas 画布宽高必须严格匹配目标图片的当前显示尺寸(不是原始分辨率),否则水印会错位或被裁切。例如:
— 图片在 iPhone 上因 viewport 缩放显示为 320×480,Canvas 就设为 320×480;
— 同一张图在 iPad 横屏下显示为 1024×680,Canvas 就要重设为该尺寸。
需监听 window.resize、img.onload 和 video.resize(如用相机插件)事件,每次触发后重新计算并重绘。
移动端适配水印字体与位置
纯 px 字号在小屏上会过小,在大屏上又显粗,应改用相对单位并做设备分级处理:
- 用
ctx.font = `${fontSize}px sans-serif`动态计算字号:取Math.max(12, Math.min(20, img.width * 0.03))作为基础值 - 右下角锚定最稳妥:坐标设为
canvas.width - 20和canvas.height - 20,配合textAlign = 'right'+textBaseline = 'bottom' - 避免使用
textBaseline = 'alphabetic'(iOS Safari 渲染偏高),统一用'bottom'或'middle' - 透明度用
ctx.globalAlpha = 0.25控制,比 CSS opacity 更精准,不影响 canvas 其他绘制内容
跨域图片与性能优化要点
从相册选图或 URL 加载的图片若跨域,Canvas 会被污染,无法导出。解决方法:
- 服务端返回图片时添加
Access-Control-Allow-Origin: *响应头 - 前端加载时设置
img.crossOrigin = 'anonymous' - 使用
requestAnimationFrame驱动绘制循环,比setInterval更省资源、更准 - 水印文本、字体、颜色等静态配置提前缓存,避免每帧重复拼接字符串
- 如需斜向平铺水印,务必用
ctx.save() → rotate() → draw → ctx.restore(),防止坐标系污染后续绘制
封装建议:一个可复用的合成函数
可封装成接受图片对象、水印文本、定位参数的函数,返回带水印的 Blob 或 Base64:
- 输入支持 File、Blob、URL、HTMLImageElement 四种类型
- 自动识别是否需要压缩(如 > 2MB 则先用 canvas.toBlob 压缩)
- 定位支持
top-left/center/bottom-right/tile四种模式 - 返回 Promise,便于链式调用到上传流程(如 uView2 的
u-upload)


















