极简原生 Canvas 图片水印方案
在内容创作与自媒体运营中,图片水印是基础的版权防护手段。本文介绍一套基于原生 JavaScript 与 Canvas 的极简水印方案:上传图片即可自动居中生成自适应水印。该方案代码精简、无第三方依赖,支持纯前端本地处理,可直接嵌入项目使用。
核心特性
- 零依赖架构:纯原生 JS+Canvas 实现,无需任何框架或插件。
- 智能自适应:水印文字大小根据图片尺寸动态调整,大图大字、小图小字。
- 美观防盗:采用半透明白色水印固定居中展示,静态无旋转,兼顾视觉效果与版权保护。
- 隐私安全:全程前端本地处理,图片不上传服务器,彻底规避隐私泄露风险。
完整代码实现
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<title>Canvas 图片中间水印</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei", sans-serif;
background: #f5f5f7;
padding: 24px;
margin: 0;
}
.container {
max-width: 720px;
margin: 0 auto;
background: #fff;
padding: 20px;
border-radius: 16px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.06);
}
h2 {
margin: 0 0 16px;
font-size: 18px;
}
.controls {
display: flex;
flex-wrap: wrap;
gap: 12px;
align-items: center;
margin-bottom: 16px;
}
.result {
margin-top: 16px;
text-align: center;
}
canvas {
max-width: 100%;
border-radius: 12px;
border: 1px solid #eee;
background: #fafafa;
}
</style>
</head>
<body>
<div class="container">
<h2>上传图片自动添加中间水印</h2>
<div class="controls">
<input type="file" id="fileInput" accept="image/*" />
</div>
<div class="result">
<canvas id="canvas"></canvas>
</div>
</div>
<script>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
// 上传图片后自动绘制水印
document.getElementById('fileInput').addEventListener('change', function (e) {
const file = e.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = function (event) {
const img = new Image();
img.onload = function () {
canvas.width = img.width;
canvas.height = img.height;
// 绘制原图
ctx.drawImage(img, 0, 0);
// 固定水印参数,取消旋转
const text = '水印';
const fontSize = Math.round(Math.min(img.width, img.height) * 0.06);
const alpha = 0.35;
ctx.save();
ctx.globalAlpha = alpha;
ctx.font = `bold ${fontSize}px -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei", sans-serif`;
ctx.fillStyle = '#ffffff';
const textWidth = ctx.measureText(text).width;
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
// 直接在画布正中间绘制文字,不再旋转
ctx.fillText(text, centerX - textWidth / 2, centerY);
ctx.restore();
};
img.src = event.target.result;
};
reader.readAsDataURL(file);
});
</script>
</body>
</html>
关键技术解析
图片读取与画布适配
利用 FileReader 读取本地文件,在图片异步加载完成(onload)后,将 Canvas 宽高同步设置为图片实际像素尺寸。此举彻底解决了因画布尺寸不匹配导致的图片拉伸或变形问题,确保水印绘制精准。
自适应水印字号算法
采用Math.min(img.width, img.height) * 0.06算法,取图片短边的 6% 作为字号基准。该逻辑完美适配横图、竖图及方形图,避免大图水印过小或小图水印溢出的视觉失衡。
居中绘制核心逻辑
摒弃复杂的坐标系旋转与位移计算,直接通过测量文字宽度计算偏移量,实现文字在画布正中心的精准定位。样式简洁干净,符合主流平台的轻量化审美需求。
半透明水印优化
设置globalAlpha = 0.35为黄金透明度参数。该数值既能有效标识版权、防止盗用,又不会过度遮挡图片主体内容,兼顾实用性与美观度。
开发避坑指南
必须在 img.onload 中执行绘制
图片加载属于异步操作,若未等待加载完成直接绘制,会导致画布空白。所有绘图逻辑必须置于图片加载完成的回调函数内。
禁止用 CSS 控制 Canvas 宽高
Canvas 的width和height属性决定画布像素尺寸,而 CSS 仅控制显示缩放。若仅通过 CSS 设置宽高,会导致渲染模糊及水印失真,必须通过 JS 设置属性值。
save()/restore() 状态隔离
使用ctx.save()和ctx.restore()包裹绘图状态修改(如透明度、字体),可防止水印样式污染后续画布操作,提升代码的可复用性与扩展性。
方案总结
该原生 Canvas 水印方案以极简、稳定、高效为核心优势。通过去除冗余交互与配置,实现了“上传即水印”的流畅体验。相较于复杂的开源插件,该方案体积更小、兼容性更强且维护成本低,是中小型项目进行图片版权防护的理想轻量化选择。

