你知道前端是如何实现水印的吗视频,前端页面水印

  你知道前端是如何实现水印的吗视频,前端页面水印

  在我们的日常工作中,经常会遇到很多敏感数据。为了防止数据泄露,要对数据做一些“包装”。目的是让那些有心泄露数据的“不法分子”在严峻的“舆论压力”下放弃违法行为,使其“犯罪未遂”,从而达到不战而屈人之兵的效果。

  我们在安全部门工作,数据安全的概念早已深入骨髓。每一个字每一张图片都要注意是否有泄露的风险,如何防止数据泄露是我们一直在思考的问题。比如图片的水印,就是我们工作中经常涉及到的问题。因为工作本身就是审核平台的开发,所以审核平台上经常会出现一些有风险的图片。考虑到审核人员安全意识参差不齐,需要对图片进行水印处理,防止不安全的事情发生。

  

分析问题

  首先考虑业务场景,现阶段的问题只是担心审计过程中的数据泄露。我们暂时只考虑显性水印,也就是在图片中加入一些可以区分你个人身份的文字或者其他数据。这样就可以根据泄露的数据追踪到个人。当然,未雨绸缪、防患于未然的警示功能是其最重要的功能。

  

解决问题

  实现方式

  水印的实现方式有很多种,按照功能的划分可以分为前端水印和后端水印。前端水印的优势可以总结为三点。第一,可以完全依靠客户端的计算能力,不占用服务器资源,从而减轻服务器的压力。第二,速度快,前端性能比后端好。第三,实现简单。后端水印最大的优势也可以总结为三点,安全,安全,安全。知乎和微博都采用后端水印方案。但综合考虑,我们还是采用前端水印方案。下面也将简单介绍nodejs如何实现后端图像水印。

  node实现

  提供了三个npm包。这部分不是本文的重点,只提供简单的演示。

  1、通用https://github.com/aheckmann/gm 6.4k星

  const fs=require( fs );

  const GM=require( GM );

  gm(/path/to/my/img.jpg )。drawText(30,20, GMagick!)。write(/path/to/drawing.png ,function (err) {

  如果(!err)console . log( done );

  });GraphicsMagick或ImageMagick需要安装;

  2、节点图像:https://github.com/zhangyuanwei/node-images

  const wrap=document . query selector(# ReactApp));

  const { clientWidth,clientHeight }=wrap

  const waterHeight=120

  const水宽=180;

  //数一数

  const [columns,rows]=[~ ~(client width/water width),~~(clientHeight/waterHeight)]

  for(设I=0;I列;i ) {

  for(设j=0;j=行数;j ) {

  const water DOM=document . createelement( div );

  //动态设置偏移值

  waterDom.setAttribute(style ,` s

  宽度:$ { waterWidth } px

  高度:$ { waterHeight } px

  left:$ { water width(I-1)* water width 10 } px;

  top:$ { water height(j-1)* water height 10 } px;

  颜色:# 000;

  位置:绝对`位

  );

  water DOM . inner text= test watermark ;

  wrap . appendchild(water DOM);

  }

  }无需安装其他工具,轻量级,张沅薇开发,中文文档;

  3、吉姆:https://github.com/oliver-moran/jimp

  Gif水印可以用gifwrap实现;

  前端实现

  1、背景图像实现全屏水印

  可以在阿里内外的个人信息页面查看效果。

  优点:图片在后端生成,安全;

  缺点:需要发起http请求来获取图片信息;

  显示:因为是内部系统,不方便显示效果。

  2.dom实现了全图像水印和图像水印

  在图片的onload事件中获取图片的宽度和高度,根据图片的大小生成水印区域,覆盖在图片的顶部。dom内容是水印的拷贝或其他信息,容易实现。

  const wrap=document . query selector(# ReactApp));

  const { clientWidth,clientHeight }=wrap

  恒定水高度=120

  常数水宽=180;

  //计算个数

  const [columns,rows]=[~ ~(client width/water width),~~(clientHeight/waterHeight)]

  对于(设I=0;我列;i ) {

  对于(设j=0;j=行数;j ) {

  const water DOM=文档。createelement( p );

  //动态设置偏移值

  waterDom.setAttribute(style ,` s

  宽度:$ { waterWidth } px

  高度:$ { waterHeight } px

  左:$ {水宽(I-1)*水宽10 } px

  top:$ {水高(j-1)*水高10 } px

  颜色:# 000;

  位置:绝对`位

  );

  waterDom.innerText=测试水印;

  包装。appendchild(水DOM);

  }

  }优点:简单易实现;

  缺点:图片过大或者过多会有性能影响;

  3、画布实现方式(第一版实现方案)

  方法一:直接在图片上操作

  废话不多说,直接上代码

  useEffect(()={

  //gif图不支持

  if (src src.includes( .gif)) {

  setShowImg(true);

  }

  image.onload=function () {

  尝试{

  //太小的图不加载水印

  if (image.width 10) {

  setIsDataError(true);

  道具。setisdataerror属性。setisdataerror(true);

  返回;

  }

  const canvas=canvasRef.current

  画布。宽度=图像。宽度;

  画布。高度=形象。身高;

  //设置水印

  const font=` $ { math。最小(数学。马克斯(数学。地板(内层帆布。width/14)、14)、48)} px ` 字号;

  内在语境。font=` $ { font } $ { font family }

  内在语境。文本基线=悬挂;

  内在语境。旋转(旋转*数学.PI/180);

  内在语境。线宽=线宽;

  内在语境。笔画风格=笔画风格;

  innerContext.strokeText(text,0,内部画布。高度/4 * 3);

  内在语境。填充样式=填充样式;

  innerContext.fillText(text,0,内部画布。高度/4 * 3);

  const context=画布。获取上下文(“2d”);

  context.drawImage(this,0,0);

  context.rect(0,0,image.width 200,image。身高 200);

  //设置水印浮层

  常量模式=上下文。创建模式(内部画布,“重复”);

  context.fillStyle=pattern

  语境。fill();

  } catch (err) {

  控制台。信息(错误);

  setShowImg(true);

  }

  };

  image.onerror=function () {

  setShowImg(true);

  };

  },[src]);优点:纯前端实现方式,右键复制的图片也是有水印的;

  缺点:不支持gif,图片必须支持跨域;

  效果展示:下文给出。

  方法二:画布生成水印全球资源定位器(统一资源定位器)赋值给钢性铸铁背景属性

  export const get base 64 background=(props)={

  const { nick,empId }=GlobalConfig.userInfo

  常数{

  旋转=-20度,

  身高=75,

  宽度=85,

  text=`${nick}-${empId} `,

  fontSize=14px ,

  线宽=2,

  fontFamily=微软雅黑,

  stroke style= rgba(255255255,15),

  fillStyle=rgba(0,0,0,0.15),

  position={ x: 30,y: 30 },

  }=道具;

  常量图像=新图像();

  image.crossOrigin=匿名

  const canvas=文档。createelement(“canvas”);

  const context=画布。获取上下文(“2d”);

  画布宽度=宽度;

  canvas.height=高度;

  语境。font=` $ { font size } $ { font family } `;

  语境。线宽=线宽;

  context.rotate(rotate * Math .PI/180);

  语境。笔画风格=笔画风格;

  语境。填充样式=填充样式;

  context.textAlign= center

  语境。文本基线=悬挂;

  context.strokeText(text,position.x,position。y);

  context.fillText(text,position.x,position。y);

  返回画布。toda taurl( image/png );

  };

  //使用方式

  img src=https://xxx.xxx.jpg /

  p class name= water-mark-area style={ { background image:` URL($ { getbase 64 background({ })})`} }/优点:纯前端实现方式,支持跨域,支持饭桶图水印;

  缺点:生成的base64 url比较大;

  其实根据这两种实现画布的方式,我们很容易想到第三种方式,即在画面上方覆盖一层第一种方式中画面以外的画布,可以完美的避免两种方案的缺点。但是停下来想一想。有没有更简单易懂的方法把两种方案结合起来,或者用画布来画?可以,用svg代替。

  4、SVG模式(正在使用的方案)

  给出一个react版本的水印组件。

  导出常量水印=(props)={

  //获取水印数据

  const { nick,empId }=GlobalConfig.userInfo

  const box ref=react . createref();

  const [waterMarkStyle,setwatermark style]=use state( 180 px 120 px );

  const [isError,setIsError]=use state(false);

  常数{

  src,text=`${nick}-${empId} `,height: propsHeight,showSrc,img,nick,empId

  }=道具;

  //设置背景图像和背景图像样式

  const boxStyle={

  backgroundSize: waterMarkStyle,

  background image:` URL( data:image/SVG XML;utf8,SVG width=\ 100% \ height=\ 100% \ xmlns=\ http://www . w3 . org/2000/SVG \ version=\ 1.1 \ text width=\ 100% \ height=\ 100% \ x=\ 20 \ y=\ 68 \ transform=\ rotate(-20)\ fill=\ rgba(0,0,0,0,0.2)\ font-1

  };

  const onLoad=(e)={

  const dom=e.target

  常数{

  previousSibling,nextSibling,offsetLeft,offsetTop,

  }=dom

  //获取图片的宽度和高度

  const { width,height }=getComputedStyle(DOM);

  if (parseInt(width.replace(px , ))180) {

  setWaterMarkStyle(` $ { width } $ { height . replace( px , )/2 } px `);

  };

  previous sibling . style . height=height;

  previous sibling . style . width=width;

  previous sibling . style . top=` $ { offsetTop } px `;

  previous sibling . style . left=` $ { offset left } px `;

  //隐藏加载

  next sibling . style . display= none ;

  };

  const onError=(event)={

  setIsError(true);

  };

  返回(

  p class name={ styles . water _ mark _ wrapper } ref={ boxRef }

  p class name={ styles . water _ mark _ box } style={ box style }/

  {isError

  ?errorsourcedatasrc={ src } show src={ show src } height={ props height } text=图片加载错误 helpText=单击复制图片链接/

  : (

  img onload={ onload } referrer policy= no-referrer on error={ on error } src={ src } alt=图片显示错误/

  icon class name={ styles . img _ loading } type= loading /

  /

  )

  }

  /p

  );

  };优点:支持gif图像水印,不存在跨域问题,使用重复属性,没有dom插入过程,不存在性能问题;

  QA

  

总结

  前端水印方案始终只是临时方案,业务的后端实现消耗服务器资源。事实上,最理想的解决方案是提供独立的水印服务。虽然加载过程中会有轻微的延迟,但是相比数据安全,毫秒级的延迟还是可以接受的,可以保证业务的服务稳定性不会受到影响。

  在每天回答问题的过程中,会有很多业务方来找我沟通水印屏蔽风险点的问题。每一次,他们都只能用数据安全的重要性来回复。当然,水印的大小、透明度和密度也在不断优化。相信会有一个版本不仅能起到水印的作用,还能更好的解决遮挡问题。

  推荐:html视频教程。以上是前端水印如何实现的细节。更多请关注我们的其他相关文章!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: