<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Victor K</title>
    <description>The latest articles on DEV Community by Victor K (@wiltodelta).</description>
    <link>https://dev.to/wiltodelta</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3978231%2Ffb284993-f4c4-4013-91ae-f3fd39de31ee.jpg</url>
      <title>DEV Community: Victor K</title>
      <link>https://dev.to/wiltodelta</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/wiltodelta"/>
    <language>en</language>
    <item>
      <title>How to detect and remove AI image watermarks (SynthID, C2PA, Gemini) in Python</title>
      <dc:creator>Victor K</dc:creator>
      <pubDate>Wed, 10 Jun 2026 18:50:56 +0000</pubDate>
      <link>https://dev.to/wiltodelta/how-to-detect-and-remove-ai-image-watermarks-synthid-c2pa-gemini-in-python-7f3</link>
      <guid>https://dev.to/wiltodelta/how-to-detect-and-remove-ai-image-watermarks-synthid-c2pa-gemini-in-python-7f3</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftt7ez93tv3jxvbmhlift.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftt7ez93tv3jxvbmhlift.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Modern AI image tools mark their output in three different ways, and most people only know about one of them. I built an open-source tool to handle all three, and this post is about how each mark actually works and, honestly, how removable each one is.&lt;/p&gt;

&lt;p&gt;The three layers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Visible marks.&lt;/strong&gt; The Gemini / Nano Banana sparkle in the corner, the ByteDance Doubao and Jimeng text strips, the Samsung Galaxy AI wordmark. These are pixel overlays.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Invisible pixel watermarks.&lt;/strong&gt; Google SynthID is the big one. It perturbs pixels in a way you cannot see but a decoder can read.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Provenance metadata.&lt;/strong&gt; C2PA Content Credentials, EXIF / XMP generator tags, the IPTC "Made with AI" field, China's TC260 AIGC label. This is data attached to the file, not the pixels.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;They have very different removability, and that is the interesting part.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read the provenance first
&lt;/h2&gt;

&lt;p&gt;Before removing anything, it helps to know what is actually in an image. The tool has an &lt;code&gt;identify&lt;/code&gt; command that aggregates every locally-readable signal into one verdict:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;remove-ai-watermarks identify image.png
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It reads:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The C2PA manifest issuer, mapped to a platform (OpenAI, Google, Adobe Firefly, Microsoft, Black Forest Labs, and so on).&lt;/li&gt;
&lt;li&gt;The C2PA soft-binding algorithm, which names the forensic-watermark vendor (Adobe TrustMark, Digimarc, and others).&lt;/li&gt;
&lt;li&gt;EXIF / XMP generator tags. Ideogram, for instance, writes &lt;code&gt;Make = "Ideogram AI"&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The IPTC "Made with AI" disclosure fields.&lt;/li&gt;
&lt;li&gt;xAI / Grok's own EXIF signature scheme.&lt;/li&gt;
&lt;li&gt;The visible mark, via a shape-matched detector.&lt;/li&gt;
&lt;li&gt;A SynthID proxy, inferred from the C2PA manifest of vendors known to pair the two.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It also flags integrity clashes: if two independent stamps disagree about who generated an image (say a C2PA OpenAI manifest plus an EXIF &lt;code&gt;Make&lt;/code&gt; of "Ideogram AI"), that contradiction is a laundering tell. The detection side turned out to be the more interesting half to build, and it is the part with almost no competition.&lt;/p&gt;

&lt;h2&gt;
  
  
  Removing visible marks: reverse alpha, not inpainting
&lt;/h2&gt;

&lt;p&gt;The obvious way to remove a corner logo is to inpaint over it. That hallucinates pixels and leaves a smudge. The better way, when the mark is a fixed overlay, is reverse alpha blending.&lt;/p&gt;

&lt;p&gt;A visible watermark is an alpha composite:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;watermarked = alpha * logo + (1 - alpha) * original
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you capture the logo's alpha map once, by stamping it on a known background, you can invert the equation and recover the original pixels:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;original = (watermarked - alpha * logo) / (1 - alpha)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the Gemini sparkle on a bright background this is near-exact. No inpainting, no hallucination. The text marks re-rasterize slightly per image, so they get a thin residual inpaint on top, but the bulk is recovered, not invented.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;remove-ai-watermarks visible image.png &lt;span class="nt"&gt;-o&lt;/span&gt; clean.png            &lt;span class="c"&gt;# auto-detect&lt;/span&gt;
remove-ai-watermarks visible image.png &lt;span class="nt"&gt;--mark&lt;/span&gt; gemini &lt;span class="nt"&gt;-o&lt;/span&gt; clean.png
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It runs on CPU, no model download.&lt;/p&gt;

&lt;h2&gt;
  
  
  Removing metadata
&lt;/h2&gt;

&lt;p&gt;This one is simple and lossless. The metadata lives in the file's containers, not in the pixels, so stripping it never touches the image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;remove-ai-watermarks metadata image.png &lt;span class="nt"&gt;--check&lt;/span&gt;               &lt;span class="c"&gt;# inspect&lt;/span&gt;
remove-ai-watermarks metadata image.png &lt;span class="nt"&gt;--remove&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; clean.png
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It handles C2PA, EXIF, IPTC, and PNG text chunks across PNG, JPEG, WebP, AVIF, HEIF, and even MP4 (which is just ISOBMFF, like AVIF).&lt;/p&gt;

&lt;h2&gt;
  
  
  The hard one: SynthID
&lt;/h2&gt;

&lt;p&gt;Here is the honest part. There is no public SynthID decoder. Google DeepMind's own paper states the verifier is restricted to trusted testers, and they do not release detector weights. A local pixel detector is infeasible by design, not just unbuilt. So the tool detects SynthID only by its C2PA companion, which is reliable while the manifest is intact and silent once you strip it.&lt;/p&gt;

&lt;p&gt;Removal is a different problem. Since you cannot read the watermark, you cannot surgically remove it. The approach is a light regeneration: a low-strength SDXL img2img pass that perturbs the pixels enough to break the watermark, with a canny ControlNet conditioning the regeneration on the original edge map so text and faces keep their structure.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;remove-ai-watermarks invisible image.png &lt;span class="nt"&gt;-o&lt;/span&gt; clean.png
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The caveats, because they matter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It is lossy.&lt;/strong&gt; A regeneration softens fine detail. The visible-mark and metadata paths above are lossless; this one is not.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It is content-dependent and not guaranteed.&lt;/strong&gt; How much you need to regenerate depends on the image, and there is no local oracle to self-verify. You confirm with the Gemini app's "Verify with SynthID" feature, and raise the strength if it still detects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It does not defeat AI-vs-real classifiers.&lt;/strong&gt; Tools like Hive Moderation are trained statistical detectors, a different thing from a watermark. A light diffusion pass will not reliably fool them, and that is out of scope on purpose.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It is an arms race.&lt;/strong&gt; A vendor can change the scheme whenever they want.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I would rather state these plainly than ship a tool that overclaims.&lt;/p&gt;

&lt;h2&gt;
  
  
  On whether any of this should exist
&lt;/h2&gt;

&lt;p&gt;Watermarking is a weak trust signal to begin with. A marker that is almost always present yet trivially removable can make a cleaned forgery look more trustworthy, not less. Durable provenance is more likely to come from signing genuine content than from watermarking synthetic content. Half of what this tool ships is &lt;code&gt;identify&lt;/code&gt;, which reads provenance rather than removing it, and the legal limits on removing an AI label are spelled out in the README.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;remove-ai-watermarks
&lt;span class="c"&gt;# or&lt;/span&gt;
brew &lt;span class="nb"&gt;install &lt;/span&gt;wiltodelta/tap/remove-ai-watermarks
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is also a ComfyUI node pack if you live in that world. It is Apache 2.0 and open source:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/wiltodelta/remove-ai-watermarks" rel="noopener noreferrer"&gt;https://github.com/wiltodelta/remove-ai-watermarks&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you find a case where a visible mark leaves a trace, the repo is the place to tell me.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>opensource</category>
      <category>machinelearning</category>
    </item>
  </channel>
</rss>
