为了防止信息泄露或知识产权被侵犯,在web的世界里,对于页面和图片等增加水印处理是十分有必要的,水印的添加根据环境可以分为两大类,前端浏览器环境添加和后端服务环境添加,简单对比一下这两种方式的特点:

前端浏览器加水印:

  • 减轻服务端的压力,快速反应
  • 安全系数较低,对于掌握一定前端知识的人来说可以通过各种骚操作跳过水印获取到源文件
  • 适用场景:资源不跟某一个单独的用户绑定,而是一份资源,多个用户查看,需要在每一个用户查看的时候添加用户特有的水印,多用于某些机密文档或者展示机密信息的页面,水印的目的在于文档外流的时候可以追究到责任人

后端服务器加水印:

  • 当遇到大文件密集水印,或是复杂水印,占用服务器内存、运算量,请求时间过长
  • 安全性高,无法获取到加水印前的源文件
  • 适用场景:资源为某个用户独有,一份原始资源只需要做一次处理,将其存储之后就无需再次处理,水印的目的在于标示资源的归属人

因为减轻对后端服务器的压力,所以这次讲讲通过前端方法去实现一个水印加密。

实现方案

1. 重复的dom元素覆盖实现

从效果开始,要实现的效果是「在页面上充满透明度较低的重复的代表身份的信息」,第一时间想到的方案是在页面上覆盖一个position:fixed的div盒子,盒子透明度设置较低,设置pointer-events: none;样式实现点击穿透,在这个盒子内通过js循环生成小的水印div,每个水印div内展示一个要显示的水印内容,简单实现了一下

  <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>

缺点:页面效果是有了,但是这种方案需要要在js内循环创建多个dom元素,既不优雅也影响性能,于是考虑可不可以不生成这么多个元素。

2. canvas输出背景图

canvas 有着不错的兼容性,是一种比较可靠、成熟的可视化技术。但是它比较依赖分辨率,对文本的处理上也有着先天的不足。但是它可以很方便的将结果保存为图片,对于完成水印的需求也是非常合适的。

第一步还是在页面上覆盖一个固定定位的盒子,然后创建一个canvas画布,绘制出一个水印区域,将这个水印通过toDataURL方法输出为一个图片,将这个图片设置为盒子的背景图,通过backgroud-repeat:repeat;样式实现填满整个屏幕的效果,简单实现的代码。

export default class CanvasWay {constructor(watermark) {this.watermark = watermarkconst {width, height} = watermarkthis.canvas = document.createElement('canvas');this.canvas.setAttribute('width', width);this.canvas.setAttribute('height', height);}render() {const {txt, x, y, width, height, font, color, fontSize, alpha, angle} = this.watermarkconst ctx = this.canvas.getContext('2d');ctx.clearRect(0, 0, width, height);ctx.textBaseline = 'top';ctx.textAlign = 'left'ctx.fillStyle = color;ctx.globalAlpha = alpha;ctx.font = `${fontSize}px ${font}`ctx.translate(x, y)ctx.rotate(Math.PI / 180 * angle);ctx.translate(-x, -y - fontSize)ctx.fillText(txt, x, y + fontSize);return this.canvas.toDataURL();}
}

还有一种类似于canvas的方法。

3.svg 生成方式

svg 与 canvas 相比浏览器兼容性几乎一致,除了几个早期的 Android 版本,这样的设备以及很难找到了,完全可以忽略。svg 使用的是 XML 的方式,不依赖分辨率,在做文本水印这件事上 svg 有着更好的优势

与canvas生成背景图的方法类似,只不过是生成背景图的方法换成了通过svg生成,canvas的兼容性略好于svg。

export default class SvgWay {constructor(watermark) {this.watermark = watermark}render() {const {txt, x, y, width, height, color, font, fontSize, alpha, angle} = this.watermarkconst svgStr =`<svg xmlns="http://www.w3.org/2000/svg" width="${width}px" height="${height}px"><text x="${x}px" y="${y}px" dy="${fontSize}px"text-anchor="start"stroke="${color}"stroke-opacity="${alpha}"fill="none"transform="rotate(${angle},${x} ${y})"font-weight="100"font-size="${fontSize}"font-family="${font}">${txt}</text></svg>`;return `data:image/svg+xml;base64,${window.btoa(unescape(encodeURIComponent(svgStr)))}`;}
}

但是,以上三种方法存在一个共同的问题,由于是前端生成dom元素覆盖到页面上的,对于有些前端知识的人来说,可以在开发者工具中找到水印所在的元素,将元素整个删掉,以达到删除页面上的水印的目的,针对这个问题,我想到了一个很笨的办法:设置定时器,每隔几秒检验一次我们的水印元素还在不在,有没有被修改,如果发生了变化则再执行一次覆盖水印的方法。

但是这种用定时器的方法还是会对我们造成很大的人力资源浪费,所以在网上看到了一种解决方法:使用MutationObserver:

MutationObserver 对现代浏览的兼容性还是不错的,MutationObserver是变动观察器,字面上就可以理解这是用来观察Node(节点)变化的。MutationObserver是在DOM4规范中定义的,它的前身是MutationEvent事件,最低支持版本为 ie9 ,目前已经被弃用。

但是MutationObserver只能监测到诸如属性改变、子结点变化等,对于自己本身被删除,是没有办法监听的,这里可以通过监测父结点来达到要求:

实现的监控的代码如下:

const MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;export const observer = (callback) => {if (!MutationObserver) return falselet bodyObserver = new MutationObserver(mutationsList => mutationsList.forEach(mutation =>mutation.removedNodes.forEach(_target => _target.id === _id && callback())))bodyObserver.observe(document.body, {childList: true});const target = document.getElementById(_id);let observer = new MutationObserver(callback);observer.observe(target, {characterData: true, attributes: true, childList: true, subtree: true});return {bodyObserver, observer};
}
4.通过NodeJS生成水印

这种方式是需要借助到后端的一种方法:
身为现代前端开发者,Node.JS也是需要掌握的。我们同样可以通过NodeJS来生成网页水印(出于性能考虑更好的方式是利用用户客户端来生成)。前端发一个请求,参数带上水印内容,后台返回图片内容。
具体实现(Koa2环境):

  1. 安装gm以及相关环境,详情看gm文档
  2. ctx.type = ‘image/png’;设置响应为图片类型
  3. 生成图片过程是异步的,所以需要包装一层Promise,这样才能为通过 async/await 方式为 ctx.body 赋值
const fs = require('fs')
const gm = require('gm');
const imageMagick = gm.subClass({imageMagick: true
});const router = require('koa-router')();router.get('/wm', async (ctx, next) => {const {text} = ctx.query;ctx.type = 'image/png';ctx.status = 200;ctx.body = await ((() => {return new Promise((resolve, reject) => {imageMagick(200, 100, "rgba(255,255,255,0)").fontSize(40).drawText(10, 50, text).write(require('path').join(__dirname, `./${text}.png`), function (err) {if (err) {reject(err);} else {resolve(fs.readFileSync(require('path').join(__dirname, `./${text}.png`)))}});})})());
});

以上就是几种可以很少借助后端实现的给图片加水印的方法,在实现浏览PDF、下载公司文件的时候为了保密性都可以尝试使用。

通过前端方法实现水印加密相关推荐

  1. 1w字详解从破解某定设计网站谈前端明暗水印(推荐收藏)

    前言 最近在写公众号的时候,常常会自己做首图,并且慢慢地发现沉迷于制作首图,感觉扁平化的设计的真好好看.慢慢地萌生了一个做一个属于自己的首图生成器的想法. 制作呢,当然也不是拍拍脑袋就开始,在开始之前 ...

  2. PDF批量加水印加密丨Acrobat Pro DC

    使用Acrobat Pro DC的动作向导进行批量加密加水印等,优点:速度快,免费,免插件,本地操作. 在工具页找到"动作向导" 如图所示新建动作,可以在页面下找到添加水印选项,双 ...

  3. Asp.Net Core SignalR 用泛型Hub优雅的调用前端方法及传参

    继续学习 最近一直在使用Asp.Net Core SignalR(下面成SignalR Core)为小程序提供websocket支持,前端时间也发了一个学习笔记,在使用过程中稍微看了下它的源码,不得不 ...

  4. 计算机硬盘加密的几种方法,对于移动硬盘加密方法 你了解多少种呢?

    原标题:对于移动硬盘加密方法 你了解多少种呢? 移动硬盘自然随身携带,有时会丢失.一旦丢失,内部数据将不再安全.如果内部有重要信息,将严重威胁您的信息安全.那么,什么是移动硬盘加密方法?让我们来看看. ...

  5. 前端使用pako.js加密解密

    之前在网上搜到的关于pako加密解密方法,其中加密方法有点问题,和解密方法不配套. 整理了下我自己最后修改的代码 zip = (str) => { let binaryString = pako ...

  6. 前端怎么把文件加密之后传给后端

    问题描述: 这边有个业务需求,需要前端把文件进行加密之后传给后端, 后端提供了一个md5的字段,需要前端这边传入这个字段. 解决过程: 1.既然需要加密,肯定是需要用到MD5js,这时候需要安装MD5 ...

  7. Javascript 核心方法加密,JS方法完美在线加密工具介绍及演示

    Javascript 核心方法加密介绍: JS方法加密工具地址:Javascript方法加密,JS核心代码加密,JS不可逆加密 - [JavaScript加密] 优点: 1.完全打乱顺序,并且很难跟踪 ...

  8. html前端的几种加密/解密方式

    一.base64加密 前端用base64加密和解密的使用方法,只需要两个函数就可以了.一个是加密:window.btoa(),一个是解密:window.atob(),看例子: var str = &q ...

  9. 前端JavaScript代码混淆加密原理介绍

    因为JavaScript大都是运行在浏览器端,这就导致任何人都可以直接对网站的代码进行查看,如果代码没有进行任何处理就会导致直接暴露源码,他人便可轻而易举的复制你的劳动成果,但是由于没有纯粹的加密方案 ...

最新文章

  1. 解密Elasticsearch技术,腾讯开源的万亿级分布式搜索分析引擎
  2. (转)解决Android SDK Manager无法更新或下载太慢问题
  3. 程序员的十层楼   (1)
  4. 黑马程序员——Java正则表达式
  5. linux正则 转义字符,正则表达式(5):转义符
  6. 2021计算机一级新增知识点,2021年计算机一级知识点.doc
  7. opencv查找边界_数据边界:查找差距,孤岛等
  8. 计算机论文格式要求吗,论文格式
  9. Anaconda出现Navigator Error的解决办法
  10. 云课堂智慧职教网页版登录入口_云课堂智慧职教网页版登录入口
  11. LOLBox多玩饭盒Android源码
  12. bindZip下载地址
  13. Linux Cpuidle介绍
  14. wifi大师分销多开v3.1.5安装教程附带源码
  15. Excel日期运算单,多条件求和与计数
  16. Windows-dos命令
  17. 基于Selenium实现网易云音乐的登录
  18. matlab求定积分和不定积分
  19. 微信小程序医院门诊体检预约信息管理系统SSM-JAVA【数据库设计、论文、源码、开题报告】
  20. Caesar密码的生成与破解

热门文章

  1. linux命令解压tar命令,菜鸟学Linux命令:tar命令 压缩与解压缩
  2. CogPMAlignTool使用详解
  3. iOS控制器瘦身-面向超类编程
  4. 凤鸣镇目标服务器无法响应,新一轮合服天龙3 4月5日八组服务器移民公告
  5. python 基础二(学习打卡)
  6. Laravel Mix
  7. android魅族手机Pro6 Android7.1.1 点击状态栏滚到顶部Bug
  8. Win10便笺stickynotes打不开
  9. 高德地图披露2016全年成绩 推出两款春运产品
  10. Android的GridView中的选中图标后图标的背景颜色