Canvas 添加水印向下兼容版
摘要:watermarks脚本文件 // watermarks.ts interface WatermarkOptions { rabbitStudent_innerText?: string | Array<String>; rabbitStudent_canvasWidth?: number; rabbitStudent_canvasHeight?: number; rabbitStudent_canvasX?: number; rabbitStudent_canvasY?: number; rabbitStudent_canvasAngle?: number; rabbitStudent_canvasFont?: string; rabbitStudent_canvasFillStyle?: string; rabbitStudent_canvasTextAlign?: string; rabbitStudent_divTop?: number; rabbitStudent_divLeft?: number; rabbitStudent_zIndex?: number; } // 换行显示 function wrapTextWithComma(context, text, maxWidth = 500 { // 增强分割逻辑(处理连续逗号) const segments = text.split(/(,+ /g // 匹配连续逗号 .filter(seg =</String><!--autointro-->...
watermarks脚本文件
// watermarks.ts
interface WatermarkOptions {
rabbitStudent_innerText?: string | Array<String>;
rabbitStudent_canvasWidth?: number;
rabbitStudent_canvasHeight?: number;
rabbitStudent_canvasX?: number;
rabbitStudent_canvasY?: number;
rabbitStudent_canvasAngle?: number;
rabbitStudent_canvasFont?: string;
rabbitStudent_canvasFillStyle?: string;
rabbitStudent_canvasTextAlign?: string;
rabbitStudent_divTop?: number;
rabbitStudent_divLeft?: number;
rabbitStudent_zIndex?: number;
}
// 换行显示
function wrapTextWithComma(context, text, maxWidth = 500) {
// 增强分割逻辑(处理连续逗号)
const segments = text.split(/(,+)/g) // 匹配连续逗号
.filter(seg => seg !== '')
.reduce((arr, seg) => {
if (/^,+$/.test(seg)) {
// 将连续逗号视为单个换行标记
arr.push({ type: 'comma' })
} else {
// 合并文本段
if (arr.length > 0 && arr[arr.length-1].type === 'text') {
arr[arr.length-1].value += seg
} else {
arr.push({ type: 'text', value: seg })
}
}
return arr
}, [])
const lines = []
let currentLine = ''
// 处理每个语义段
segments.forEach((seg, index) => {
if (seg.type === 'comma') {
// 强制换行并保留至少一个逗号
lines.push(currentLine + (seg.value?.[0] || ','))
currentLine = ''
} else {
// 逐字符处理保证完整性
let tempLine = currentLine
for (const char of seg.value) {
const testLine = tempLine + char
if (context.measureText(testLine).width > maxWidth) {
lines.push(tempLine)
tempLine = char // 新行开始
} else {
tempLine = testLine
}
}
currentLine = tempLine
}
})
// 处理最后剩余内容
if (currentLine !== '') lines.push(currentLine)
return lines.map(v => v?.replace(',', '')).filter(line => line.trim() !== '') // 过滤空行
}
// 增强绘制方法(自动处理超出画布内容)
function drawText(context, lines, x, y, lineHeight) {
const canvas = context.canvas
const maxLines = Math.floor((canvas.height - y) / lineHeight)
lines.slice(0, maxLines).forEach((line, index) => {
context.fillText(line, x, y + index * lineHeight)
})
// 添加省略号提示
if (lines.length > maxLines) {
const lastLine = lines[maxLines-1]
const ellipsis = '...'
let truncated = lastLine
while (context.measureText(truncated + ellipsis).width > canvas.width - x) {
truncated = truncated.slice(0, -1)
}
context.fillText(truncated + ellipsis, x, y + (maxLines-1) * lineHeight)
}
}
/**
* @description 设置水印
* @description 使用方法 import { getmark } from '@/utils/watermarks';
* @description const {watermark}=getmark() watermark(传参)
* @author rabbitStudent 小菟同学
* @param {Object} obj 水印参数
* @param {String | Array} obj.rabbitStudent_innerText 参数:水印文字--必填
* @param {Number} obj.rabbitStudent_canvasWidth 参数:canvas宽度
* @param {Number} obj.rabbitStudent_canvasHeight 参数:canvas高度
* @param {Number} obj.rabbitStudent_canvasX 参数:canvasX轴
* @param {Number} obj.rabbitStudent_canvasY 参数:canvasY轴
* @param {Number} obj.rabbitStudent_canvasAngle 参数:canvas旋转角度
* @param {String} obj.rabbitStudent_canvasFont 参数:canvas字体
* @param {String} obj.rabbitStudent_canvasFillStyle 参数:canvas字体颜色
* @param {String} obj.rabbitStudent_canvasTextAlign 参数:canvas对齐方式
* @param {Number} obj.rabbitStudent_divTop 参数:div距离顶部距离
* @param {Number} obj.rabbitStudent_divLeft 参数:div距离左侧距离
* @param {Number} obj.rabbitStudent_zIndex 参数:div层级
* @date 2024-4-25 15:27
* @returns
*/
export const getmark = () => {
const setWatermark = (row:WatermarkOptions) => {
const {
rabbitStudent_innerText,
rabbitStudent_canvasWidth,//canvas宽度
rabbitStudent_canvasHeight,//canvas高度
rabbitStudent_canvasX,
rabbitStudent_canvasY,
rabbitStudent_canvasAngle,//canvas旋转角度
rabbitStudent_canvasFont,//canvas字体
rabbitStudent_canvasFillStyle,
rabbitStudent_canvasTextAlign,//canvas对齐方式
rabbitStudent_divTop,
rabbitStudent_divLeft,
rabbitStudent_zIndex,
}=row
const id = "1.23452384164.123412416";
if (document.getElementById(id) !== null) {
document.body.removeChild(document.getElementById(id)!);
}
//创建一个画布
const can = document.createElement("canvas");
//设置画布的长宽
can.width = rabbitStudent_canvasWidth;
can.height = rabbitStudent_canvasHeight;
const cans = can.getContext("2d")!;
// const { width } = cans.measureText(rabbitStudent_innerText);
// const canvasSize = Math.max(200, width) * devicePixelRatio;
// console.log(canvasSize)
// can.width = canvasSize;
// can.height = canvasSize;
//旋转角度
cans.rotate((rabbitStudent_canvasAngle * Math.PI) / 180);
cans.font = rabbitStudent_canvasFont;
//设置填充绘画的颜色、渐变或者模式
cans.fillStyle = rabbitStudent_canvasFillStyle;
//设置文本内容的当前对齐方式
cans.textAlign = rabbitStudent_canvasTextAlign;
//设置在绘制文本时使用的当前文本基线
// cans.textBaseline = "Middle";
//在画布上绘制填色的文本(输出的文本,开始绘制文本的X坐标位置,开始绘制文本的Y坐标位置)
if(rabbitStudent_innerText?.indexOf(',') != '-1'){
// wrapText(cans, rabbitStudent_innerText)
const wrappedLines = wrapTextWithComma(cans, rabbitStudent_innerText, 200)
// 绘制文本
drawText(cans, wrappedLines, 10, 100, 20) // x=10, y=100, 行高=20
}else {
cans.fillText(rabbitStudent_innerText, can.width / rabbitStudent_canvasX, can.height / rabbitStudent_canvasY);
}
const div = document.createElement("div");
div.id = id;
div.style.pointerEvents = "none";
div.style.top = rabbitStudent_divTop+'px';
div.style.left =rabbitStudent_divLeft+"px";
div.style.position = "fixed";
div.style.zIndex = rabbitStudent_zIndex;
div.style.width = document.documentElement.clientWidth + "px";
div.style.height = document.documentElement.clientHeight + "px";
div.style.background =
"url(" + can.toDataURL("image/png") + ") left top repeat";
document.body.appendChild(div);
return id;
};
const watermark = (obj: WatermarkOptions) => {
//默认设置
const defaultSetting:WatermarkOptions={
rabbitStudent_innerText:'',
rabbitStudent_canvasWidth:400,//canvas宽度
rabbitStudent_canvasHeight:200,//canvas高度
rabbitStudent_canvasX:8,
rabbitStudent_canvasY:2,
rabbitStudent_canvasAngle:-22,//canvas旋转角度
rabbitStudent_canvasFont:'18px Vedana',//canvas字体
rabbitStudent_canvasFillStyle:'rgba(0, 0, 0, 0.3)',
rabbitStudent_canvasTextAlign:'middle',//canvas对齐方式
rabbitStudent_divTop:0,
rabbitStudent_divLeft:0,
rabbitStudent_zIndex:1,
}
let mergeObj=merge({},defaultSetting,obj)
let id = setWatermark(mergeObj);
// setInterval(() => {
// //防止用户进行删除元素
// if (document.getElementById(id) === null) {
// id = setWatermark(mergeObj);
// }
// //防止用户进行隐藏元素
// if(hasDeveloperToolClasses(document.getElementById(id))){
// document.body.removeChild(document.getElementById(id)!);
// id=setWatermark(mergeObj)
// }
// //防止用户使用display:none
// if(document.getElementById(id).style.display=='none'){
// document.getElementById(id).style.display='block'
// }
// }, 1000);
window.onresize = () => {
setWatermark(mergeObj);
};
};
return { watermark };
};
// 检查水印元素是否包含开发者工具添加的特殊类
function hasDeveloperToolClasses(element) {
return element.classList.contains("__web-inspector-hide-shortcut__") ||
element.classList.contains("__web-inspector-hide-shortcut__") ||
element.classList.contains("__web-inspector-hidebefore-shortcut__") ||
element.classList.contains("__web-inspector-hideafter-shortcut__") ||
hasDeveloperToolClassesInChildren(element);
}
// 检查水印元素的子元素是否包含开发者工具添加的特殊类
function hasDeveloperToolClassesInChildren(element) {
var children = element.querySelectorAll("*");
for (var i = 0; i < children.length; i++) {
if (hasDeveloperToolClasses(children[i])) {
return true;
}
}
return false;
}
function merge(target, ...sources) {
// 遍历所有的源对象
for (const source of sources) {
// 遍历源对象的所有属性
for (const key in source) {
// 如果属性是对象,则递归调用 merge
if (typeof source[key] === 'object') {
// 如果目标对象不存在该属性,则创建一个空对象
if (!target[key]) {
target[key] = {};
}
// 递归调用 merge
merge(target[key], source[key]);
} else {
// 否则直接赋值给目标对象的属性
target[key] = source[key];
}
}
}
// 返回合并后的目标对象
return target;
}
使用
import { getmark } from '@/utils/watermarks.ts'
// 辅助函数用于创建水印
let obj = { rabbitStudent_innerText: `禁止截图外传` };
const { idCard, username } = userInfo;
let obj = { rabbitStudent_innerText: `${username},${idCard ?? ''},${parseTime(new Date())}` };
// 如果需要换行的话需要使用下面的方式,中间用 , 分隔传参。第一种传参不支持换行
const addWatermark = (obj) => {
const {
watermark
} = getmark()
watermark(obj)
};
本文链接:https://blog.smallhao.fun/?id=26 转载需授权!
Chen’Blog版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!