为了防止信息的泄露,水印作为一种防泄密的方式,被使用的频率越来越高。
那么在Odoo中,如何添加水印呢?其实添加的方法有很多,如利用svg生成背景图,重复的dom元素覆盖等等。
本文主要讲解利用canvas输出背景图的方式来添加水印。
原理简介
首先创建一个canvas画布,利用canvas的特点绘制出一个带有文字字样的水印区域,然后将这个水印区域通过 toDataURL方法 输出为一个图片,并将这个图片设置为背景图,通过backgroud-repeat:repeat 样式填满这个屏幕。
实现方法
# 封装一个生成图片的函数
先创建一个canvas元素,标签用于使用 JavaScript 动态绘制图形但是元素没有自己的绘图能力(它只是一个图形容器),因此我们需要通过getContext()方法获得一个画布对象。
该对象提供在画布上绘图的方法和属性,可用于在画布上绘制文本、线条、框、圆等,具体实现如下 ⬇
createImg(imgOptions = {}) {
const canvas = document.createElement('canvas');
const text = imgOptions.content || "Test";
canvas.width = imgOptions.width || 200;
canvas.height = imgOptions.height || 200;
const ctx = canvas.getContext('2d');
if (ctx) {
ctx.font = imgOptions.font || "15px PingFang SC, sans-serif";
ctx.fillStyle = imgOptions.color || "rgba(150, 160, 150, 0.5)";
ctx.rotate(imgOptions.rotateDegree);
ctx.textAlign = 'center';
ctx.fillText(text, imgOptions.x || 100, imgOptions.y || 100);
}
return canvas.toDataURL('image/png');
},
canvas.toDataURL()方法返回一个用于图片展示的data url,即我们常说的base64地址。其接受两个参数 type 和 encoderOptions :
· type:可选,转换的图片类型,默认值是image/png,还可以是image/jpeg,甚至image/webp前提浏览器支持,如Chrome)等。
· encoderOptions:可选,转换的图片质量。范围是0到1,不在该取值范围,则取默认值0.92。此参数要想有效,type 需要是 image/jpeg 或者 image/webp,其他 type 值无效。
# 将图片作为背景图添加至页面上并铺满页面
将生成图片的函数封装好之后,我们就可以把该图片作为背景图片平铺到页面上,实现添加水印的效果了,具体实现如下 ⬇
generateWaterMark({
className = 'my_watermarked',
width = 360,
height = 240,
content = 'Test',
font = '15px PingFang SC, sans-serif',
color = 'rgba(150, 160, 150, 0.5)',
rotate = -20,
position = 'absolute',
top = 0,
left = 0,
zIndex = 1000,
}) {
const option = {
width,
height,
content,
font,
color,
rotateDegree: (rotate * Math.PI) / 180,
};
const dataUri1 = this.createImg({
...option,
x: 80,
y: 120,
});
const dataUri2 = this.createImg({
...option,
x: 200,
y: 280,
});
let defaultStyle = document.createElement('style');
defaultStyle.innerHTML = `.${className}:after {
content: '';
display: block;
width: 100%;
height: 100%;
${top || top === 0 ? `top: ${top}px;` : ''}
${left || left === 0 ? `left: ${left}px;` : ''}
background-repeat: repeat;
pointer-events: none;
}`;
let styleEl = document.createElement('style');
styleEl.innerHTML = `.${className}:after
{
${position ? `position: ${position}` : ''};
${zIndex ? `z-index:${zIndex}` : ''};
background-image: url(${dataUri1}), url(${dataUri2});
background-size: ${option.width}px ${option.height}px;
}`;
document.head.appendChild(defaultStyle);
document.head.appendChild(styleEl);
},
可以看到,我们首先创建了两个style元素,然后利用css样式
· background-image: url(${dataUri1}), url(${dataUri2})
· background-repeat: repeat
把生成的两张图片作为背景图片进行填充并铺满整个页面(两张图片通过传入的文字偏移量不同,来实现页面上的交错效果,也可以选用一张或多张);
zIndex表示图片所处图层,要尽可能设置的大一些,让水印处于最底层。
当然也可以在此方法中修改图片的大小,文字颜色,字体大小等。
最后,我们可以在addons/web/static/src/js/chrome/web_client.js (不同版本路径可能不同)的start()函数中调用该方法。
并在需要添加水印的页面中加上classs="my_watermarked即可,可以添加到body上,这样所有页面均生效 ⬇
start: function () {
core.bus.on('change_menu_section', this, function (menuID) {
this.do_push_state(_.extend($.bbq.getState(), {
menu_id: menuID,
}));
});
<-- code start -->
const watermark_option = {
content: "这是一个水印",
className: 'my_watermarked',
};
this.genWaterMark(watermark_option);
<-- code end -->
return this._super.apply(this, arguments);
},
注意:该方法是通过class来确定渲染水印,因此class的名称一定要与传入的值一致。
展示效果
重启服务之后,可以看到页面上已经出现我们需要的水印了。
Tips:由于该方法是通过class来渲染水印,很容易被稍微懂点前端知识的人修改,接下来介绍一种防修改的方式,供参考:
利用 Web API 接口 MutationObserver 来监听body元素的变化,MutationObserver可以用来监听 DOM 变动。
DOM 的任何变动,比如节点的增减、属性的变动、文本内容的变动都会触发MutationObserver 事件。
当 body 元素的class发生变化,触发 MutationObserver 事件,重新将class添加进去,这样就可以防止误删或修改了。
当然所有的防修改方案都不是绝对的,防君子不防小人。