Remove the Gemini β sparkle watermark from images you generated with Google Gemini or Nano Banana β entirely on your own machine. No uploads, no sign-up, no server. Works as a browser tool, a TypeScript library, and a CLI.
Look at the stars inside the sparkle's outline. They are back, not painted over β see how it works.
What this does β and doesn't.This removes thevisiblecorner sparkle only. It doesnottouch[SynthID]or any other invisible provenance watermark, and it never will. Google itself already ships watermark-free images to AI Ultra subscribers; this gives you the same clean canvas for contentyou generated yourself.
Try it: geminiwatermarkwiper.com β same engine, running in your browser tab.
The mark is composited as a plain alpha blend:
observed = Ξ± Β· overlay + (1 β Ξ±) Β· original
That equation is invertible. If you know the overlay β its exact colour and its exact alpha, per pixel β the original comes back:
original = (observed β Ξ± Β· overlay) / (1 β Ξ±)
So the whole problem reduces to knowing the overlay, and it can be solved for exactly. Ask Gemini for a flat white image and a flat black one. Both come back carrying the same mark, over backgrounds you already know, which is two equations per pixel for two unknowns:
Ξ± = 1 β (obs_white β obs_black) / (bg_white β bg_black)
overlay = (obs_black β (1 β Ξ±) Β· bg_black) / Ξ±
The recovered mark peaks at 31% opacity and is nowhere near opaque, so the original pixels were never destroyed β they were only dimmed. Reversing the blend restores them outright. Nothing is inpainted, nothing is guessed at, and the stars that were under the sparkle come back exactly as they were.
The template lives in src/template-sparkle.ts;
regenerates it if Google ever changes the mark.
scripts/extract-template.mjs
Google composites the mark at a fixed 48px, inset a fixed 96px from the right and bottom β the same absolute pixels in a 1024Γ1024 image and a 1408Γ768 one, not scaled to the frame.
Confirming the mark is there is the harder half, and most of the obvious approaches quietly fail. Matching on colour finds teal lakes. Correlating the template's shape against brightness is buried by gravel and fooled by any smooth gradient. And one unmarked photo has a grey rock sitting exactly where the sparkle would be, matching an overlay's brightness to within 5%, which defeats every test based on amplitude.
What works is to remove the overlay and ask whether it explained the pixels β specifically, what happens to the gradient energy along the mark's own silhouette, the ring where the template's alpha changes fastest and a composited edge would live:
The outline must vanish. Subtracting a sparkle from something that isn't one manufactures edges instead of erasing them.What's left must look like the rest of the photo, judged against control patches beside it. The rock fails here: it isn't star-shaped, so cutting a star out of it leaves its edges standing.
Both gates are in src/detect.ts, with the measurements that set them.
100% localβ images never leave your machine** Exact reconstruction**, not inpainting: the pixels under the mark are recovered, not approximated** Says no when it means no**β an image with no sparkle is returned untouched rather than scrubbed- Batch CLI for folders of images β PNG, JPG, WebP
- Zero runtime dependencies in the core;
sharp
only for the CLI
import { removeWatermark } from 'gemini-watermark-remover';
// imageData: ImageData from a canvas, or { width, height, data }
const result = removeWatermark(imageData);
if (result.mode === 'none') {
// No sparkle found. The image is returned unchanged.
} else {
ctx.putImageData(
new ImageData(result.image.data, result.image.width, result.image.height),
0,
0,
);
}
npx gemini-watermark-remover input.png # writes input-clean.png
gwr *.png --suffix -nowm # batch
gwr shot.jpg -o clean.jpg --region 900,980,120,120 # override detection
Nano Banana is the community name for Gemini's image model β its images carry the same sparkle, so everything here applies unchanged.
On the roadmap: the same template applied per-frame via WebCodecs. Watch the repo.
- Images carrying the
large "Gemini" wordmark(a different, much bigger overlay) are not supported yet. They are detected as unsupported and left alone rather than half-erased. Extracting that template needs a flat white/black pair from the export path that produces it. - The mark is assumed to be at Google's standard placement. A cropped or resized
image may need
--region
.
Use this on content you generated yourself. Invisible provenance (SynthID) is deliberately left intact β this project is about a clean visual canvas, not about defeating AI-content detection.
MIT