如何在Odoo中添加水印?

news2024/11/22 15:12:51

为了防止信息的泄露,水印作为一种防泄密的方式,被使用的频率越来越高。

那么在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添加进去,这样就可以防止误删或修改了。

当然所有的防修改方案都不是绝对的,防君子不防小人。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/46701.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

不懂单链表? 这篇文章就帮你搞明白

坚持看完&#xff0c;结尾有思维导图总结 链表对指针的操作要求不低链表的概念链表的特性链表的功能(最重要)定义和初始化头插头删细节说明尾插尾删寻找链表元素与打印链表在 某位置后插入删除在某位置的插入删除销毁链表链表的概念 什么是链表 官方概念&#xff1a;链表是一种…

链表(1)

我们以前学过的线性数据结构底层原理都是依托静态数组来实现的&#xff0c;今天我们讲学习一个最简单的动态数据结构---->链表&#xff01; 掌握链表有助于学习更加复杂的数据结构&#xff0c;例如&#xff1a;二叉树、trie 链表的优点是不需要处理固定的问题&#xff0c;…

mavon-editor的使用

vue3vitets下安装mavon-editor 3.0.0-beta版本&#xff0c;效果如下&#xff1a; 安装 //引入样式 import mavon-editor/dist/css/index.css; import mavonEditor from mavon-editor; app.use(router).use(mavonEditor).mount(#app);<template><div class"rich…

zabbix主动监控和被动监控

目录 一、环境准备 1、搭建zabbix基础环境 二、主动监控与被动监控介绍 三、设置客户端为主动监控 1、给web2主机安装zabbix_agent 2、修改主动监控配置 四、设置zabbix管理端主动监控 1、克隆模板 2、给目标主机绑定主动监控模板 3、查看主动监控的数据 一、环境准备…

【HIT-OSLAB-实验中的碎碎念】

文章目录应该养成的好习惯删除 替换 修改 内容时 记得留备份遇到问题要通过文字 图片 等多种途径去记录不同的项目应该在不同的文件夹进行处理代码文档 记得添加一些注释用于说明功能多输出有区别度的提示信息s找bug 先定位错误 再改当一份代码有不同版本的时候 记得说明每份代…

109376-05-8,Boc-QRR-AMC, Hepsin substrate

Boc-QRR-AMC是跨膜丝氨酸蛋白酶hepsin的底物&#xff0c;也用于测定酿酒酵母中的可辛(Kex2内蛋白酶)。Boc-QRR-AMC的库存解决方案最好在DMSO中准备。 编号: 187545中文名称: Hepsin substrate&#xff1a;Boc-Gln-Arg-Arg-7-氨基-4-甲基香豆素英文名: Boc-Gln-Arg-Arg-AMCCAS号…

全球No.1集装箱人工智能企业CIMCAI中集飞瞳,集装箱信息识别铅封号识别API免费,集装箱识别率99.98%高泛化性,全球两千+企业用户使用

全球No.1集装箱人工智能企业CIMCAI中集飞瞳&#xff0c;先进人工智能AI科技打造飞瞳引擎™AI集装箱检测云服务&#xff0c;集装箱信息识别铅封号识别API免费&#xff0c;集装箱识别率99.98%高泛化性&#xff0c;全球两千企业用户使用。CIMCAI中集飞瞳成熟港航人工智能核心技术及…

3年功能测试拿8K,被刚入职的应届生反超,其实你在假装努力

最近朋友给我分享了一个他公司发生的事 大概的内容呢&#xff1a;公司一位工作3年的测试工资还没有新人高&#xff0c;对此怨气不小&#xff0c;她来公司辛辛苦苦三年&#xff0c;三年内迟到次数都不超过5次&#xff0c;每天都是按时上下班&#xff0c;工作也按量完成&#xf…

PyQT6关联信号槽 (六) 百篇文章学PyQT6

本文章是百篇文章学PyQT6的第六篇&#xff0c;本文讲述如何使用PySide创建UI界面&#xff0c;并且关联入PyCharm 新建的项目中成功运行第一个PyQT程序&#xff0c;并且使用 信号槽 connect 到函数&#xff0c;在写博客和学习的过程中会遇到很多问题&#xff0c;例如&#xff1a…

Python实现点选验证码识别, B站模拟登陆

话不多说&#xff0c;今天就分享一下如何用Python实现点选验证码识别&#xff0c;小破站模拟登陆 开发环境 Python 3.8Pycharm 2021.2谷歌浏览器谷歌驱动 模块使用 selenium >>> pip install selenium3.141.0 指定版本安装time打码平台 模块安装问题: -如果安装…

Java注解(Annotation)

一、什么是注解 个人理解&#xff0c;注解就是代码中的特殊标记&#xff0c;这些标记可以在编译、类加载、运行时被读取&#xff0c;从而做相对应的处理。 注解跟注释很像&#xff0c;区别是注释是给人看的&#xff1b;而注解是给程序看的&#xff0c;它可以被编译器读取。 …

ERP软件定价策略与模型设计

ERP软件定价(价格)的高低是ERP厂商整体竞争力强弱的一个重要指针&#xff0c;也是影响客户购买行为的重要因素。客户购买某一ERP软件&#xff0c;总是面临不同的ERP厂商﹑不同渠道的多种选择&#xff0c;ERP软件价格往往成了除软件功能﹑售后服务态度、实施水平等因素外&#x…

web前端-Ajax基础学习

web前端-Ajax基础学习1. Ajax基础描述1.1 URL地址的概念1.2 客户端和服务器的通信过程1.3 Ajax1.3.1 $.get()函数1.3.2 $.post()1.3.3 $.ajax()1.4 接口1.4.1 GET、POST方式请求的过程1.4.2 接口文档2. form表单与模版引擎2.1 表单的基本介绍2.2 form表单同步提交的缺点2.3 通过…

stm32 笔记 外部中断以及HAL库应用

外部中断 由外部设备发起的中断请求&#xff0c;会使得设备暂停当前的主程序&#xff0c;保存标志位并把当前指令压入堆栈&#xff0c;转而去执行中断的子程序。执行完毕后再弹出执行堆栈&#xff0c;恢复标志位&#xff0c;继续执行主程序。 STM32 的外部中断线 STM32的每个…

嵌入式 C语言/C++ 常见笔试、面试题 难疑点汇总(经典100道)

#pragma comment。将一个注释记录放置到对象文件或可执行文件中。 #pragma pack。用来改变编译器的字节对齐方式。 #pragma code_seg。它能够设置程序中的函数在obj文件中所在的代码段。如果未指定参数&#xff0c;函数将放置在默认代码段.text中 #pragma once。保证所在文件只…

Pytest接口测试框架实战项目搭建(三)

一、前言 前面相当于已经讲完整体框架搭建了&#xff0c;本篇主要讲述在实际业务系统的接口请求中&#xff0c;如何运用好该接口自动化测试框架。 二、步骤演示 1、在conf/api_path.py新增需要测试的接口&#xff0c;标黄底色为新加 存放测试接口仅这一个文件就行&#xff0c…

吉时利2604B系列数字源表,双通道,3A直流/10A脉冲

作为2600B系列源表SMU系列产品的一部分&#xff0c;2602B源表SMU是全新改良版双通道SMU&#xff0c;具有紧密集成的4象限设计&#xff0c;能同步源和测量电压/电流以提高研发到自动生产测试等应用的生产率。除保留了2602A的全部产品特点外&#xff0c;2602B还具有6位半分辨率、…

Android 面试题收集:Handler+Binder+Activity+时间分发机制+View绘制流程+……等

一、Handler相关知识 一个线程只有一个Looper&#xff0c;一个Messagequeue&#xff0c;可以创建多个handler。 1、Handler与Looper的关联是怎样的? 实例化 Handler 的时候 Handler 会去检查当前线程的 Looper 是否存在&#xff0c;如果不存在则会报异常&#xff0c;也就是…

关于TreeView的简单使用(Qt6.4.1)

前言 TreeView是在Qt6.3中加入的&#xff0c;弥补了Qt中无官方树图。笔者上手尝试了下&#xff0c;虽然有点麻烦&#xff0c;但官方也做了不少简化。 本次教程&#xff0c;笔者创建一个简单的示例&#xff0c;以帮助读者使用TreeView。 一、创建模型类 当前模型需要使用C定义…

人工智能概况笔记

文章目录一、人的智能与人工智能二、人工智能的发展历程三、人工智能的主要应用四、人工智能的伦理思考五、神经网络与深度学习六、国内外人工智能动向一、人的智能与人工智能 智能&#xff1a;基于推理的学习、理解和做出判断或意见的能力 人的智能&#xff08;Human Intell…