前端水印方案汇总

前言

    水印作为保护知识产权的手段之一,在我们的日常生活中已经随处可见,比如度娘图片、ZF官网报表和随处可见的海报等。水印距离我们的生活如此之近,作为开发人员,水印的实施方案很值得我们去探索一番!

正文

    水印的生成手段无外乎两种:程序合成和PS。从严格意义上来讲,PS也是程序合成的手段之一(图层合成),本文重点介绍如何使用程序合成手段添加水印。

1 水印合成的分类

    这里只阐述和本文内容相关的分类,其他角度分类请自行度娘!

    从素材来源分类:图图合成、图文合成以及无图合成。

    从前端技术手段上:canvas、div遮罩和直接设置背景图片。

2 水印前端合成技术详述

    由于直接设置背景图片过于简单,本节仅详述canvas和div遮罩实现图图合成、图文合成以及无图合成的原理。

2.1 canvas水印合成原理

    利用canvas相关api:drawImage、toDataURL和fillText。drawImage可以将图片绘制到canvas,toDataURL则可以将canvas转变为base64图片,fillText可以向图片中添加文字。示例代码如下:

async function compseImages(image1, image2){
  return new Promise((resolve, reject) => {
      const canvas = document.createElement("canvas");
      canvas.width = 700;
      canvas.height = 700;
      const context = canvas.getContext("2d");
      context.rect(0 , 0 , canvas.width , canvas.height);
      context.fillStyle = "#fff";
      context.fill();
      const myImage = new Image();
      myImage.src = image1;  //背景图片
      myImage.crossOrigin = 'Anonymous';
      myImage.onerror = (e) => { reject(e)}
      myImage.onload = () => {
        context.drawImage(myImage , 0 , 0 , 700 , 700);
        context.font = "60px Courier New";
        context.fillText("我是文字",350,450);
        var myImage2 = new Image();
        myImage2.src = image2;  //你自己本地的图片或者在线图片
        myImage2.crossOrigin = 'Anonymous';
        myImage2.onerror = (e) => { reject(e) }
        myImage2.onload = () => {
          context.drawImage(myImage2 , 175 , 175 , 225 , 225);
          resolve(canvas.toDataURL("image/jpeg"));
        }
      }
  })
  
}
复制代码

    上面代码仅仅合并了2副图像,并添加了一段文字。实现水印效果相信对于开发童鞋应该不是什么难事!Github上已经有使用此原理的水印工具,详见仓库地址

2.2 div遮罩水印合成原理

    这种方案适合图文合成以及无图合成。两种具体实施方案:普通div和shadowDom。建议使用shadowDom,可以进行样式封装。随便提一下,Google已于2017年10月移除::shadow和/deep/,详见链接。目前外部样式只能通过宿主元素设置可继承属性加以干扰。总之,在规范设置全局样式的前提下,可以放心使用shadowDom,不用担心样式污染!使用shadowDom设置水印的示例代码如下:

// index.html
<div class="content">
  <div id="watermark" style="pointer-events: none!important"></div>
</div>
<script>
   const ele = document.querySelector('#watermark')
   if (typeof ele .attachShadow === 'function') { // 如果元素支持创建shadowRoot则创建否则用普通div
       shadowRoot = ele .attachShadow({ mode: 'open' })
   } else {
       shadowRoot = ele 
   }
   const textEl = document.createElement('div')
   const textNode = document.createTextNode('水印')
   textEl.append(textNode)
   textEl.style.width='200px'
   textEl.style.height='200px'
   textEl.style.fontSize='20px'
   textEl.style.opacity='0.5'
   textEl.style.transform='rotate(-15deg)'
   textEl.style['user-slect']='none'
   shadowRoot.append(textEl)
</script>
复制代码

    上面代码仅添加了一个水印,添加有规律或者无规律水印需要在循环中处理,水印行列需要根据父级元素区域和水印宽高进行计算,从而达到铺满全屏的效果。同样,Github上已经有使用此原理的水印工具,详见仓库地址

3 结果评估

    利用前端技术手段生成的水印,比较容易被擦除,比如删除背景图或者删除dom节点。还是采用PDF或者图片的方式进行内容展现才能最大可能的避免侵权!欢迎访问原文链接!

Guess you like

Origin juejin.im/post/7039536411552251934