mirror of
https://github.com/wiltodelta/remove-ai-watermarks.git
synced 2026-07-26 01:11:11 +02:00
docs: correct overstated FLUX open-watermark claim; record detector content-fragility
Earlier notes asserted BFL hosted output has no open DWT-DCT watermark. That was overstated: the test carriers were high-texture fox images where a clean encode->decode round-trip of a KNOWN-embedded watermark recovers only 28-35/48 bits (below the safe 44 gate), so the detector would miss a present mark there -- the None is inconclusive, not proof of absence. Verified positive-control (2026-06-19): imwatermark dwtDct round-trips 48/48 on synthetic carriers and on chatgpt-1.png (48/48) / firefly-1.png (45/48), but FAILS on flux-1.png (28/48) and doubao-1.png (39/48). So invisible_watermark detection is a positive-only signal: trust a hit, treat a miss on busy content as inconclusive. Affects all open SD/SDXL/FLUX DWT-DCT detection. C2PA stays the reliable FLUX identifier; whether BFL hosted embeds the open mark is unresolved (needs a low-texture hosted sample). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -5,7 +5,9 @@
|
||||
> no content was changed or summarized.
|
||||
|
||||
Who embeds what, and whether it is locally detectable (so we know which gaps are fillable). See `identify.py` for what we read.
|
||||
- **Locally detectable (open decoder, no key/API):** Stable Diffusion / SDXL / FLUX via `imwatermark` DWT-DCT (now covered by `invisible_watermark.py`). FLUX uses the same library (`black-forest-labs/flux2` `src/flux2/watermark.py`, 48-bit `0b001010101111111010000111100111001111010100101110`); SDXL is the diffusers `WATERMARK_MESSAGE` (`0b101100111110110010010000011110111011000110011110`). Caveat: fragile to re-encoding. **The FLUX open DWT-DCT is OPTIONAL dev-inference-code only and is NOT applied by Black Forest Labs' hosted surface** — verified 2026-06-19 on real BFL Playground outputs from BOTH FLUX.2 [pro] and FLUX.1 [dev] (lossless PNG + JPG each): all carry the signed C2PA manifest (issuer "Black Forest Labs") but the DWT-DCT decode lands at chance level (FLUX.2 [pro] PNG decodes to the degenerate all-ones; FLUX.1 [dev] lossless PNG to 17/48 ones; matches to the FLUX reference 19-28/48, threshold 44), so the open pixel watermark is absent on hosted output regardless of model line or container. Practical consequence: a hosted FLUX.2 image is identified by C2PA only; once C2PA is stripped there is NO open-pixel fallback for it (the 48-bit pattern in `_BITS_48` is correct and would fire only on a locally-generated FLUX.2 with the watermark flag explicitly enabled).
|
||||
- **Locally detectable (open decoder, no key/API):** Stable Diffusion / SDXL / FLUX via `imwatermark` DWT-DCT (now covered by `invisible_watermark.py`). FLUX uses the same library (`black-forest-labs/flux2` `src/flux2/watermark.py`, 48-bit `0b001010101111111010000111100111001111010100101110`); SDXL is the diffusers `WATERMARK_MESSAGE` (`0b101100111110110010010000011110111011000110011110`). **Caveat: the `imwatermark` dwtDct decode is content-fragile, NOT just re-encode-fragile.** A clean encode->decode round-trip (no re-encode at all) recovers 48/48 bits on synthetic carriers (random / flat / gradient) AND on some real images (chatgpt-1.png 48/48, firefly-1.png 45/48), but FAILS on high-texture/high-frequency content — the FLUX fox sample recovers only 28/48 and doubao-1.png 39/48, both below the safe `_MATCH_48` = 44 gate (random baseline ~24). So a `None` from `detect_invisible_watermark` on a textured image is **inconclusive** — the decoder would miss even a present watermark. The 44 gate is a deliberate precision choice (lowering it to catch textured carriers would admit false positives); the blind spot is the imwatermark method on high-frequency content.
|
||||
|
||||
Consequence for the FLUX hosted-output question (BFL Playground, FLUX.2 [pro] + FLUX.1 [dev], 2026-06-19): both carry the signed C2PA manifest (issuer "Black Forest Labs"); the open DWT-DCT decode returned `None`, BUT the test carriers were the high-texture fox images where even a *known-embedded* watermark only round-trips 28-35/48 — so **whether BFL hosted output embeds the open pixel watermark is UNRESOLVED** (an earlier note here wrongly asserted it absent; that was overstated — the carrier defeats the detector). What IS established: C2PA is the reliable FLUX identifier; the open DWT-DCT is OPTIONAL in the FLUX dev inference code and the `_BITS_48` pattern is correct (round-trips on low/medium-texture carriers). To resolve the hosted question, test a LOW-texture hosted FLUX image (where the round-trip is first validated to recover >=44/48).
|
||||
- **C2PA / IPTC (covered by the issuer/marker scan):** OpenAI, Google, Adobe Firefly, Microsoft (Designer + **Bing Image Creator** — collected 2026-05-24; Bing now runs Microsoft's own **MAI-Image** model, signs C2PA as "Microsoft", NOT OpenAI/DALL-E), **Stability AI** (collected from Brand Studio / DreamStudio successor; signs C2PA as "Stability AI Ltd", no SynthID, no imwatermark on its current Stable Image model — issuer added to `C2PA_ISSUERS`), and **Canva** (Magic Media signs C2PA as "Canva" + `trainedAlgorithmicMedia` with a generic `c2pa-rs` claim generator, no SynthID — issuer `b"Canva"` → "Canva (Magic Media)"; found on real production traffic 2026-06-19, which **disproved the earlier assumption** that Canva downloads are re-encoded exports that always strip C2PA). Still unsampled: Getty, Shutterstock. Midjourney embeds NO C2PA and no invisible watermark (our `mj-*` sample carried only the IPTC tag).
|
||||
|
||||
**Samsung Galaxy AI** (Generative Edit / Sketch to Image / Portrait Studio on Galaxy S23 FE / S24 / S25, One UI 7+) signs C2PA as "Samsung Galaxy" with the standard `trainedAlgorithmicMedia` source type AND a proprietary `genAIType` marker; verified on real signed files 2026-05-29 (the standard scan catches the source type; `genAIType` additionally catches a Galaxy S24 file that omits it). It ALSO burns a **visible** localized wordmark into the pixels — a sparkle + "generated with AI" string in the bottom-LEFT corner (issue #37; the Italian "✦ Contenuti generati dall'AI" variant is calibrated) — removed by `samsung_engine.py` / `visible --mark samsung` (reverse-alpha, see the engine bullet); detection feeds `identify` as the medium `visible_samsung` signal. The string is locale-specific, so each locale needs its own captured alpha template.
|
||||
|
||||
Reference in New Issue
Block a user