你知道前端是如何实现水印的吗视频,前端页面水印
在我们的日常工作中,经常会遇到很多敏感数据。为了防止数据泄露,要对数据做一些“包装”。目的是让那些有心泄露数据的“不法分子”在严峻的“舆论压力”下放弃违法行为,使其“犯罪未遂”,从而达到不战而屈人之兵的效果。
我们在安全部门工作,数据安全的概念早已深入骨髓。每一个字每一张图片都要注意是否有泄露的风险,如何防止数据泄露是我们一直在思考的问题。比如图片的水印,就是我们工作中经常涉及到的问题。因为工作本身就是审核平台的开发,所以审核平台上经常会出现一些有风险的图片。考虑到审核人员安全意识参差不齐,需要对图片进行水印处理,防止不安全的事情发生。
分析问题
首先考虑业务场景,现阶段的问题只是担心审计过程中的数据泄露。我们暂时只考虑显性水印,也就是在图片中加入一些可以区分你个人身份的文字或者其他数据。这样就可以根据泄露的数据追踪到个人。当然,未雨绸缪、防患于未然的警示功能是其最重要的功能。
解决问题
实现方式
水印的实现方式有很多种,按照功能的划分可以分为前端水印和后端水印。前端水印的优势可以总结为三点。第一,可以完全依靠客户端的计算能力,不占用服务器资源,从而减轻服务器的压力。第二,速度快,前端性能比后端好。第三,实现简单。后端水印最大的优势也可以总结为三点,安全,安全,安全。知乎和微博都采用后端水印方案。但综合考虑,我们还是采用前端水印方案。下面也将简单介绍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的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。