Report a gain map claim with no payload as orphaned - #1
Merged
Merged
Conversation
A JPEG whose primary XMP declares hdrgm:Version was classified ultrahdr even when the file held no gain map. Pillow, and anything else that re-encodes the primary while carrying the XMP across, produces exactly that file, so `gmaudit diff` called those round trips clean. That is the one thing the tool exists to catch. The Ultra HDR rule now needs a payload it can point at: an MPF entry with an image really parsed behind it, or an appended image found by the SOI scan. An MPF entry whose bytes are gone does not count, and neither does an entry MPF labels a thumbnail. When nothing locates the gain map the XMP names, the file reports orphaned, which is what that state is for. Found by lab/, a real-file environment added here: fifty samples from libavif, Awesome-Gain-Maps and libultrahdr, pushed through Pillow, OpenCV and ffmpeg, plus fresh files encoded by ultrahdr_app, all cross-checked against libultrahdr's own decoder. It disagreed with us on seven of eight real exports before this change and none after. CI does not run it; it needs network access and third-party encoders. Also switches --verify-with-ultrahdr to ultrahdr_app's probe mode (-P), which reads the gain map metadata without decoding and writes nothing. Builds older than libultrahdr 1.5.0 have no -P and report it by name, so those fall back to the full decode in a scratch directory as before. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The bug
A JPEG whose primary XMP declares
hdrgm:Versionwas classifiedultrahdreven when the file held no gain map at all. Pillow, and anything else that re-encodes the primary image while carrying the XMP across, produces exactly that file. Sogmaudit diffreported those round trips as clean, which is the one thing the tool exists to catch.Before, on a real Pillow export whose gain map is gone:
offset: Nonewas the tell. Nothing had ever located a payload.The fix
The Ultra HDR rule now needs a payload it can point at: an MPF entry with an image really parsed behind it, or an appended image found by the SOI scan
walk()falls back to. Two more cases fall out of the same rule:When nothing locates it, the file reports
orphaned.gain_map.sourcenow names what located the payload (mpf,appended, or those prefixedgcontainer+); the baregcontainersource is gone, since a container directory entry on its own never located anything.Two existing tests asserted the old behaviour on single-image fixtures. Those fixtures were the bug, so they now build real two-image pairs, and the single-image shape is asserted as
orphaned.How it was found
lab/, added here, is a real-file environment CI does not run: around fifty samples from libavif, Awesome-Gain-Maps and libultrahdr, pushed through Pillow, OpenCV and ffmpeg, plus fresh files encoded byultrahdr_app, then audited and cross-checked against libultrahdr's own decoder.libultrahdr disagreed with us on seven of eight real exports before this change:
and none after.
lab/audit.pyreports 102 real files, 0 problems on this branch, and 21 problems withdetect.pyreverted, so it is not a vacuous green. It needs network access and third-party encoders, which is why it stays out oftests/and out of the sdist.Also here
--verify-with-ultrahdrnow usesultrahdr_app's probe mode (-P), which reads the gain map metadata without decoding and writes nothing. The old path dumped a 786 KBoutrgb.rawper file into a scratch directory. Builds older than libultrahdr 1.5.0 have no-Pand report it by name, so those fall back to the full decode as before, still in the scratch directory.Testing
127 tests,
ruff checkclean,twine checkpassed. The four new detection tests each fail withdetect.pyreverted. The real-bytes regression test cuts the gain map off a genuine corpus file rather than committing a derived image, sotests/corpus/stays purely upstream output.🤖 Generated with Claude Code