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} 渲染添加完水印后的新图片临时路径 */ 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); } }); }); }