Thinking--在应用中添加动态水印,且不可删除

Thinking系列,旨在利用10分钟的时间传达一种可落地的编程思想。

水印是一种用于保护版权和识别内容的技术,通常用于图像、视频或文档中。它可以是文本、图像或两者的组合,通常半透明或以某种方式嵌入到内容中,使其不易被移除或篡改。

今天主要阐述,如何在应用中添加动态水印「如下图」。

在这里插入图片描述

静态水印

① 将水印作为背景图片嵌入到页面或特定元素中。

.watermark-background {background-image: url('watermark.png');background-repeat: repeat;opacity: 0.5;
}

② 使用SVG(可缩放矢量图形)可以创建高质量的图像水印。SVG可以被嵌入到HTML中,并且可以很容易地通过CSS进行样式化。

<svg width="100%" height="100%" style="position: fixed; top: 0; left: 0; z-index: -1;"><text x="50%" y="50%" fill="black" font-size="50" text-anchor="middle" opacity="0.05">版权所有</text>
</svg>

易于实现,且不会影响页面的加载和渲染性能;
✅ 不存在层级(zIndex)问题,不会导致交互等问题;
❎ 容易被移除,且不能动态调整文案(在应用系统中,水印往往是登录者信息)

动态水印

简易 Demo

const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');canvas.setAttribute('width', '200px')
canvas.setAttribute('height', '200px')ctx.translate(20, 20); // x、y移动20px
ctx.rotate((Math.PI / 180) * 45);	// 旋转45度ctx.font = 'normal 20px Arial';
ctx.fillStyle = 'rgba(0, 0, 0, 0.1)';
ctx.fillText('李刚', 60, 0);
ctx.font = 'normal 14px Arial';
ctx.fillText('https://ligang.blog.csdn.net/', 0, 20);document.querySelector('body').style.backgroundImage = `url('${canvas.toDataURL()}')` // 以背景图片形式追加

高度定制化:可以根据用户行为或特定条件动态显示或隐藏水印。
❎ 实现较复杂,对页面性能可能有一定的影响(JavaScript实现)

如何防止被删除

const observer = new MutationObserver((mutationList, observer) => {mutationList.forEach((mutation) => {// style 属性被修改,重新追加if (mutation.type === 'attributes' && mutation.attributeName === 'style') {document.querySelector('body').style.backgroundImage = `url('${canvas.toDataURL()}')`}})
})// 接收body变化的通知
observer.observe(document.body, {childList: false, // 监听 target 节点中发生的节点的新增与删除(attributes: true, // 听的 target 节点属性值的变化subtree: false 	  // 监听以 target 为根节点的整个子树(包括子树中所有节点的属性)
})

MutationObserver 提供了监视对 DOM 树所做更改的能力。

🐾 上述简单示意。实际使用时,需要水印宽高(注意像素比),以及水印之间的水平/垂直间距 等一些信息。具体可以参考 【WaterMark】

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

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

相关文章

【Linux】多线程_2

文章目录 九、多线程2. 线程的控制 未完待续 九、多线程 2. 线程的控制 主线程退出 等同于 进程退出 等同于 所有线程都退出。为了避免主线程退出&#xff0c;但是新线程并没有执行完自己的任务的问题&#xff0c;主线程同样要跟进程一样等待新线程返回。 pthread_join 函数…

算法学习笔记(8.2)-动态规划入门进阶

目录 问题判断: 问题求解步骤&#xff1a; 图例&#xff1a; 解析&#xff1a; 方法一&#xff1a;暴力搜索 实现代码如下所示&#xff1a; 解析&#xff1a; 方法二&#xff1a;记忆化搜索 代码示例&#xff1a; 解析&#xff1a; 方法三&#xff1a;动态规划 空间…

Qt入门(二):Qt的基本组件

目录 Designer程序面板 1、布局Layout 打破布局 贴合窗口 2、QWidget的属性 3、Qlabel标签 显示图片 4、QAbstractButton 按钮类 按钮组 5、QLineEdit 单行文本输入框 6、ComboBox 组合框 7、若干与数字相关的组件 Designer程序面板 Qt包含了一个Designer程序 &…

Django 更新数据 save()方法

1&#xff0c;添加模型 Test/app11/models.py from django.db import modelsclass Post(models.Model):title models.CharField(max_length200)content models.TextField()pub_date models.DateTimeField(date published)class Book(models.Model):title models.CharFie…

Spring Boot集成grpc快速入门demo

1.什么是GRPC&#xff1f; gRPC 是一个高性能、开源、通用的RPC框架&#xff0c;由Google推出&#xff0c;基于HTTP2协议标准设计开发&#xff0c;默认采用Protocol Buffers数据序列化协议&#xff0c;支持多种开发语言。gRPC提供了一种简单的方法来精确的定义服务&#xff0c…

UE5.3-基础蓝图类整理一

常用蓝图类整理&#xff1a; 1、获取当前关卡名&#xff1a;Get Current LevelName 2、通过关卡名打开关卡&#xff1a;Open Level(by name) 3、碰撞检测事件&#xff1a;Event ActorBeginOverlap 4、获取当前player&#xff1a;Get Player Pawn 5、判断是否相等&#xff1…

WEB安全基础:网络安全常用术语

一、攻击类别 漏洞&#xff1a;硬件、软件、协议&#xff0c;代码层次的缺陷。 后⻔&#xff1a;方便后续进行系统留下的隐蔽后⻔程序。 病毒&#xff1a;一种可以自我复制并传播&#xff0c;感染计算机和网络系统的恶意软件(Malware)&#xff0c;它能损害数据、系统功能或拦…

C++语言学习精简笔记(包含C++20特性)

目录 1 C新语法C与CC编译运行String编程范式C基础类型**自动类型推导**统一对象初始化&#xff1a;Uniform Initialization 控制结构if语句for语句switch语句namespace 2 函数函数声明形式参数函数参数传递的选择函数返回值的选择 函数重载 Lambda表达式函数的定义和申明生存期…

【一】m2芯片的mac中安装ubuntu24虚拟机集群

文章目录 1. 虚拟机配置2. 复制虚拟机2.1 修改主机名2.2 修改网络 1. 虚拟机配置 在官方网站下载好ubuntu24-arm版镜像开始安装&#xff0c;安装使用VMWare Fusion的社区免费授权版,使用一台m2芯片的mac电脑作为物理机平台。 为什么选择ubuntu24&#xff1f;因为centOS7目前已…

Proteus + Keil单片机仿真教程(五)多位LED数码管的静态显示

Proteus + Keil单片机仿真教程(五)多位LED数码管 上一章节讲解了单个数码管的静态和动态显示,这一章节将对多个数码管的静态显示进行学习,本章节主要难点: 1.锁存器的理解和使用; 2.多个数码管的接线封装方式; 3.Proteus 快速接头的使用。 第一个多位数码管示例 元件…

『C + ⒈』‘\‘

&#x1f942;在反斜杠(\)有⒉种最常用的功能如下所示&#x1f44b; #define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> int main(void) {int a 10;int b 20;int c 30;if (a 10 &&\b 20 &&\c 30){printf("Your print\n");}else{prin…

二分查找3

1. 有序数组中的单一元素&#xff08;540&#xff09; 题目描述&#xff1a; 算法原理&#xff1a; 二分查找解题关键就在于去找到数组的二段性&#xff0c;这里数组的二段性是从单个数字a开始出现然后分隔出来的&#xff0c;如果mid落入左半部分那么当mid为偶数时nums[mid1]…

ByteMD富文本编辑器的vue3配置

Git地址&#xff1a;GitHub - bytedance/bytemd: ByteMD v1 repository 控制面板输入 npm install bytemd/vue-next 下载成功后在src/main.ts中引用 import "bytemd/dist/index.css";引入后保存&#xff0c;下面是一些插件&#xff0c;比如说我用到gmf和hightLight&…

彩色图像(RGB)或灰度图像(Gray)转tensor数据(附img2tensor代码)

&#x1f4aa; 专业从事且热爱图像处理&#xff0c;图像处理专栏更新如下&#x1f447;&#xff1a; &#x1f4dd;《图像去噪》 &#x1f4dd;《超分辨率重建》 &#x1f4dd;《语义分割》 &#x1f4dd;《风格迁移》 &#x1f4dd;《目标检测》 &#x1f4dd;《暗光增强》 &a…

CompletableFuture工具类使用

CompletableFuture工具类可以帮助实现Java并发编程中的任务编排 以上除了join用于阻塞调用该方法的线程并且接受CompletableFuture的返回值以外其它方法皆有Async异步和Executor指定线程池选项 对于supply,run,apply,accept的区别在于函数式编程的接口类型不同: supply: Sup…

tk 文本生成器

import random import tkinter as tk import ttkbootstrap as ttk from tkinter import messagebox import pyperclipdef wenben_run():def generate_text(original_text, length):# 去掉原始文本中的换行符和空格original_text original_text.replace(\n, )original_text or…

Windows11配置WSL2支持代理上网

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、安装WSL2分发版二、配置步骤三、测试总结 前言 说起来本来这个功能我也不需要的&#xff0c;只是最近突然有个需求就顺便研究了下&#xff0c;WSL2默认的网…

北京大学长安汽车发布毫米波与相机融合模型RCBEVDet:最快能达到每秒28帧

Abstract 三维目标检测是自动驾驶中的关键任务之一。为了在实际应用中降低成本&#xff0c;提出了利用低成本的多视角相机进行3D目标检测&#xff0c;以取代昂贵的LiDAR传感器。然而&#xff0c;仅依靠相机很难实现高精度和鲁棒性的3D目标检测。解决这一问题的有效方法是将多视…

C++入门基础(2)

目录 一、引用: 1、定义&#xff1a; 2、特性&#xff1a; 3、引用的使用&#xff1a; 4、const引用&#xff1a;控制权限 const引用定义: const引用可以接收3种对象&#xff1a; 1、正常对象&#xff1a; 2、临时对象&#xff1a; 3、const对象&#xff1a; 总结&…

C++笔试强训3

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、选择题1-5题6-10题 二、编程题题目一题目二 一、选择题 1-5题 如图所示&#xff0c;如图所示p-3指向的元素是6&#xff0c;printf里面的是%s&#xff0c;从6开…