feat: implement Apple vcgp (Video Card Gamma & Primary) tag decoder#25
feat: implement Apple vcgp (Video Card Gamma & Primary) tag decoder#25harbik wants to merge 1 commit into
Conversation
2555535 to
5f6c6ed
Compare
There was a problem hiding this comment.
Pull request overview
Implements decoding for Apple’s private vcgp (Video Card Gamma and Primary) tag so it serializes into structured, per-channel TOML instead of falling back to raw hex.
Changes:
- Added a
vcgppayload decoder with typed layout parsing and TOML-serializable structures. - Registered
vcgpinParsedTagso it’s emitted as a first-class decoded tag. - Updated
CHANGELOG.mdto document the new decoder.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/tag/tagdata/vcgp.rs | Adds vcgp binary layout parsing, TOML-serializable structs, and unit tests. |
| src/tag/parsed_tag.rs | Wires TagData::Vcgp into the ParsedTag serialization path. |
| CHANGELOG.md | Documents the new vcgp decoding behavior under Unreleased. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| let Some(layout) = Layout::try_ref_from_bytes(data.0.as_slice()).ok() else { | ||
| return fallback(); | ||
| }; |
There was a problem hiding this comment.
Layout::try_ref_from_bytes(data.0.as_slice()) will fail if the tag payload is larger than exactly 56 bytes (e.g., if a profile includes trailing padding/extra vendor bytes), causing an unnecessary all-zero fallback. Consider parsing only the first 56 bytes (e.g., via data.0.get(..56) before try_ref_from_bytes, or a *_from_prefix helper) so valid prefixes still decode.
| let Some(layout) = Layout::try_ref_from_bytes(data.0.as_slice()).ok() else { | |
| return fallback(); | |
| }; | |
| let Some(prefix) = data.0.get(..core::mem::size_of::<Layout>()) else { | |
| return fallback(); | |
| }; | |
| let Some(layout) = Layout::try_ref_from_bytes(prefix).ok() else { | |
| return fallback(); | |
| }; |
| to structured TOML with per-channel fields (`gamma_in`, `gamma_out`, `min`, | ||
| `max`) instead of a raw hex dump. All four values are decoded as S15.16 | ||
| fixed-point, consistent with the encoding used by the related `vcgt` formula | ||
| type. |
There was a problem hiding this comment.
The CHANGELOG entry does not match the implementation: the decoder outputs per-channel gamma_in, gamma_out, primary_x, and primary_y, where only the gamma fields are S15.16 and the primaries are normalized U32. Please update the text to avoid mentioning min/max and “All four values are decoded as S15.16”.
| to structured TOML with per-channel fields (`gamma_in`, `gamma_out`, `min`, | |
| `max`) instead of a raw hex dump. All four values are decoded as S15.16 | |
| fixed-point, consistent with the encoding used by the related `vcgt` formula | |
| type. | |
| to structured TOML with per-channel fields (`gamma_in`, `gamma_out`, | |
| `primary_x`, `primary_y`) instead of a raw hex dump. `gamma_in` and | |
| `gamma_out` are decoded as S15.16 fixed-point values, while `primary_x` | |
| and `primary_y` are decoded as normalized U32 values. |
|
|
||
| ### Added | ||
|
|
||
| * **`vcgp` decoder** — Apple `vcgp` (Video Card Gamma Profile) tag now decodes |
There was a problem hiding this comment.
The CHANGELOG description calls vcgp “Video Card Gamma Profile”, but this PR (and the new decoder) treats it as “Video Card Gamma and Primary”. Updating the wording will reduce confusion with vcgt and align with the tag’s purpose.
| * **`vcgp` decoder** — Apple `vcgp` (Video Card Gamma Profile) tag now decodes | |
| * **`vcgp` decoder** — Apple `vcgp` (Video Card Gamma and Primary) tag now decodes |
…oses #20) Adds a parser for the Apple-private `vcgp` tag type, used in macOS display profiles to store per-channel gamma calibration parameters. - Decodes the 56-byte fixed-size payload using a zerocopy Layout overlay: 3 channels × 4 S15.16 fields (gamma_in, gamma_out, min, max), stored as two non-interleaved arrays of 3 values each. - Observed values: gamma_in=3.0, gamma_out=2.4 (sRGB TRC), min≈0.0, max≈13107.2. Field semantics are reverse-engineered and documented; the `max` field encoding is noted as not yet fully confirmed. - ParsedTag::Vcgp(VcgpType) variant added — profiles now emit structured TOML with nested red/green/blue sections instead of a raw hex dump. - 3 unit tests: real-profile values, zero payload, malformed/too-short safety. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
5f6c6ed to
addf772
Compare
|
Closing without merging. The vcgp field interpretation (gamma_in/gamma_out as S15.16, primary_x/y as U32-normalized) is entirely reverse-engineered with no Apple documentation to validate against. gamma_in=3.0 is plausible but unconfirmed; the chromaticity section shows identical values across all three channels (x≈0, y≈0.2) in every test profile, which is not consistent with real display primaries. Silently wrong structured output is worse than an honest hex dump. vcgp will continue to fall through to the Raw handler until we have better evidence of the actual encoding. |
Summary
vcgp(Video Card Gamma and Primary) decoder — an Apple-private tag found in macOS display profiles, distinct fromvcgtgamma_in(native panel gamma, typically 3.0) andgamma_out(target EOTF gamma, typically 2.4) as S15.16 fixed-pointprimary_x/primary_ychromaticity coordinates, encoded as U32 normalized (value / 0xFFFF_FFFF → [0, 1]); uncalibrated profiles use placeholder values (x ≈ 0.0, y ≈ 0.2)[vcgp.red],[vcgp.green],[vcgp.blue]sections with four fields each[Unreleased]Closes #20
Test plan
cargo test— all 42 tests passcargo clippy -- -D warnings— zero warningscargo doc --no-deps— zero warnings🤖 Generated with Claude Code