gemini_watermark_cleaner/js/core/blendModes.js

62 lines
2.1 KiB
JavaScript
Raw Normal View History

2025-12-19 09:10:36 +00:00
/**
* 反向 Alpha 混合模块
* 实现去除水印的核心算法
*/
// 常量定义
const ALPHA_THRESHOLD = 0.002; // 忽略极小的 alpha 值(噪声)
const MAX_ALPHA = 0.99; // 避免除以接近零的值
const LOGO_VALUE = 255; // 白色水印的颜色值
/**
* 使用反向 alpha 混合移除水印
*
* 原理
* Gemini 添加水印: watermarked = α × logo + (1 - α) × original
* 反向求解: original = (watermarked - α × logo) / (1 - α)
*
* @param {ImageData} imageData - 要处理的图像数据会被原地修改
* @param {Float32Array} alphaMap - Alpha 通道数据
* @param {Object} position - 水印位置 {x, y, width, height}
*/
export function removeWatermark(imageData, alphaMap, position) {
const { x, y, width, height } = position;
// 遍历水印区域的每个像素
for (let row = 0; row < height; row++) {
for (let col = 0; col < width; col++) {
// 计算在原图中的索引RGBA 格式,每个像素 4 个字节)
const imgIdx = ((y + row) * imageData.width + (x + col)) * 4;
// 计算在 alpha map 中的索引
const alphaIdx = row * width + col;
// 获取 alpha 值
let alpha = alphaMap[alphaIdx];
// 跳过极小的 alpha 值(噪声)
if (alpha < ALPHA_THRESHOLD) {
continue;
}
// 限制 alpha 值,避免除零
alpha = Math.min(alpha, MAX_ALPHA);
const oneMinusAlpha = 1.0 - alpha;
// 对 RGB 三个通道应用反向 alpha 混合公式
for (let c = 0; c < 3; c++) {
const watermarked = imageData.data[imgIdx + c];
// 反向 alpha 混合公式
const original = (watermarked - alpha * LOGO_VALUE) / oneMinusAlpha;
// 裁剪到 [0, 255] 范围
imageData.data[imgIdx + c] = Math.max(0, Math.min(255, Math.round(original)));
}
// Alpha 通道保持不变
// imageData.data[imgIdx + 3] 不需要修改
}
}
}