Files
threeonecheck_web/utils/watermark.js
2026-06-03 10:16:37 +08:00

95 lines
3.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { nextTick } from 'vue';
/**
* 前端实时渲染防作弊当前时间戳水印
* @param {Object} options
* @param {string} options.tempFilePath - 原始图片临时路径
* @param {string} options.canvasId - canvas的ID名默认为 watermarkCanvas
* @param {Object} options.canvasWidthRef - 绑定的 canvasWidth 响应式变量(ref)
* @param {Object} options.canvasHeightRef - 绑定的 canvasHeight 响应式变量(ref)
* @param {Object} options.instance - 当前Vue组件的实例 (通过 getCurrentInstance() 获取)
* @returns {Promise<string>} 渲染添加完水印后的新图片临时路径
*/
export function addTimestampWatermark({ tempFilePath, canvasId = 'watermarkCanvas', canvasWidthRef, canvasHeightRef, instance }) {
return new Promise((resolve, reject) => {
uni.getImageInfo({
src: tempFilePath,
success: (imageInfo) => {
const imgWidth = imageInfo.width;
const imgHeight = imageInfo.height;
// 动态配置 Canvas 宽高与图片 1:1 比例,确保高清晰度不失真
if (canvasWidthRef && canvasWidthRef.value !== undefined) {
canvasWidthRef.value = imgWidth;
}
if (canvasHeightRef && canvasHeightRef.value !== undefined) {
canvasHeightRef.value = imgHeight;
}
// 延迟至 nextTick 等待 UniApp 应用并渲染新的 Canvas 尺寸
nextTick(() => {
const ctx = uni.createCanvasContext(canvasId, instance);
if (!ctx) {
reject('创建水印画布上下文失败');
return;
}
// 1. 绘制原始图片
ctx.drawImage(tempFilePath, 0, 0, imgWidth, imgHeight);
// 2. 构造防作弊当前真实时间戳字符串
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0');
const day = String(now.getDate()).padStart(2, '0');
const hours = String(now.getHours()).padStart(2, '0');
const minutes = String(now.getMinutes()).padStart(2, '0');
const seconds = String(now.getSeconds()).padStart(2, '0');
const timeStr = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
// 3. 动态计算合适的水印字体大小(以标准 375px 屏幕下的 14px 为基准,按图片实际宽度等比缩放,保证大图下不模糊且比例完美)
const fontSize = Math.max(14, Math.floor(imgWidth * (14 / 375)));
ctx.setFontSize(fontSize);
ctx.setFillStyle('#C9CBD4'); // 水印文字颜色 #C9CBD4
// 设置半透明黑色文字阴影,确保在亮色背景下时间戳也具有极强的辨识度
ctx.setShadow(2, 2, 4, 'rgba(0, 0, 0, 0.6)');
// 4. 计算右下角坐标
const padding = fontSize;
const textWidth = timeStr.length * (fontSize * 0.55); // 估算英文字符占用宽度
const x = imgWidth - textWidth - padding;
const y = imgHeight - padding;
// 5. 渲染防作弊时间戳
ctx.fillText(timeStr, x, y);
// 6. 执行画布绘制并导出文件路径
ctx.draw(false, () => {
setTimeout(() => {
uni.canvasToTempFilePath({
canvasId: canvasId,
destWidth: imgWidth,
destHeight: imgHeight,
fileType: 'jpg',
quality: 0.9,
success: (exportRes) => {
resolve(exportRes.tempFilePath);
},
fail: (err) => {
console.error('导出带水印图片失败:', err);
reject(err);
}
}, instance);
}, 150);
});
});
},
fail: (err) => {
console.error('获取图片信息失败:', err);
reject(err);
}
});
});
}