
Gemini Watermark Remover
Strip the visible Gemini bottom-right logo from exported images using reverse alpha blending before publishing or repurposing AI-generated artwork.
Overview
Gemini Watermark Remover is an agent skill for the Build phase that removes Gemini’s visible bottom-right watermark via reverse alpha blending on matching image layouts.
Install
npx skills add https://github.com/rookie-ricardo/erduo-skills --skill gemini-watermark-removerWhat is this skill?
- Reverse alpha blend: original = (watermarked − α·logo) / (1 − α) with white logo (255)
- Alpha maps built from captured watermark templates, max-RGB normalized to [0, 1]
- Size rules: >1024×1024 → 96×96 logo, 64px margins; else 48×48, 32px margins
- Only removes visible corner Gemini watermark—not steganographic or other patterns
- Python + PIL implementation with packaged alpha map assets beside the script
- Two layout profiles: 96×96 logo with 64px margins above 1024×1024, else 48×48 with 32px margins
Adoption & trust: 1.7k installs on skills.sh; 884 GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
You have Gemini-generated images with the standard corner logo and need publishable originals without sending files to opaque third-party removers.
Who is it for?
Solo builders batch-cleaning Gemini exports that follow the documented 48/96px corner watermark layout.
Skip if: Images with different watermark placements, aggressive compression artifacts, or requirements to remove invisible or forensic watermarks.
When should I use this skill?
You need to remove the visible Gemini corner watermark from images that match the documented pattern using reverse alpha compositing.
What do I get? / Deliverables
You get a reproducible PIL-based restore path and dimension rules so agents can output cleaned images that match the current Gemini visible watermark pattern.
- Restored image files with corner watermark mathematically inverted
- Agent-runnable removal script adapted from the documented algorithm
Recommended Skills
Journey fit
How it compares
A narrow deterministic restore recipe—not a general generative inpainting or broad metadata-stripping tool.
Common Questions / FAQ
Who is gemini-watermark-remover for?
Indie developers and content builders who use Gemini image output and want a local, algorithmic corner-logo removal step in their agent workflow.
When should I use gemini-watermark-remover?
During Build integrations when post-processing AI images before launch assets, or when automating cleanup in a content pipeline that already matches Gemini’s size-based watermark rules.
Is gemini-watermark-remover safe to install?
Review the Security Audits panel on this Prism page and inspect the Python script before it reads or writes images on your filesystem.
SKILL.md
READMESKILL.md - Gemini Watermark Remover
# Gemini watermark removal algorithm ## Reverse alpha blending Gemini visible watermark uses alpha compositing: watermarked = α * logo + (1 - α) * original Solve for original: original = (watermarked - α * logo) / (1 - α) Logo value is white (255). Alpha values come from pre-captured watermark maps. ## Alpha map construction Compute alpha per pixel by taking the max RGB channel of the captured watermark image and normalizing to [0, 1]. ## Detection rules If image width > 1024 AND height > 1024: - logo size: 96x96 - margin right: 64px - margin bottom: 64px Otherwise: - logo size: 48x48 - margin right: 32px - margin bottom: 32px ## Limits - Only removes the visible Gemini watermark in the bottom-right corner. - Does not remove invisible/steganographic watermarks. - Works on images that match the current watermark pattern. #!/usr/bin/env python3 import os import sys from typing import List, Tuple from PIL import Image ALPHA_THRESHOLD = 0.002 MAX_ALPHA = 0.99 LOGO_VALUE = 255 def detect_watermark_config(width: int, height: int) -> Tuple[int, int, int]: if width > 1024 and height > 1024: return 96, 64, 64 return 48, 32, 32 def calculate_position(width: int, height: int, logo_size: int, margin_right: int, margin_bottom: int) -> Tuple[int, int]: return width - margin_right - logo_size, height - margin_bottom - logo_size def load_alpha_map(logo_size: int) -> List[float]: script_dir = os.path.dirname(os.path.abspath(__file__)) asset_name = "bg_48.png" if logo_size == 48 else "bg_96.png" asset_path = os.path.abspath(os.path.join(script_dir, "..", "assets", asset_name)) with Image.open(asset_path) as img: img = img.convert("RGB") if img.width != logo_size or img.height != logo_size: raise ValueError(f"Unexpected asset size for {asset_name}: {img.width}x{img.height}") pixels = list(img.getdata()) alpha_map: List[float] = [0.0] * (logo_size * logo_size) for i, (r, g, b) in enumerate(pixels): max_channel = r if r >= g and r >= b else (g if g >= b else b) alpha_map[i] = max_channel / 255.0 return alpha_map def remove_watermark(input_path: str, output_path: str) -> None: with Image.open(input_path) as img: img = img.convert("RGBA") width, height = img.size logo_size, margin_right, margin_bottom = detect_watermark_config(width, height) start_x, start_y = calculate_position(width, height, logo_size, margin_right, margin_bottom) alpha_map = load_alpha_map(logo_size) pixels = img.load() for row in range(logo_size): y = start_y + row if y < 0 or y >= height: continue alpha_row_offset = row * logo_size for col in range(logo_size): x = start_x + col if x < 0 or x >= width: continue alpha = alpha_map[alpha_row_offset + col] if alpha < ALPHA_THRESHOLD: continue if alpha > MAX_ALPHA: alpha = MAX_ALPHA one_minus_alpha = 1.0 - alpha r, g, b, a = pixels[x, y] r_out = int(round((r - alpha * LOGO_VALUE) / one_minus_alpha)) g_out = int(round((g - alpha * LOGO_VALUE) / one_minus_alpha)) b_out = int(round((b - alpha * LOGO_VALUE) / one_minus_alpha)) r_out = 0 if r_out < 0 else (255 if r_out > 255 else r_out) g_out = 0 if g_out < 0 else (255 if g_out > 255 else g_out) b_out = 0 if b_out < 0 else (255 if b_out > 255 else b_out) pixels[x, y] = (r_out, g_out, b_out, a) output_ext = os.path.splitext(output_path)[1].lower() if output_ext in {".jpg", ".jpeg"}: img = img.convert("RGB") img.save(output_path) def usage() -> str: script_name = os.path.basename(sys.argv[0]) return f"Usage: pytho