mirror of
https://github.com/wiltodelta/remove-ai-watermarks.git
synced 2026-05-26 22:22:24 +02:00
fix(metadata): guard get_ai_metadata PIL open against non-OSError
get_ai_metadata opened the file with PIL unguarded, so a HEIC (or any format PIL can't open without optional plugins) raised UnidentifiedImageError instead of falling through to the binary scan -- unlike has_ai_metadata, which already guards. Wrap the open in except Exception and continue to the C2PA/IPTC path. Regression test feeds an unopenable .heic shell and asserts no raise. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -198,15 +198,21 @@ def get_ai_metadata(image_path: Path) -> dict[str, str]:
|
||||
|
||||
result: dict[str, str] = {}
|
||||
|
||||
with Image.open(image_path) as img:
|
||||
for key, value in img.info.items():
|
||||
if _is_ai_key(key):
|
||||
if isinstance(value, bytes):
|
||||
result[key] = f"<binary {len(value)} bytes>"
|
||||
elif isinstance(value, str) and len(value) > 200:
|
||||
result[key] = value[:200] + "…"
|
||||
else:
|
||||
result[key] = str(value)
|
||||
# PIL may not open AVIF/HEIF/JPEG-XL without optional plugins (and
|
||||
# ultralytics' Image.open patch can raise ModuleNotFoundError); fall through
|
||||
# to the C2PA/binary path on any open failure. See CLAUDE.md.
|
||||
try:
|
||||
with Image.open(image_path) as img:
|
||||
for key, value in img.info.items():
|
||||
if _is_ai_key(key):
|
||||
if isinstance(value, bytes):
|
||||
result[key] = f"<binary {len(value)} bytes>"
|
||||
elif isinstance(value, str) and len(value) > 200:
|
||||
result[key] = value[:200] + "…"
|
||||
else:
|
||||
result[key] = str(value)
|
||||
except Exception as exc:
|
||||
logger.debug("PIL could not open %s for AI-metadata scan: %s", image_path, exc)
|
||||
|
||||
# C2PA manifest fields from the single canonical parser (noai/c2pa.py).
|
||||
c2pa = extract_c2pa_info(image_path)
|
||||
|
||||
@@ -159,6 +159,13 @@ class TestGetAiMetadata:
|
||||
assert meta["parameters"].endswith("…")
|
||||
assert len(meta["parameters"]) <= 205
|
||||
|
||||
def test_unopenable_file_does_not_raise(self, tmp_path: Path):
|
||||
# PIL can't open HEIC without pillow-heif; get_ai_metadata must fall
|
||||
# through to the binary scan, not propagate UnidentifiedImageError.
|
||||
path = tmp_path / "iphone.heic"
|
||||
path.write_bytes(b"\x00\x00\x00\x18ftypheic" + b"\x00" * 64)
|
||||
assert get_ai_metadata(path) == {}
|
||||
|
||||
|
||||
@pytest.mark.skipif(not SAMPLES_DIR.exists(), reason="data/samples not present")
|
||||
class TestGetAiMetadataRealSample:
|
||||
|
||||
Reference in New Issue
Block a user