Align watermark content with detector coverage

This commit is contained in:
Victor Kuznetsov
2026-08-27 20:05:03 -07:00
parent 17408b958e
commit a8d4bce14a
61 changed files with 933 additions and 198 deletions
+2 -2
View File
@@ -228,8 +228,8 @@ class TestVisibleCommand:
# The transparent corners must remain transparent.
assert out[0, 0, 3] == 0
assert out[199, 199, 3] == 0
# The opaque centre remains opaque (the watermark region default is bottom-right,
# which doesn't overlap the centre square at 200x200).
# The opaque center remains opaque (the watermark region default is bottom-right,
# which doesn't overlap the center square at 200x200).
assert out[100, 100, 3] == 255
def test_visible_keeps_alpha_opaque_in_watermark_region(self, runner, tmp_path):
+38 -20
View File
@@ -17,7 +17,11 @@ from unittest.mock import patch
import pytest
from remove_ai_watermarks._internal.c2pa import c2pa_info_from_manifest_store
from remove_ai_watermarks._internal.constants import C2PA_AI_VENDORS, C2PA_CLAIM_GENERATOR_PLATFORMS
from remove_ai_watermarks._internal.constants import (
C2PA_AI_VENDORS,
C2PA_CLAIM_GENERATOR_PLATFORMS,
C2PA_IDENTITY_AI_ORGS,
)
from remove_ai_watermarks.identify import (
ProvenanceEvidence,
ProvenanceReport,
@@ -179,7 +183,7 @@ class TestProvenanceEvidence:
assert report.is_ai_generated is True
assert report.confidence == "high"
assert report.platform == "OpenAI (ChatGPT / gpt-image / DALL-E / Sora)"
assert report.platform == "OpenAI (ChatGPT / GPT Image / DALL·E / Sora)"
assert not any("not anchored" in caveat for caveat in report.caveats)
def test_external_metadata_record_builds_equivalent_evidence(self, tmp_path: Path):
@@ -244,7 +248,7 @@ class TestProvenanceEvidence:
report = identify_from_evidence(evidence_from_metadata_record(record, path=path))
assert report.is_ai_generated is True
assert report.platform == "OpenAI (ChatGPT / gpt-image / DALL-E / Sora)"
assert report.platform == "OpenAI (ChatGPT / GPT Image / DALL·E / Sora)"
assert [signal.name for signal in report.signals] == ["c2pa"]
def test_external_generator_bytes_are_normalized(self, tmp_path: Path):
@@ -374,13 +378,12 @@ class TestAttributePlatform:
assert platform
assert "Canva" in platform
def test_byteplus_attributes_to_bytedance(self):
def test_byteplus_keeps_its_product_name(self):
# ByteDance's intl brand signs as "Byteplus Pte. Ltd."; the registry maps
# it to the ByteDance platform (was mis-read as Adobe via an incidental
# it to the ByteDance family (was mis-read as Adobe via an incidental
# "Adobe XMP" file string before the entry existed).
platform = _attribute_platform(["BytePlus (ByteDance)"])
assert platform
assert "ByteDance" in platform
assert platform == "BytePlus (ByteDance)"
def test_empty_is_none(self):
assert _attribute_platform([]) is None
@@ -444,7 +447,7 @@ class TestIdentifyNonPng:
path = self._c2pa_jpeg(tmp_path, b"certificate_center@volcengine.com ... trainedAlgorithmicMedia")
r = identify(path, check_visible=False, check_invisible=False)
assert r.is_ai_generated is True
assert "ByteDance" in (r.platform or "")
assert r.platform == "ByteDance Volcano Engine"
def test_bytedance_chinese_legal_name_attributed(self, tmp_path: Path):
# Some Volcano Engine certs name the signer with the Chinese legal entity
@@ -454,7 +457,7 @@ class TestIdentifyNonPng:
path = self._c2pa_jpeg(tmp_path, blob)
r = identify(path, check_visible=False, check_invisible=False)
assert r.is_ai_generated is True
assert "ByteDance" in (r.platform or "")
assert r.platform == "ByteDance Volcano Engine"
@pytest.mark.parametrize(
("claim_generator", "platform"),
@@ -498,7 +501,7 @@ class TestIdentifyNonPng:
path = self._c2pa_jpeg(tmp_path, b"Bytedance Pte. Ltd. Dreamina/7.5.0 c2pa.created")
r = identify(path, check_visible=False, check_invisible=False)
assert r.is_ai_generated is True
assert "ByteDance" in (r.platform or "")
assert r.platform == "ByteDance Dreamina"
def test_elevenlabs_attributed(self, tmp_path: Path):
path = self._c2pa_jpeg(tmp_path, b"Eleven Labs Inc. ... trainedAlgorithmicMedia")
@@ -895,7 +898,7 @@ class TestIdentifyAigcPngChunk:
assert "doubao" in signal.detail
# ── HuggingFace-hosted job marker (medium confidence) ───────────────
# ── Hugging Face-hosted job marker (medium confidence) ─────────────
class TestIdentifyHuggingFaceJob:
@@ -917,7 +920,7 @@ class TestIdentifyHuggingFaceJob:
assert r.is_ai_generated is True
assert r.confidence == "medium"
assert r.platform is not None
assert "HuggingFace" in r.platform
assert "Hugging Face" in r.platform
signal = next(s for s in r.signals if s.name == "hf_job")
assert signal.confidence == "medium"
@@ -1221,7 +1224,7 @@ class TestSynthIDProvenanceEvidence:
png = self._png(tmp_path, "dreamina.png", self._png_chunk(b"caBX", b"jumbc2pa Dreamina/7.5.0 c2pa.created"))
r = identify(png, check_visible=False, check_invisible=False)
assert r.is_ai_generated is True
assert "ByteDance" in (r.platform or "")
assert r.platform == "ByteDance Dreamina"
class TestReportSerializable:
@@ -1452,7 +1455,7 @@ class TestIdentifyAIGC:
class TestVendorOf:
def test_openai_variants(self):
assert _vendor_of("OpenAI (ChatGPT / gpt-image / DALL-E / Sora)") == "OpenAI"
assert _vendor_of("OpenAI (ChatGPT / GPT Image / DALL·E / Sora)") == "OpenAI"
assert _vendor_of("DALL-E 3") == "OpenAI"
def test_google_variants(self):
@@ -1478,17 +1481,32 @@ class TestVendorOf:
# entered clash detection (a coverage hole). They now normalize to one origin.
assert _vendor_of("Microsoft (Copilot / Designer)") == "Microsoft"
assert _vendor_of("Copilot") == "Microsoft"
assert _vendor_of("ByteDance (Doubao / Jimeng / Dreamina / Volcano Engine)") == "ByteDance"
assert _vendor_of("ByteDance Volcano Engine") == "ByteDance"
assert _vendor_of("BytePlus (ByteDance)") == "ByteDance"
assert _vendor_of("Dreamina/1.2") == "ByteDance"
assert _vendor_of("Canva (Magic Media)") == "Canva"
assert _vendor_of("Black Forest Labs (FLUX)") == "Black Forest Labs"
assert _vendor_of("Eleven Labs Inc.") == "ElevenLabs"
assert _vendor_of("Ideogram") == "Ideogram"
def test_bytedance_issuers_share_one_platform(self):
expected = "ByteDance (Doubao / Jimeng / Dreamina / Volcano Engine)"
platforms = {vendor.platform for vendor in C2PA_AI_VENDORS if vendor.needle == "ByteDance"}
assert platforms == {expected}
assert ("dreamina", expected) in C2PA_CLAIM_GENERATOR_PLATFORMS
def test_ideogram_issuer_attributed(self):
# Corpus evidence 2026-08-08: four uploads signed "Ideogram, Inc" read as
# unknown-signer C2PA with no platform. The issuer token is the org prefix.
platforms = {v.issuer: v.platform for v in C2PA_AI_VENDORS}
assert platforms[b"Ideogram"] == "Ideogram"
assert "Ideogram" in C2PA_IDENTITY_AI_ORGS
assert _issuers_in(b"...CN=Ideogram, Inc...trainedAlgorithmicMedia") == ["Ideogram"]
def test_bytedance_issuers_keep_the_source_product(self):
platforms = {
vendor.issuer: vendor.platform
for vendor in C2PA_AI_VENDORS
if vendor.org.startswith("ByteDance") or vendor.org.startswith("BytePlus")
}
assert platforms[b"volcengine"] == "ByteDance Volcano Engine"
assert platforms[b"Byteplus"] == "BytePlus (ByteDance)"
assert platforms[b"Dreamina"] == "ByteDance Dreamina"
assert ("dreamina", "ByteDance Dreamina") in C2PA_CLAIM_GENERATOR_PLATFORMS
class TestIntegrityClashesHelper:
+1 -1
View File
@@ -245,7 +245,7 @@ class TestEngineResolvesThePolishPerProfile:
This is the change that stopped a library caller and a CLI caller on one profile
from producing different pixels, and it had no test: rebinding
``resolve_adaptive_polish`` to ``bool(value)`` -- exactly the pre-commit behaviour --
``resolve_adaptive_polish`` to ``bool(value)`` -- exactly the pre-commit behavior --
left the whole suite green.
"""
+1 -1
View File
@@ -72,7 +72,7 @@ class TestConfig:
assert KlingEngine().config.provenance_ncc_factor == 1.0
def test_gate_above_clean_arm_max(self):
# Clean arm scored p99 0.304 / max 0.320 on 286 hand-labelled frames; the
# Clean arm scored p99 0.304 / max 0.320 on 286 hand-labeled frames; the
# gate must sit above that with margin.
assert KlingEngine().config.detect_ncc_threshold > 0.32
+6 -3
View File
@@ -1562,7 +1562,7 @@ class TestAIGCLabel:
class TestHuggingFaceJob:
"""HuggingFace-hosted job marker (``hf-job-id`` PNG text chunk)."""
"""Hugging Face-hosted job marker (``hf-job-id`` PNG text chunk)."""
def _hf_png(self, tmp_path: Path, job_id: str = "ec8380a6-2091-423a-b835-209420f99ee1") -> Path:
p = tmp_path / "hfjob.png"
@@ -1622,10 +1622,13 @@ class TestSoftBinding:
from remove_ai_watermarks._internal.c2pa import soft_binding_vendors_in
assert soft_binding_vendors_in(b"...alg...com.adobe.trustmark.P...") == ["Adobe TrustMark"]
assert soft_binding_vendors_in(b"com.digimarc.validate.1") == ["Digimarc"]
assert soft_binding_vendors_in(b"com.digimarc.validate.1") == ["Digimarc Validate"]
assert soft_binding_vendors_in(b"ai.steg.api blah") == ["Steg.AI"]
# Registry-verified vendors added in v0.6.x.
assert soft_binding_vendors_in(b"ai.trufo.gen1.image") == ["Trufo"]
assert soft_binding_vendors_in(b"ai.trufo.pawprint.watermark") == ["Trufo PawPrint"]
assert soft_binding_vendors_in(b"com.aiwatermark.pixelseal.1") == ["AIWatermark PixelSeal"]
assert soft_binding_vendors_in(b"com.aiwatermark.videoseal.1") == ["AIWatermark VideoSeal"]
assert soft_binding_vendors_in(b"com.aiwatermark.audioseal.1") == ["AIWatermark AudioSeal"]
assert soft_binding_vendors_in(b"io.iscc.v0") == ["ISCC (content code)"]
def test_vendors_in_empty_when_absent(self):
+5 -5
View File
@@ -266,8 +266,8 @@ class TestC2PA:
def test_content_fingerprint_does_not_trigger_invisible_removal(self):
info = {
"soft_binding": "Adobe (content fingerprint)",
"soft_binding_vendors": ["Adobe (content fingerprint)"],
"soft_binding": "Adobe Image Comparator Network",
"soft_binding_vendors": ["Adobe Image Comparator Network"],
}
assert c2pa_info_has_removal_hint(info) is False
@@ -1007,7 +1007,7 @@ class TestTc260ContainerRouting:
def _riff_chunk(chunk_id: bytes, payload: bytes) -> bytes:
return chunk_id + len(payload).to_bytes(4, "little") + payload + (b"\x00" if len(payload) & 1 else b"")
def _labelled_avi(self) -> bytes:
def _labeled_avi(self) -> bytes:
info = self._riff_chunk(b"AIGC", _TC260_AIGC_VALUE)
body = b"AVI " + self._riff_chunk(b"LIST", b"INFO" + info)
return b"RIFF" + len(body).to_bytes(4, "little") + body
@@ -1016,7 +1016,7 @@ class TestTc260ContainerRouting:
from remove_ai_watermarks.metadata import aigc_label
target = tmp_path / "clip.bin" # correct AVI bytes, wrong suffix
target.write_bytes(self._labelled_avi())
target.write_bytes(self._labeled_avi())
label = aigc_label(target)
assert label is not None
assert label["Label"] == "1"
@@ -1025,7 +1025,7 @@ class TestTc260ContainerRouting:
from remove_ai_watermarks.metadata import aigc_label
target = tmp_path / "clip.avi"
target.write_bytes(self._labelled_avi())
target.write_bytes(self._labeled_avi())
assert aigc_label(target) is not None
def test_webp_yields_nothing_from_the_riff_reader(self, tmp_path: Path):
+163
View File
@@ -0,0 +1,163 @@
"""Tests for the measured Microsoft top-right AI-badge engine.
The covered variant is a white top-right pill with dark internal shapes. The
2026-08-27 calibration kept visually confirmed carriers, provenance-only files,
and no-signal controls separate. These tests pin the load-bearing constants --
especially the long-side scale basis and the internal holes as the discriminator.
"""
from __future__ import annotations
import cv2
import numpy as np
import pytest
from remove_ai_watermarks import watermark_registry as registry
from remove_ai_watermarks.microsoft_engine import (
_ALPHA_HEIGHT_FRAC,
_ALPHA_WIDTH_FRAC,
MicrosoftEngine,
_alpha_template,
)
_INSET = 0.010 # measured pill inset from the top/right edges (long-side fraction)
def _pill_geometry(w: int, h: int) -> tuple[int, int, int, int]:
long_side = max(w, h)
pw = int(_ALPHA_WIDTH_FRAC * long_side)
ph = max(4, int(_ALPHA_HEIGHT_FRAC * long_side))
pad = int(_INSET * long_side)
return w - pad - pw, pad, pw, ph
def _compose(w: int, h: int, bg: float = 110.0):
"""Composite the synthetic pill at its measured size onto a flat background."""
img = np.full((h, w, 3), bg, np.uint8)
at = _alpha_template()
x0, y0, pw, ph = _pill_geometry(w, h)
pill = cv2.resize(at, (pw, ph))
region = img[y0 : y0 + ph, x0 : x0 + pw]
bright = pill > 0.6
region[bright] = 245
# Internal holes are dark ink inside the pill, not background.
region[~bright] = 45
return img, (x0, y0, pw, ph)
def _plain_pill(w: int, h: int, text: str | None = None) -> np.ndarray:
"""Return a white rounded pill without the expected holes, or with foreign text."""
img = np.full((h, w, 3), 110.0, np.uint8)
x0, y0, pw, ph = _pill_geometry(w, h)
cv2.rectangle(img, (x0, y0), (x0 + pw, y0 + ph), (245, 245, 245), -1)
cv2.circle(img, (x0 + ph // 2, y0 + ph // 2), ph // 3, (110, 110, 110), -1)
if text:
cv2.putText(img, text, (x0 + ph, y0 + ph // 2 + ph // 6), cv2.FONT_HERSHEY_SIMPLEX, ph / 90.0, (45, 45, 45), 1)
return img
class TestLocate:
def test_box_anchored_top_right(self):
eng = MicrosoftEngine()
loc = eng.locate(np.zeros((1024, 1024, 3), np.uint8))
assert loc.x + loc.w == pytest.approx(1024 - int(0.004 * 1024), abs=2)
assert loc.y == pytest.approx(int(0.003 * 1024), abs=2)
def test_box_scales_with_long_side_not_width(self):
# Measured: the pill tracks the render dimension, so a 1024x1536 portrait
# carries the SAME pill size as 1536x1024. A width basis undersized the
# template by the aspect ratio and dropped every portrait carrier.
eng = MicrosoftEngine()
portrait = eng.locate(np.zeros((1536, 1024, 3), np.uint8))
landscape = eng.locate(np.zeros((1024, 1536, 3), np.uint8))
assert portrait.w == landscape.w
small = eng.locate(np.zeros((720, 480, 3), np.uint8))
assert small.w < portrait.w
class TestConfig:
def test_strict_only_no_provenance_relaxation(self):
# Provenance names Microsoft, not the presence of this visible layout.
assert MicrosoftEngine().config.provenance_ncc_factor == 1.0
def test_long_scale_basis(self):
assert MicrosoftEngine().config.scale_basis == "long"
def test_threshold_and_geometry_pins(self):
from remove_ai_watermarks.microsoft_engine import (
DETECT_NCC_THRESHOLD,
MARGIN_RIGHT_FRAC,
WM_WIDTH_FRAC,
)
assert pytest.approx(0.38) == DETECT_NCC_THRESHOLD # controls max 0.293; carriers max 0.579
assert pytest.approx(0.170) == WM_WIDTH_FRAC
assert pytest.approx(0.004) == MARGIN_RIGHT_FRAC
def test_registry_row(self):
mark = registry.get_mark("microsoft")
assert mark.location == "top-right"
assert mark.label == "Microsoft top-right AI badge"
assert mark.in_auto
assert mark.provenance_platform_tokens == ("microsoft",)
assert mark.label_regime is None # not a China-TC260 mark
class TestDetect:
@pytest.mark.parametrize(("w", "h"), [(1024, 1024), (1536, 1024), (1024, 1536), (720, 480), (1206, 1194)])
def test_composites_detected_across_sizes(self, w, h):
eng = MicrosoftEngine()
img, _box = _compose(w, h)
det = eng.detect(img)
assert det.detected, f"{w}x{h}: conf={det.confidence:.3f}"
assert det.confidence >= 0.38
def test_portrait_composite_region_covers_pill(self):
eng = MicrosoftEngine()
img, (x, y, pw, ph) = _compose(1024, 1536)
det = eng.detect(img)
assert det.detected
rx, ry, rw, _rh = det.region
assert abs((rx + rw) - (x + pw)) < 0.08 * pw
assert abs(ry - y) < 0.4 * ph
def test_clean_gradient_not_detected(self):
eng = MicrosoftEngine()
ramp = np.tile(np.linspace(0, 255, 1024, dtype=np.uint8), (1024, 1))
img = cv2.cvtColor(ramp, cv2.COLOR_GRAY2BGR)
assert not eng.detect(img).detected
def test_plain_white_pill_not_detected(self):
# The expected internal holes are the discriminator: any other bright rounded
# element in the corner must not attribute Microsoft.
eng = MicrosoftEngine()
assert not eng.detect(_plain_pill(1024, 1024)).detected
def test_foreign_text_pill_not_detected(self):
eng = MicrosoftEngine()
assert not eng.detect(_plain_pill(1024, 1024, text="Sample Text")).detected
def test_busy_content_corner_not_detected(self):
# A photo-like textured corner must stay under the gate.
eng = MicrosoftEngine()
rng = np.random.default_rng(7)
img = rng.integers(0, 255, (1024, 1024, 3), dtype=np.uint8)
img = cv2.GaussianBlur(img, (0, 0), 3)
assert not eng.detect(img).detected
class TestMask:
def test_footprint_covers_the_pill(self):
eng = MicrosoftEngine()
img, (x, y, pw, ph) = _compose(1536, 1024)
det = eng.detect(img)
assert det.detected
mask = eng.footprint_mask(img, detection=det)
assert mask.shape[:2] == img.shape[:2]
ys, xs = np.where(mask > 0)
assert xs.min() >= x - 0.15 * pw
assert xs.max() <= x + pw + 0.15 * pw
assert ys.min() >= y - 0.3 * ph
assert ys.max() <= y + ph + 0.3 * ph
# the fill must cover the pill area, not just the text glyphs
assert float(mask[y : y + ph, x : x + pw].mean()) > 0.4
+1 -1
View File
@@ -285,7 +285,7 @@ class TestResolveStrength:
assert SDXL_ZIMAGE_UNKNOWN_STRENGTH == SDXL_ZIMAGE_GEMINI_STRENGTH
assert resolve_strength(None, "openai", "sdxl-zimage") == SDXL_ZIMAGE_OPENAI_STRENGTH
assert resolve_strength(None, "google", "sdxl-zimage") == SDXL_ZIMAGE_GEMINI_STRENGTH
# An unrecognised issuer takes the stricter Gemini value, not the OpenAI one.
# An unrecognized issuer takes the stricter Gemini value, not the OpenAI one.
assert resolve_strength(None, "adobe", "sdxl-zimage") == SDXL_ZIMAGE_UNKNOWN_STRENGTH
assert resolve_strength(None, None, "sdxl-zimage") == SDXL_ZIMAGE_UNKNOWN_STRENGTH
+59
View File
@@ -0,0 +1,59 @@
"""Contracts for the registered visible-mark calibration harness."""
from __future__ import annotations
import importlib.util
import json
from pathlib import Path
import pytest
SCRIPT = Path(__file__).parents[1] / "scripts" / "registered_mark_calibrate.py"
SPEC = importlib.util.spec_from_file_location("registered_mark_calibrate", SCRIPT)
assert SPEC
assert SPEC.loader
module = importlib.util.module_from_spec(SPEC)
SPEC.loader.exec_module(module)
def test_manifest_preserves_evidence_arms(tmp_path: Path) -> None:
manifest = tmp_path / "manifest.jsonl"
manifest.write_text(
"\n".join(
[
json.dumps({"path": "carrier.png", "arm": "positive"}),
json.dumps({"path": "provider.png", "arm": "metadata"}),
json.dumps({"path": "comparison.png", "arm": "control"}),
]
),
encoding="utf-8",
)
rows = module.load_manifest(manifest)
assert [row["arm"] for row in rows] == ["positive", "metadata", "control"]
assert all(Path(row["path"]).is_absolute() for row in rows)
def test_manifest_rejects_one_file_in_multiple_arms(tmp_path: Path) -> None:
manifest = tmp_path / "manifest.jsonl"
manifest.write_text(
"\n".join(
[
json.dumps({"path": "same.png", "arm": "positive"}),
json.dumps({"path": "same.png", "arm": "control"}),
]
),
encoding="utf-8",
)
with pytest.raises(ValueError, match="duplicate image path"):
module.load_manifest(manifest)
def test_summary_never_relabels_a_control() -> None:
summary = module.summarize([0.1, 0.4], unreadable=1, fires=1)
assert summary["n"] == 2
assert summary["unreadable"] == 1
assert summary["fires"] == 1
+1 -1
View File
@@ -71,7 +71,7 @@ class TestConfig:
assert RunningHubEngine().config.provenance_ncc_factor == 1.0
def test_gate_above_clean_arm_max(self):
# Clean arm scored p99 0.273 / max 0.295 on 286 hand-labelled frames.
# Clean arm scored p99 0.273 / max 0.295 on 286 hand-labeled frames.
assert RunningHubEngine().config.detect_ncc_threshold > 0.295
def test_registry_row(self):
+1
View File
@@ -17,6 +17,7 @@ ROOT = Path(__file__).resolve().parents[1]
"visible_groundtruth.py",
"visible_recall_sample.py",
"visible_sheets.py",
"registered_mark_calibrate.py",
],
)
def test_script_help_exits_cleanly(script: str) -> None:
+2 -2
View File
@@ -1,6 +1,6 @@
"""Policy-level tests for the shared text-mark engine config.
These assert calibrated TUNING, not algorithm behaviour --
These assert calibrated TUNING, not algorithm behavior --
they exist so a future edit cannot silently revert a calibrated constant back to a
value that was measured to be wrong. The measurements themselves live in
`docs/module-internals.md` and in the comment at
@@ -74,7 +74,7 @@ class TestScaleBasis:
assert doubao_engine._CONFIG.scale_basis == "short"
def test_jimeng_scales_with_width(self):
"""Measured, not an oversight: the short-side basis took jimeng's labelled
"""Measured, not an oversight: the short-side basis took jimeng's labeled
landscape positives from 13/13 to 0/13."""
from remove_ai_watermarks import jimeng_engine
+1 -1
View File
@@ -118,7 +118,7 @@ class TestFaintMaskStaysTight:
loc = eng.locate(img)
roi = loc.w * loc.h
# The mark's own glyph box is ~40% of the corner ROI and the mask pads it, so a
# correct mask lands near 60%. The pre-fix behaviour measured 120.9% (the whole
# correct mask lands near 60%. The pre-fix behavior measured 120.9% (the whole
# ROI plus padding), which this bound excludes.
assert area < 0.85 * roi, f"mask covers {100 * area / roi:.0f}% of the corner box"
+1 -1
View File
@@ -100,7 +100,7 @@ class TestRunTiled:
def test_identity_generate_reconstructs_image(self):
# A blend of identical (unchanged) tiles must reproduce the input exactly,
# regardless of overlap -- the feather weights are a partition-of-unity once
# normalised. This is the seam-free guarantee.
# normalized. This is the seam-free guarantee.
rng = np.random.default_rng(0)
arr = rng.integers(0, 256, size=(1500, 1300, 3), dtype=np.uint8)
image = Image.fromarray(arr)
+1 -1
View File
@@ -3,7 +3,7 @@
TrustMark is an optional dependency (extra ``trustmark``) that downloads model
weights on first use, so the decode path is only exercised when it is installed
(mirrors the imwatermark handling). The always-on test pins the graceful
absent/error behaviour: detect must return None, never raise.
absent/error behavior: detect must return None, never raise.
"""
from __future__ import annotations
+7 -1
View File
@@ -860,6 +860,12 @@ class TestVideoMetadataApi:
class TestVideoProvenanceApi:
def test_c2pa_platform_keeps_the_bytedance_surface_name(self):
from remove_ai_watermarks.video import _platform_from_video_metadata
assert _platform_from_video_metadata({"issuer": "BytePlus (ByteDance)"}) == "BytePlus (ByteDance)"
assert _platform_from_video_metadata({"issuer": "ByteDance (Volcano Engine)"}) == "ByteDance Volcano Engine"
def test_identifies_metadata_without_pixel_scan(self, tmp_path: Path):
from remove_ai_watermarks.video import identify_video
@@ -870,7 +876,7 @@ class TestVideoProvenanceApi:
assert report.source == source
assert report.is_ai_generated is True
assert report.confidence == "high"
assert report.platform == "OpenAI (ChatGPT / gpt-image / DALL-E / Sora)"
assert report.platform == "OpenAI (ChatGPT / GPT Image / DALL·E / Sora)"
assert report.visible_mark is None
assert report.total_frames is None
assert report.has_ai_metadata is True
+1 -1
View File
@@ -142,7 +142,7 @@ def test_pairing_follows_the_engine_sampling_rule_not_just_the_frame_count(
in the suite that constrains the sampler's phase at all.
The clips encode losslessly, so the aligned pairing is exact and clears any
floor; the misaligned one compares frames a full colour step apart and lands
floor; the misaligned one compares frames a full color step apart and lands
near 9 dB, which is what leaves the 25 dB ceiling a wide moat rather than a
tuned threshold.
"""
+10 -5
View File
@@ -25,6 +25,7 @@ class TestCatalog:
"runninghub",
"baidu",
"liblib",
"microsoft",
"jimeng_pill",
]
@@ -113,6 +114,7 @@ class TestScan:
"runninghub",
"baidu",
"liblib",
"microsoft",
"jimeng_pill",
}
@@ -219,7 +221,7 @@ class TestProvenanceGate:
# 0.38 is inside the measured 13%-precision band and above the engine's own
# 0.35 floor, so the engine reports `detected` and only the registry gate can
# reject it. Hardcoded on purpose: if the gate is ever lowered back under this
# value, this test must fail on the BEHAVIOUR below, not on its own arithmetic.
# value, this test must fail on the behavior below, not on its own arithmetic.
self._stub(monkeypatch, 0.38)
img = np.zeros((256, 256, 3), np.uint8)
assert reg.get_mark("gemini").detect(img).detected is False
@@ -555,9 +557,12 @@ class TestMarkKnowledgeIsOnTheRow:
if mark.label_regime == "tc260" and mark.key != "jimeng_pill":
assert "aigc" in mark.provenance_signals, mark.key
def test_only_gemini_claims_platform_tokens(self):
def test_platform_token_marks_are_the_c2pa_attributed_ones(self):
# Gemini (Google C2PA) and Microsoft (issuer "Microsoft") are the marks whose
# vendor a C2PA platform string can confirm; every other mark reaches its
# provenance through TC260 codes or product signals instead.
by_token = {m.key for m in reg.known_marks() if m.provenance_platform_tokens}
assert by_token == {"gemini"}
assert by_token == {"gemini", "microsoft"}
class TestPillSuppressors:
@@ -589,7 +594,7 @@ class TestPillSuppressors:
assert not reg._keep_pill({"liblib", "jimeng"}, provenance=frozenset(), footprint_flat=1.0)
def test_pill_survives_gemini_and_samsung(self):
"""Neither is a TC260 labeller, and neither can put "jimeng" into provenance,
"""Neither is a TC260 labeler, and neither can put "jimeng" into provenance,
so neither may veto the arm it could not have enabled."""
assert reg._keep_pill({"gemini", "jimeng"}, provenance=frozenset(), footprint_flat=1.0)
assert reg._keep_pill({"samsung", "jimeng"}, provenance=frozenset(), footprint_flat=1.0)
@@ -632,4 +637,4 @@ class TestProvenanceMaskThreading:
)
monkeypatch.setattr(eng, "footprint_mask", lambda image, *, force=False, region=None, dilate=None: None)
_, removed = reg.remove_auto_marks(np.zeros((256, 256, 3), np.uint8), sensitivity="strict", backend="cv2")
assert "Google Gemini sparkle" not in removed
assert "Google Gemini visible watermark (sparkle)" not in removed