main
mula.liu 2026-02-03 13:13:33 +08:00
parent a3ffa67a66
commit 0ecad3a423
26 changed files with 208 additions and 419 deletions

2
.env.sample 100644
View File

@ -0,0 +1,2 @@
# Application Port
PORT=3000

32
Dockerfile 100644
View File

@ -0,0 +1,32 @@
# Stage 1: Build the application
FROM swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/node:20-alpine AS builder
WORKDIR /app
# Enable pnpm
RUN corepack enable && corepack prepare pnpm@latest --activate
# Copy package management files
COPY package.json pnpm-lock.yaml ./
# Install dependencies (ignoring scripts to speed up and safer)
# Removing frozen-lockfile restriction in case of version mismatch, ensuring install works
RUN pnpm install --no-frozen-lockfile
# Copy source code
COPY . .
# Build the project
RUN pnpm build
# Stage 2: Serve with Nginx
FROM swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/nginx:alpine
# Copy built assets from builder stage
COPY --from=builder /app/dist /usr/share/nginx/html
# Expose port 80 (internal container port)
EXPOSE 80
# Start Nginx
CMD ["nginx", "-g", "daemon off;"]

243
README.md
View File

@ -1,221 +1,92 @@
[中文文档](README_zh.md) [中文文档](README_zh.md)
# Gemini Lossless Watermark Remover - [banana.ovo.re](https://banana.ovo.re) # Gemini & NotebookLM Watermark Cleaner
A high-performance, 100% client-side tool for removing Gemini AI watermarks. Built with pure JavaScript, it leverages a mathematically precise **Reverse Alpha Blending** algorithm rather than unpredictable AI inpainting. A privacy-first, browser-based tool for removing watermarks from Gemini and NotebookLM generated content (Images & PDFs). Built with vanilla JavaScript, featuring mathematical precision for lossless restoration and robust fallback cloning for complex document formats.
<p align="center"> <p align="center">
<img src="https://count.getloli.com/@gemini-watermark-remover?name=gemini-watermark-remover&theme=minecraft&padding=7&offset=0&align=top&scale=1&pixelated=1&darkmode=auto" width="400"> <img src="https://count.getloli.com/@gemini-watermark-remover?name=gemini-watermark-remover&theme=minecraft&padding=7&offset=0&align=top&scale=1&pixelated=1&darkmode=auto" width="400">
</p> </p>
## Features ## Features
- ✅ **100% Client-side** - No backend, no server-side processing. Your data stays in your browser. - **Multi-Format Support**: Handles standard Gemini Images (`.jpg`, `.png`, `.webp`) and NotebookLM documents (`.pdf`).
- ✅ **Privacy-First** - Images are never uploaded to any server. Period. - **Lossless Restoration**: Uses **Reverse Alpha Blending** for standard Gemini images to perfectly restore original pixels without blurring.
- ✅ **Mathematical Precision** - Based on the Reverse Alpha Blending formula, not "hallucinating" AI models. - **Smart Cloning**: Applies intelligent **Simple Clone** (patching) for NotebookLM headers/footers and PDF slides where alpha maps don't apply.
- ✅ **Auto-Detection** - Intelligent recognition of 48×48 or 96×96 watermark variants. - **Privacy-First**: 100% client-side processing. No files are ever uploaded to any server.
- ✅ **User Friendly** - Simple drag-and-drop interface with instant processing. - **Batch Processing**: Process multiple files at once and download them as a ZIP archive.
- ✅ **Cross-Platform** - Runs smoothly on all modern web browsers. - **Modern UI**: Dark/Light mode support with a clean, responsive interface.
- **PDF Preview**: Real-time progress tracking and preview for PDF file cleaning.
## Examples ## 🛠️ Technology Stack
<details open> - **Core Logic**: Vanilla JavaScript (ES Modules)
<summary>Click to Expand/Collapse Examples</summary> - **PDF Processing**: `pdfjs-dist` (Parsing) & `jspdf` (Re-generation)
  - **UI Styling**: Tailwind CSS (CDN)
<p>lossless diff example</p> - **Packaging**: `esbuild` for bundling
<p><img src="docs/lossless_diff.webp"></p>
## 🧩 How It Works
<p>example images</p> This tool employs two distinct strategies depending on the content type:
| Original Image | Watermark Removed | ### 1. Reverse Alpha Blending (for Gemini Images)
| :---: | :----: | Gemini applies watermarks using a standard alpha compositing formula:
| <img src="docs/1.webp" width="400"> | <img src="docs/unwatermarked_1.webp" width="400"> | $$Pixel_{watermarked} = \alpha \cdot Pixel_{logo} + (1 - \alpha) \cdot Pixel_{original}$$
| <img src="docs/2.webp" width="400"> | <img src="docs/unwatermarked_2.webp" width="400"> |
| <img src="docs/3.webp" width="400"> | <img src="docs/unwatermarked_3.webp" width="400"> |
| <img src="docs/4.webp" width="400"> | <img src="docs/unwatermarked_4.webp" width="400"> |
| <img src="docs/5.webp" width="400"> | <img src="docs/unwatermarked_5.webp" width="400"> |
</details> We reverse this to recover the original pixel:
$$Pixel_{original} = \frac{Pixel_{watermarked} - \alpha \cdot Pixel_{logo}}{1 - \alpha}$$
## ⚠️ Disclaimer By using pre-calibrated Alpha Maps (48px/96px), we can mathematically restore the original pixel values with near-zero loss.
> [!WARNING] ### 2. Smart Cloning (for NotebookLM & PDF)
> **USE AT YOUR OWN RISK** For NotebookLM's strip-like watermarks or PDF slides where exact alpha maps vary, the tool uses a **Simple Clone** technique. It identifies the watermark region and intelligently "clones" a patch of pixels from the immediate neighborhood (e.g., just above the watermark) to cover it, blending the edges for a seamless look.
>
> This tool modifies image files. While it is designed to work reliably, unexpected results may occur due to:
> - Variations in Gemini's watermark implementation
> - Corrupted or unusual image formats
> - Edge cases not covered by testing
>
> The author assumes no responsibility for any data loss, image corruption, or unintended modifications. By using this tool, you acknowledge that you understand these risks.
> [!NOTE] ## 🔗 Attribution & References
> **Note**: Disabling any fingerprint defender extensions (e.g., Canvas Fingerprint Defender) to avoid processing errors. https://github.com/journey-ad/gemini-watermark-remover/issues/3
## Usage This project is built upon the excellent work of the open-source community. Special thanks to:
### Online Website - **Original Project**: [gemini-watermark-remover](https://github.com/journey-ad/gemini-watermark-remover) by [journey-ad](https://github.com/journey-ad).
- *Base architecture, alpha map logic, and core "Reverse Alpha Blending" implementation.*
1. Open [banana.ovo.re](https://banana.ovo.re). - **Algorithm Origin**: [Gemini Watermark Tool](https://github.com/allenk/GeminiWatermarkTool) by [Allen Kuo](https://github.com/allenk).
2. Drag and drop or click to select your Gemini-generated image. - *Original discovery of the math and watermark masks.*
3. The engine will automatically process and remove the watermark.
4. Download the cleaned image.
### Userscript for Gemini Conversation Pages ## 🚀 Usage
1. Install a userscript manager (e.g., Tampermonkey or Greasemonkey).
2. Open [gemini-watermark-remover.user.js](https://banana.ovo.re/userscript/gemini-watermark-remover.user.js).
3. The script will install automatically.
4. Navigate to Gemini conversation pages.
5. Click "Copy Image" or "Download Image" to remove the watermark.
## Development
### Development
1. Clone the repository:
```bash
git clone http://git.unissense.tech/mula/gemini_watermark_cleaner.git
```
2. Install dependencies:
```bash ```bash
# Install dependencies
pnpm install pnpm install
```
# Development build 3. Start development mode (rebuilds on changes):
```bash
pnpm dev pnpm dev
```
# Production build 4. Start a local preview server:
pnpm build ```bash
# Local preview
pnpm serve pnpm serve
``` ```
5. Build for production:
## How it Works ```bash
pnpm build
### The Gemini Watermarking Process
Gemini applies watermarks using standard alpha compositing:
$$watermarked = \alpha \cdot logo + (1 - \alpha) \cdot original$$
Where:
- `watermarked`: The pixel value with the watermark.
- `α`: The Alpha channel value (0.0 - 1.0).
- `logo`: The watermark logo color value (White = 255).
- `original`: The raw, original pixel value we want to recover.
### The Reverse Solution
To remove the watermark, we solve for `original`:
$$original = \frac{watermarked - \alpha \cdot logo}{1 - \alpha}$$
By capturing the watermark on a known solid background, we reconstruct the exact Alpha map and apply the inverse formula to restore the original pixels with zero loss.
## Detection Rules
| Image Dimension Condition | Watermark Size | Right Margin | Bottom Margin |
| :--- | :--- | :--- | :--- |
| Width > 1024 **AND** Height > 1024 | 96×96 | 64px | 64px |
| Otherwise | 48×48 | 32px | 32px |
## Project Structure
```text
gemini-watermark-remover/
├── public/
│ ├── index.html # Main page
│ └── terms.html # Terms of Service page
├── src/
│ ├── core/
│ │ ├── alphaMap.js # Alpha map calculation logic
│ │ ├── blendModes.js # Implementation of Reverse Alpha Blending
│ │ └── watermarkEngine.js # Main engine coordinator
│ ├── assets/
│ │ ├── bg_48.png # Pre-captured 48×48 watermark map
│ │ └── bg_96.png # Pre-captured 96×96 watermark map
│ ├── i18n/ # Internationalization language files
│ ├── userscript/ # Userscript for Gemini
│ ├── app.js # Website application entry point
│ └── i18n.js # Internationalization utilities
├── dist/ # Build output directory
├── build.js # Build script
└── package.json
``` ```
## Core Modules ### Docker Deployment
1. Build and run the container:
### alphaMap.js ```bash
docker-compose up -d --build
Calculates the Alpha channel by comparing captured watermark assets:
```javascript
export function calculateAlphaMap(bgCaptureImageData) {
// Extract max RGB channel and normalize to [0, 1]
const alphaMap = new Float32Array(width * height);
for (let i = 0; i < alphaMap.length; i++) {
const maxChannel = Math.max(r, g, b);
alphaMap[i] = maxChannel / 255.0;
}
return alphaMap;
}
``` ```
2. The application will be available at `http://localhost:3000` (or the port specified in `.env`).
### blendModes.js ### Browser
Simply open the `dist/index.html` (after building) or the deployed site. Drag and drop your files.
- **Images**: Instant preview and cleaning.
- **PDFs**: Shows progress per page, then displays the cleaned first page.
The mathematical core of the tool: ## 📄 License
```javascript
export function removeWatermark(imageData, alphaMap, position) {
// Formula: original = (watermarked - α × 255) / (1 - α)
for (let row = 0; row < height; row++) {
for (let col = 0; col < width; col++) {
const alpha = Math.min(alphaMap[idx], MAX_ALPHA);
const original = (watermarked - alpha * 255) / (1.0 - alpha);
imageData.data[idx] = Math.max(0, Math.min(255, original));
}
}
}
```
## Browser Compatibility
- ✅ Chrome 90+
- ✅ Firefox 88+
- ✅ Safari 14+
- ✅ Edge 90+
Required APIs:
- ES6 Modules
- Canvas API
- Async/Await
- TypedArray (Float32Array, Uint8ClampedArray)
---
## Limitations
- Only removes **Gemini visible watermarks** <small>(the semi-transparent logo in bottom-right)</small>
- Does not remove invisible/steganographic watermarks. <small>[(Learn more about SynthID)](https://support.google.com/gemini/answer/16722517)</small>
- Designed for Gemini's current watermark pattern <small>(as of 2025)</small>
## Legal Disclaimer
This tool is provided for **personal and educational use only**.
The removal of watermarks may have legal implications depending on your jurisdiction and the intended use of the images. Users are solely responsible for ensuring their use of this tool complies with applicable laws, terms of service, and intellectual property rights.
The author does not condone or encourage the misuse of this tool for copyright infringement, misrepresentation, or any other unlawful purposes.
**THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY ARISING FROM THE USE OF THIS SOFTWARE.**
## Credits
This project is a JavaScript port of the [Gemini Watermark Tool](https://github.com/allenk/GeminiWatermarkTool) by Allen Kuo ([@allenk](https://github.com/allenk)).
The Reverse Alpha Blending method and calibrated watermark masks are based on the original work © 2024 AllenK (Kwyshell), licensed under MIT License.
## Related Links
- [Gemini Watermark Tool](https://github.com/allenk/GeminiWatermarkTool)
- [Removing Gemini AI Watermarks: A Deep Dive into Reverse Alpha Blending](https://allenkuo.medium.com/removing-gemini-ai-watermarks-a-deep-dive-into-reverse-alpha-blending-bbbd83af2a3f)
## License
[MIT License](./LICENSE) [MIT License](./LICENSE)

View File

@ -1,241 +1,92 @@
[English](README.md) [English](README.md)
# Gemini 无损去水印工具 - [banana.ovo.re](https://banana.ovo.re) # Gemini & NotebookLM 无损去水印工具
基于 Javascript 的纯浏览器端 Gemini AI 图像无损去水印工具,使用数学精确的反向 Alpha 混合算法 基于浏览器的隐私优先去水印工具,专为处理 Gemini 和 NotebookLM 生成的内容(图片及 PDF而设计。项目采用原生 JavaScript 构建,结合了数学精确的无损还原算法与鲁棒的智能修补技术。
<p align="center"> <p align="center">
<img src="https://count.getloli.com/@gemini-watermark-remover?name=gemini-watermark-remover&theme=minecraft&padding=7&offset=0&align=top&scale=1&pixelated=1&darkmode=auto" width="400"> <img src="https://count.getloli.com/@gemini-watermark-remover?name=gemini-watermark-remover&theme=minecraft&padding=7&offset=0&align=top&scale=1&pixelated=1&darkmode=auto" width="400">
</p> </p>
## 特性 ## ✨ 功能特性
- ✅ **纯浏览器端处理** - 无需后端服务器,所有处理在本地完成 - **多格式支持**:完美支持 Gemini 生成的标准图片 (`.jpg`, `.png`, `.webp`) 以及 NotebookLM 文档 (`.pdf`)。
- ✅ **隐私保护** - 图片不会上传到任何服务器 - **无损还原**:针对 Gemini 标准图片,采用 **反向 Alpha 混合 (Reverse Alpha Blending)** 算法,像素级还原原图,拒绝模糊。
- ✅ **数学精确** - 基于反向 Alpha 混合算法,非 AI 模型 - **智能修补**:针对 NotebookLM 的条状水印或 PDF 幻灯片,采用 **智能克隆 (Simple Clone)** 技术,自动采样邻近像素进行修补融合。
- ✅ **自动检测** - 自动识别 48×48 或 96×96 水印尺寸 - **隐私优先**100% 纯浏览器本地处理,任何文件都不会上传至服务器。
- ✅ **易于使用** - 拖拽选择图片,一键处理 - **批量处理**:支持多文件拖拽上传,处理完成后可打包为 ZIP 一键下载。
- ✅ **跨平台** - 支持所有现代浏览器 - **现代 UI**:支持深色/浅色模式切换,界面简洁响应快。
- **PDF 预览**PDF 处理时实时显示页码进度,完成后可预览处理好的首页。
## 效果示例 ## 🛠️ 技术栈
<details open> - **核心逻辑**: Vanilla JavaScript (ES Modules)
<summary>点击查看/收起示例</summary> - **PDF 处理**: `pdfjs-dist` (解析) & `jspdf` (生成)
  - **UI 样式**: Tailwind CSS (CDN)
<p>无损 diff 示例</p> - **构建工具**: `esbuild`
<p><img src="docs/lossless_diff.webp"></p>
## 🧩 原理说明
<p>示例图片</p> 本工具根据文件类型自动选择两种不同的处理策略:
| 原图 | 去水印后 | ### 1. 反向 Alpha 混合 (适用于 Gemini 图片)
| :---: | :----: | Gemini 添加水印使用的是标准的 Alpha 合成公式:
| <img src="docs/1.webp" width="400"> | <img src="docs/unwatermarked_1.webp" width="400"> | $$Pixel_{watermarked} = \alpha \cdot Pixel_{logo} + (1 - \alpha) \cdot Pixel_{original}$$
| <img src="docs/2.webp" width="400"> | <img src="docs/unwatermarked_2.webp" width="400"> |
| <img src="docs/3.webp" width="400"> | <img src="docs/unwatermarked_3.webp" width="400"> |
| <img src="docs/4.webp" width="400"> | <img src="docs/unwatermarked_4.webp" width="400"> |
| <img src="docs/5.webp" width="400"> | <img src="docs/unwatermarked_5.webp" width="400"> |
</details> 我们通过反向推导来恢复原始像素:
$$Pixel_{original} = \frac{Pixel_{watermarked} - \alpha \cdot Pixel_{logo}}{1 - \alpha}$$
## ⚠️ 使用需注意 利用预先提取的 Alpha Map48px/96px我们可以精确计算出原始像素值实现近乎零损失的还原。
> [!WARNING] ### 2. 智能克隆修补 (适用于 NotebookLM & PDF)
> **使用此工具产生的风险由用户自行承担** 对于 NotebookLM 的条状水印或某些 PDF 页面,由于缺乏固定的 Alpha Map工具采用 **Simple Clone** 技术。它自动定位水印区域,从紧邻水印上方或周围的区域“克隆”像素块覆盖水印,并对边缘进行羽化融合,从而达到视觉上的消除效果。
>
> 本工具涉及对图像数据的修改。尽管在设计上力求处理结果的可靠性,但由于以下因素,仍可能产生非预期的处理结果:
> - Gemini 水印实现方式的更新或变动
> - 图像文件损坏或使用了非标准格式
> - 测试案例未能覆盖的边界情况
>
> 作者对任何形式的数据丢失、图像损坏或非预期的修改结果不承担法律责任。使用本工具即代表您已了解并接受上述风险。
> [!NOTE] ## 🔗 致谢与参考
> 另请注意:使用此工具需禁用 Canvas 指纹防护扩展(如 Canvas Fingerprint Defender否则可能会导致处理结果错误。 https://github.com/journey-ad/gemini-watermark-remover/issues/3
## 使用方法 本项目站在巨人的肩膀上,特别感谢开源社区的杰出贡献:
### 在线使用 - **原项目**: [gemini-watermark-remover](https://github.com/journey-ad/gemini-watermark-remover) by [journey-ad](https://github.com/journey-ad)。
- *提供了项目的基础架构、Alpha Map 核心逻辑及反向混合算法的初始实现。*
1. 浏览器打开 [banana.ovo.re](https://banana.ovo.re) - **算法起源**: [Gemini Watermark Tool](https://github.com/allenk/GeminiWatermarkTool) by [Allen Kuo](https://github.com/allenk)。
2. 拖拽或点击选择带水印的 Gemini 图片 - *最早发现并公开了该数学原理及水印掩膜数据。*
3. 图片会自动开始处理,移除水印
4. 下载处理后的图片
### 油猴脚本 ## 🚀 使用指南
1. 安装油猴插件(如 Tampermonkey 或 Greasemonkey
2. 打开 [gemini-watermark-remover.user.js](https://banana.ovo.re/userscript/gemini-watermark-remover.user.js)
3. 脚本会自动安装到浏览器中
4. Gemini 对话页面点击复制或者下载图片时,会自动移除水印
## 开发
### 本地开发
1. 克隆代码仓库:
```bash
git clone http://git.unissense.tech/mula/gemini_watermark_cleaner.git
```
2. 安装依赖:
```bash ```bash
# 安装依赖
pnpm install pnpm install
```
# 开发构建 3. 启动开发模式(持续监听变化):
```bash
pnpm dev pnpm dev
```
# 生产构建 4. 启动本地预览服务:
pnpm build ```bash
# 本地预览
pnpm serve pnpm serve
``` ```
5. 构建生产版本:
## 算法原理 ```bash
pnpm build
### Gemini 添加水印的方式
Gemini 通过以下方式添加水印:
$$watermarked = \alpha \cdot logo + (1 - \alpha) \cdot original$$
其中:
- `watermarked`: 带水印的像素值
- `α`: Alpha 通道值 (0.0-1.0)
- `logo`: 水印 logo 的颜色值(白色 = 255
- `original`: 原始像素值
### 反向求解移除水印
为了去除水印,可以反向求解如下:
$$original = \frac{watermarked - \alpha \cdot logo}{1 - \alpha}$$
通过在纯色背景上捕获水印,我们可以重建 Alpha 通道,然后应用反向公式恢复原始图像
## 水印检测规则
| 图像尺寸条件 | 水印尺寸 | 右边距 | 下边距 |
|------------|---------|--------|--------|
| 宽 > 1024 **且** 高 > 1024 | 96×96 | 64px | 64px |
| 其他情况 | 48×48 | 32px | 32px |
## 项目结构
```
gemini-watermark-remover/
├── public/
│ ├── index.html # 主页面
│ └── terms.html # 使用条款页面
├── src/
│ ├── core/
│ │ ├── alphaMap.js # Alpha map 计算
│ │ ├── blendModes.js # 反向 alpha 混合算法
│ │ └── watermarkEngine.js # 主引擎
│ ├── assets/
│ │ ├── bg_48.png # 48×48 水印背景
│ │ └── bg_96.png # 96×96 水印背景
│ ├── i18n/ # 国际化语言文件
│ ├── userscript/ # 用户脚本
│ ├── app.js # 网站应用入口
│ └── i18n.js # 国际化工具
├── dist/ # 构建输出目录
├── build.js # 构建脚本
└── package.json
``` ```
## 核心模块 ### Docker 部署
1. 构建并启动容器:
### alphaMap.js ```bash
docker-compose up -d --build
从背景捕获图像计算 Alpha 通道:
```javascript
export function calculateAlphaMap(bgCaptureImageData) {
// 提取 RGB 通道最大值并归一化到 [0, 1]
const alphaMap = new Float32Array(width * height);
for (let i = 0; i < alphaMap.length; i++) {
const maxChannel = Math.max(r, g, b);
alphaMap[i] = maxChannel / 255.0;
}
return alphaMap;
}
``` ```
2. 访问 `http://localhost:3000`(或在 `.env` 中配置的端口)即可使用应用。
### blendModes.js ### 浏览器使用
构建完成后打开 `dist/index.html`,或直接访问部署好的站点。将文件拖入上传区域即可:
- **图片**:即时预览去水印结果。
- **PDF**:显示处理进度(页码),完成后预览并支持下载。
实现反向 Alpha 混合算法: ## 📄 许可证
```javascript
export function removeWatermark(imageData, alphaMap, position) {
// 对每个像素应用公式original = (watermarked - α × 255) / (1 - α)
for (let row = 0; row < height; row++) {
for (let col = 0; col < width; col++) {
const alpha = Math.min(alphaMap[idx], MAX_ALPHA);
const original = (watermarked - alpha * 255) / (1.0 - alpha);
imageData.data[idx] = Math.max(0, Math.min(255, original));
}
}
}
```
### watermarkEngine.js
主引擎类,协调整个处理流程:
```javascript
export class WatermarkEngine {
async removeWatermarkFromImage(image) {
// 1. 检测水印尺寸
const config = detectWatermarkConfig(width, height);
// 2. 获取 alpha map
const alphaMap = await this.getAlphaMap(config.logoSize);
// 3. 移除水印
removeWatermark(imageData, alphaMap, position);
return canvas;
}
}
```
## 浏览器兼容性
- ✅ Chrome 90+
- ✅ Firefox 88+
- ✅ Safari 14+
- ✅ Edge 90+
需要支持:
- ES6 Modules
- Canvas API
- Async/Await
- TypedArray (Float32Array, Uint8ClampedArray)
---
## 局限性
- 只去除了 **Gemini 可见的水印**<small>(即右下角的半透明 Logo</small>
- 无法去除隐形或隐写水印。<small>[(了解更多关于 SynthID 的信息)](https://support.google.com/gemini/answer/16722517)</small>
- 针对 Gemini 当前的水印模式设计<small>(截至 2025 年)</small>
## 免责声明
本工具仅限**个人学习研究**所用,不得用于商业用途。
根据您所在的司法管辖区及图像的实际用途,移除水印的行为可能具有潜在的法律影响。用户需自行确保其使用行为符合适用法律、相关服务条款以及知识产权规定,并对此承担全部责任。
作者不纵容也不鼓励将本工具用于侵犯版权、虚假陈述或任何其他非法用途。
**本软件按“原样”提供,不提供任何形式(无论是明示或暗示)的保证。在任何情况下,作者均不对因使用本软件而产生的任何索赔、损害或其他责任承担任何义务。**
## 致谢
本项目是 [Gemini Watermark Tool](https://github.com/allenk/GeminiWatermarkTool) 的 JavaScript 移植版本,原作者 Allen Kuo ([@allenk](https://github.com/allenk))
反向 Alpha 混合算法和用于校准的水印图像基于原作者的工作 © 2024 AllenK (Kwyshell),采用 MIT 许可证
## 相关链接
- [Gemini Watermark Tool](https://github.com/allenk/GeminiWatermarkTool)
- [算法原理说明](https://allenkuo.medium.com/removing-gemini-ai-watermarks-a-deep-dive-into-reverse-alpha-blending-bbbd83af2a3f)
## 许可证
[MIT License](./LICENSE) [MIT License](./LICENSE)

View File

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 MiB

View File

Before

Width:  |  Height:  |  Size: 8.9 MiB

After

Width:  |  Height:  |  Size: 8.9 MiB

View File

Before

Width:  |  Height:  |  Size: 586 KiB

After

Width:  |  Height:  |  Size: 586 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 MiB

View File

Before

Width:  |  Height:  |  Size: 5.8 MiB

After

Width:  |  Height:  |  Size: 5.8 MiB

View File

Before

Width:  |  Height:  |  Size: 5.9 MiB

After

Width:  |  Height:  |  Size: 5.9 MiB

View File

Before

Width:  |  Height:  |  Size: 6.3 MiB

After

Width:  |  Height:  |  Size: 6.3 MiB

View File

Before

Width:  |  Height:  |  Size: 6.2 MiB

After

Width:  |  Height:  |  Size: 6.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 MiB

14
docker-compose.yml 100644
View File

@ -0,0 +1,14 @@
version: '3.8'
services:
app:
container_name: gemini-watermark-cleaner
build:
context: .
dockerfile: Dockerfile
restart: always
ports:
# Maps Host Port (from .env) to Container Port (80)
- "${PORT:-3000}:80"
environment:
- NODE_ENV=production

View File

@ -2,10 +2,10 @@
"name": "gemini-watermark-remover", "name": "gemini-watermark-remover",
"description": "Automatically removes watermarks from Gemini AI generated images", "description": "Automatically removes watermarks from Gemini AI generated images",
"version": "1.0.0", "version": "1.0.0",
"author": "journey-ad", "author": "mula.liu",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/journey-ad/gemini-watermark-remover.git" "url": "http://git.unissense.tech/mula/gemini_watermark_cleaner"
}, },
"license": "MIT", "license": "MIT",
"type": "module", "type": "module",

View File

@ -247,7 +247,17 @@ async function processSingle(item) {
let previewUrl; let previewUrl;
if (item.isPdf) { if (item.isPdf) {
const result = await processPdf(item.file); // Show result section immediately for progress
processedSection.style.display = 'block';
processedImage.src = item.originalUrl || img.src;
processedImage.style.opacity = '0.5'; // Dim original while processing
processedInfo.innerHTML = `<span class="text-accent">${i18n.t('status.processing')}</span>`;
const result = await processPdf(item.file, (page, total) => {
processedInfo.innerHTML = `<span class="text-accent">${i18n.t('status.processing')} ${page}/${total}</span>`;
});
processedImage.style.opacity = '1';
blob = result.pdfBlob; blob = result.pdfBlob;
previewUrl = result.previewDataUrl; previewUrl = result.previewDataUrl;
} else { } else {
@ -476,9 +486,9 @@ async function processPdf(file, onProgress) {
// So I should force clone for PDF to use `NOTEBOOK_CLONE_CONFIG`? // So I should force clone for PDF to use `NOTEBOOK_CLONE_CONFIG`?
// Let's assume PDF pages are NotebookLM slides. // Let's assume PDF pages are NotebookLM slides.
await engine.removeWatermarkFromImage(canvas, { forceSimpleClone: true }); const cleanedCanvas = await engine.removeWatermarkFromImage(canvas, { forceSimpleClone: true });
const imgData = canvas.toDataURL('image/jpeg', 0.9); const imgData = cleanedCanvas.toDataURL('image/jpeg', 0.9);
// Capture first page as preview // Capture first page as preview
if (i === 1) { if (i === 1) {

View File

@ -10,6 +10,14 @@ import BG_96_PATH from '../assets/bg_96.png';
import BG_NOTEBOOK_PATH from '../assets/bg_notebook.png'; import BG_NOTEBOOK_PATH from '../assets/bg_notebook.png';
import BG_NOTEBOOK_LARGE_PATH from '../assets/bg_notebook_large.png'; import BG_NOTEBOOK_LARGE_PATH from '../assets/bg_notebook_large.png';
const GEMINI_CLONE_CONFIG = {
wRatio: 0.06, wRef: 'long',
hRatio: 0.06, hRef: 'long',
mrRatio: 0.04, mrRef: 'long',
mbRatio: 0.04, mbRef: 'long',
featherSize: 12
};
const NOTEBOOK_CLONE_CONFIG = { const NOTEBOOK_CLONE_CONFIG = {
wRatio: 0.0825, wRef: 'long', wRatio: 0.0825, wRef: 'long',
hRatio: 0.0375, hRef: 'short', hRatio: 0.0375, hRef: 'short',
@ -293,17 +301,18 @@ export class WatermarkEngine {
// Draw original image onto canvas // Draw original image onto canvas
ctx.drawImage(image, 0, 0); ctx.drawImage(image, 0, 0);
// Detect watermark configuration
const config = detectWatermarkConfig(canvas.width, canvas.height);
// Use simple clone if forced (e.g. for PDFs or explicit override) // Use simple clone if forced (e.g. for PDFs or explicit override)
if (options.forceSimpleClone) { if (options.forceSimpleClone) {
this.removeWatermarkSimpleClone(ctx, canvas.width, canvas.height, NOTEBOOK_CLONE_CONFIG); const cloneConfig = config.type === 'notebooklm' ? NOTEBOOK_CLONE_CONFIG : GEMINI_CLONE_CONFIG;
this.removeWatermarkSimpleClone(ctx, canvas.width, canvas.height, cloneConfig);
return canvas; return canvas;
} }
// Get image data // Get image data
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
// Detect watermark configuration
const config = detectWatermarkConfig(canvas.width, canvas.height);
const position = calculateWatermarkPosition(canvas.width, canvas.height, config); const position = calculateWatermarkPosition(canvas.width, canvas.height, config);
if (config.type === 'notebooklm') { if (config.type === 'notebooklm') {

View File

@ -14,7 +14,7 @@
"preview.result": "Processed Result", "preview.result": "Processed Result",
"panel.title": "Control Panel", "panel.title": "Control Panel",
"btn.download": "Download", "btn.download": "Download",
"btn.reset": "Reset / Change Image", "btn.reset": "Reset / Change File",
"progress.text": "Progress", "progress.text": "Progress",
"btn.downloadAll": "Download All", "btn.downloadAll": "Download All",
"feature.title": "Features", "feature.title": "Features",

View File

@ -14,7 +14,7 @@
"preview.result": "处理结果", "preview.result": "处理结果",
"panel.title": "操作面板", "panel.title": "操作面板",
"btn.download": "下载结果", "btn.download": "下载结果",
"btn.reset": "重置 / 更换图片", "btn.reset": "重置 / 更换文件",
"progress.text": "处理进度", "progress.text": "处理进度",
"btn.downloadAll": "全部下载", "btn.downloadAll": "全部下载",
"feature.title": "功能特点", "feature.title": "功能特点",