mirror of
https://github.com/guillaumemeyer/watermarks-remover.git
synced 2026-08-22 13:11:57 +02:00
Add stdlib-only detection, inspection, and cleaning for four more formats. - BMP: locate the pixel payload via the DIB header and strip trailing non-image metadata (the only place non-standard BMP metadata can live), rewriting the file-size field. - GIF: drop comment and XMP application extensions while preserving NETSCAPE2.0 looping, ICC, graphic-control, and image blocks. - TIFF (classic + BigTIFF): walk IFD chains and drop XMP/EXIF/GPS/IPTC/ Photoshop/MakerNote tags, zeroing orphaned payloads while keeping strip/tile offsets valid. - EPUB: scrub OPF package metadata and XHTML meta/JSON-LD, clean embedded raster/SVG media, apply Layer A to XHTML body text, and pass OCF-encrypted parts through untouched. All four route through format_dispatch, so the unified CLIs, the HTTP service, and the audits pick them up automatically.
5.2 KiB
5.2 KiB
Removal matrix
| Target | Method | Script / action | Side effects | Verifiable today? |
|---|---|---|---|---|
| Invisible Unicode / exotic spaces / bidi / tags | Strip / normalize | inspect_text.py, clean_text.py, clean_file.py |
Minimal | Yes (codepoint report) |
| Stylometric AI cadence / burstiness / n-grams (zero-LLM) | Statistical variance & cadence scoring | score_stylometry.py, inspect_text.py --stylometry, audit_dir.py --check-stylometry |
None (detection only) | Yes (calibrated score + phrase spans) |
| Statistical text watermark (SynthID-class / Kirchenbauer) | Multi-pass paraphrase / humanize / back-translate / structural | Agent Layer B + optional rewrite_text.py |
Meaning/style drift | No without vendor key/detector; MarkLLM harness (detect_text_watermark.py) verifies a specific scheme config before/after |
| C2PA on PNG/JPEG/WebP/AVIF/HEIC | Drop APP11 / PNG caBX / RIFF C2PA / ISOBMFF jumb & uuid / exiftool |
clean_image.py |
Loses provenance metadata | Yes |
| GIF comment/XMP extensions | Drop 0xFE / XMP application extensions (keep NETSCAPE2.0) |
clean_image.py |
Loses GIF comments/XMP | Yes (re-inspect) |
| TIFF XMP/EXIF/GPS/IPTC/MakerNote (classic + BigTIFF) | Drop IFD tags, zero payloads, keep strip offsets | clean_image.py |
Loses TIFF metadata | Yes (re-inspect) |
| BMP trailing metadata | Truncate non-image trailing bytes, fix file-size field | clean_image.py |
Removes appended metadata | Yes (re-inspect) |
| EPUB OPF metadata / XHTML meta / embedded media | Scrub OPF, strip XHTML meta/JSON-LD, clean embedded media, Layer A (skip encrypted parts) | clean_file.py |
Loses book metadata; rewrites archive | Yes (re-inspect) |
| SVG metadata / XMP / embedded data URIs | Drop <metadata>, xmpmeta; clean embedded data URIs |
clean_file.py |
Loses SVG metadata; cleans embedded rasters | Yes (re-inspect) |
| PDF XMP / info | exiftool -all= preferred |
clean_file.py |
Loses PDF metadata; degraded without exiftool | Partial |
| DOCX / XLSX / PPTX props / customXml / embedded media | Rewrite OOXML zip, scrub text runs, clean media/ | clean_file.py |
Loses doc properties; cleans embedded rasters | Yes |
| ODT meta:generator | Scrub meta.xml |
clean_file.py |
Loses generator tag | Yes |
| HTML generator / JSON-LD / embedded data URIs | Strip tags; clean embedded data URIs | clean_file.py |
Loses meta; cleans embedded rasters | Yes |
| Markdown AI frontmatter keys / embedded data URIs | Drop keys; clean embedded data URIs | clean_file.py |
Loses YAML keys; cleans embedded rasters | Yes |
| Pixel image watermark (SynthID-media / StegaStamp / Tree-Ring / StableSignature) | CtrlRegen regeneration (external backend) | clean_ctrlregen.py / clean_image.py --remove-pixel ctrlregen |
Regenerates pixels; heavy compute; detail drift at higher strength | No without official detector; reverse-SynthID score is a local surrogate; MarkDiffusion same-scheme harness (markdiffusion_harness.py detect) verifies a Tree-Ring-class scheme config before/after |
| Pixel image watermark (Tree-Ring-class) | DiffusionPurification regeneration (external MarkDiffusion backend) | clean_image.py --remove-pixel diffusion |
Blind regeneration; more drift than CtrlRegen; heavy compute | Same-scheme only via the MarkDiffusion harness (not a vendor-detector oracle) |
| Audio / video watermarks (SynthID-media) | — | Out of scope | — | — |
| C2PA soft binding (in-content link to manifest) | — | Out of scope (survives our metadata strip) | — | Vendor detector only |
| Data-driven model backdoors | — | Out of scope | — | — |
Default pipeline
- Inspect (
inspect_file.pyor specific inspect_*). - Deterministic clean — Layer A text and/or container/image metadata; for images, optionally add pixel removal (
--remove-pixel ctrlregen) after the metadata strip. - Always offer Layer B rewrite for prose (paraphrase → optional strong pass:
humanize/ back-translate / structural). - Prefer a non-origin, open-weight rewrite model when available (avoid re-stamping).
- Layer A again after rewrite.
- Report: Layer B is best-effort; residual risk remains.
- Optional verification:
rewrite_text.py --markllm-scheme kgw|synthidruns a MarkLLM before/after detection (externaldetect_text_watermark.pyharness) to show a specific scheme config clears. Same-config-only; not a vendor-detector oracle.
Code vs prose
- Prose / Markdown / HTML body: full A + B.
- Code: Layer A + formatter; statistical marks are weak; offer
coderewrite (comments/docstrings/string-literal wording + local identifier renames) with user OK.
Layer B strengths
| Strength | When |
|---|---|
paraphrase |
Default; explicit word-choice + syntax churn |
humanize |
Zero-shot "write like a human" token reshuffle |
backtranslate |
Stronger token reshuffle via pivot language |
structural |
Strongest; most drift (outline → human prose) |
code |
Comments/docstrings/string-literal wording + local identifier renames |
Frontier production watermarks are currently token-by-token (streaming constraint); paragraph-level robust methods (SemStamp / PostMark) are not yet deployed, so paraphrase-class attacks remain effective today.