一、问题背景
为了防止信息泄露或知识产权被侵犯,在web世界里,对于页面和图片等增加水印处理是十分有必要的,水印的添加根据环境可分为两大类,前端浏览器环境添加和后端服务器环境添加,简单对比一下这两种方式的特点:
前端浏览器添加水印:
- 减轻服务器端压力,快速反应
- 安全系统较低,对于掌握一定前端知识的人来说可以通过各种操作跳过水印获取到源文件(防君子不防小人,防外行不防内行)
- 适用场景:资源不跟某一个单独的用户绑定,而是一份资源,多个用户查看,需要在每一个用户查看 的时候添加用户特有的水印,多用于某些机密文档或者展示机密信息的页面,水印的目的在于文档外流的时候可以追究到责任人。
后端服务器添加水印:
当遇到大文件密集水印,或者复杂水印,占用了服务器内存,运算量,请求时间过长, 安全性高,无法获取到加水印前的源文件。
适用场景:资源为某个用户独有,一份原始资源只需要做一次处理,将其存储之后就无需要再次处理,水印的目的在于标示资源的归属人,这里我们主要讨论前端浏览器环境添加。
二、实现方案
1.重复的DOM元素覆盖实现
2.canvas输出背景图
3.svg实现背景图
4.图片加水印
5.拓展:图片隐性水印
1.重复的DOM元素覆盖实现
从效果开始,要实现效果是在页面上充满透明度较低的重复的代表身份的信息,第一时间想到的方案是在页面上覆盖一个position:fixed的div的盒子,盒子透明底设置较低,设置Pointer-events:none;样式实现点击穿透,在这个盒子内通过js循环生成小水印div,每个水印div内展示一个要显示水印内容,简单实现一下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style>
#watermark-box {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
font-size: 24px;
font-weight: 700;
display: flex;
flex-wrap: wrap;
overflow: hidden;
user-select: none;
pointer-events: none;
opacity: 0.1;
z-index: 999;
}
.watermark {
text-align: center;
}
</style>
</head>
<body>
<div>
<h2> 机密内容- 机密内容- 机密内容- 机密内容- 机密内容- 机密内容- </h2>
<br />
<h2> 机密内容- 机密内容- 机密内容- 机密内容- 机密内容- 机密内容- </h2>
<br />
<h2 onclick="alert(1)"> 机密内容- 机密内容- 机密内容- 机密内容- 机密内容- 机密内容- 机密内容- </h2>
<br />
</div>
<div id="watermark-box">
</div>
<script>
function doWaterMark(width, height, content) {
let box = document.getElementById("watermark-box");
let boxWidth = box.clientWidth,
boxHeight = box.clientHeight;
for (let i = 0; i < Math.floor(boxHeight / height); i++) {
for (let j = 0; j < Math.floor(boxWidth / width); j++) {
let next = document.createElement("div")
next.setAttribute("class", "watermark")
next.style.width = width + 'px'
next.style.height = height + 'px'
next.innerText = content
box.appendChild(next)
}
}
}
window.onload = doWaterMark(300, 100, '水印123')
</script>
</body>
</html>
2.canvas输出背景图
第一步还是在页面上覆盖一个固定定位的盒子,然后创建一个canvas画布,绘制出一个水印区域,将这个水印通过toDataURL方法输出为一个图片,将这个图片设置为盒子的背景图,通过background-repreat:repeat;样式实现填满整个屏幕的效果。