Fix translucent image colors by correcting alpha premultiplication in image decoding and GPU texture transfers - #4517
Fix translucent image colors by correcting alpha premultiplication in image decoding and GPU texture transfers#4517Keavon wants to merge 1 commit into
Conversation
… image decoding and GPU texture transfers
There was a problem hiding this comment.
2 issues found across 6 files
Confidence score: 4/5
node-graph/libraries/no-std-types/src/color/color_types.rsduplicates SRGBA8-to-premultiplied-Colorconversion logic, so future color or alpha fixes could diverge across image decoding and GPU readback; extract and reuse a shared helper.node-graph/libraries/raster-types/src/image.rschanges stored alpha semantics and could introduce a subtle color regression despite the fix; add a round-trip test usingfrom_image_datawith known alpha values.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="node-graph/libraries/no-std-types/src/color/color_types.rs">
<violation number="1" location="node-graph/libraries/no-std-types/src/color/color_types.rs:363">
P3: This change duplicates the SRGBA8-to-premultiplied-`Color` conversion already used by image-data decoding and GPU readback. Extract the conversion into a shared helper and call it from all paths so future color or alpha fixes cannot leave these implementations inconsistent.</violation>
</file>
<file name="node-graph/libraries/raster-types/src/image.rs">
<violation number="1" location="node-graph/libraries/raster-types/src/image.rs:152">
P3: This premultiplication fix changes stored alpha semantics (no longer alpha-squared) and is the kind of subtle color-space regression that can silently reappear. Add a round-trip test that runs from_image_data on a known semi-transparent RGBA pixel and asserts the stored Color has alpha == v[3]/255 with premultiplied linear RGB (e.g. white at alpha 128 → rgb ≈ 0.502, alpha ≈ 0.502), and that to_png()/to_flat_u8 recovers the original u8 values.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| // `Image<Color>` pixel convention is linear-light with associated (premultiplied) alpha. | ||
| let srgba = SRGBA8::new(bytes[0], bytes[1], bytes[2], bytes[3]); | ||
| Color::from(srgba).apply_opacity(bytes[3] as f32 / 255.) | ||
| let color = Color::from(SRGBA8::new(bytes[0], bytes[1], bytes[2], bytes[3])); |
There was a problem hiding this comment.
P3: This change duplicates the SRGBA8-to-premultiplied-Color conversion already used by image-data decoding and GPU readback. Extract the conversion into a shared helper and call it from all paths so future color or alpha fixes cannot leave these implementations inconsistent.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At node-graph/libraries/no-std-types/src/color/color_types.rs, line 363:
<comment>This change duplicates the SRGBA8-to-premultiplied-`Color` conversion already used by image-data decoding and GPU readback. Extract the conversion into a shared helper and call it from all paths so future color or alpha fixes cannot leave these implementations inconsistent.</comment>
<file context>
@@ -360,8 +360,8 @@ impl Pixel for Color {
// `Image<Color>` pixel convention is linear-light with associated (premultiplied) alpha.
- let srgba = SRGBA8::new(bytes[0], bytes[1], bytes[2], bytes[3]);
- Color::from(srgba).apply_opacity(bytes[3] as f32 / 255.)
+ let color = Color::from(SRGBA8::new(bytes[0], bytes[1], bytes[2], bytes[3]));
+ color.map_rgb(|channel| channel * color.a())
}
</file context>
| let srgba = SRGBA8::new(v[0], v[1], v[2], v[3]); | ||
| Color::from(srgba).apply_opacity(v[3] as f32 / 255.) | ||
| let color = Color::from(SRGBA8::new(v[0], v[1], v[2], v[3])); | ||
| color.map_rgb(|channel| channel * color.a()) |
There was a problem hiding this comment.
P3: This premultiplication fix changes stored alpha semantics (no longer alpha-squared) and is the kind of subtle color-space regression that can silently reappear. Add a round-trip test that runs from_image_data on a known semi-transparent RGBA pixel and asserts the stored Color has alpha == v[3]/255 with premultiplied linear RGB (e.g. white at alpha 128 → rgb ≈ 0.502, alpha ≈ 0.502), and that to_png()/to_flat_u8 recovers the original u8 values.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At node-graph/libraries/raster-types/src/image.rs, line 152:
<comment>This premultiplication fix changes stored alpha semantics (no longer alpha-squared) and is the kind of subtle color-space regression that can silently reappear. Add a round-trip test that runs from_image_data on a known semi-transparent RGBA pixel and asserts the stored Color has alpha == v[3]/255 with premultiplied linear RGB (e.g. white at alpha 128 → rgb ≈ 0.502, alpha ≈ 0.502), and that to_png()/to_flat_u8 recovers the original u8 values.</comment>
<file context>
@@ -148,8 +148,8 @@ impl Image<Color> {
- let srgba = SRGBA8::new(v[0], v[1], v[2], v[3]);
- Color::from(srgba).apply_opacity(v[3] as f32 / 255.)
+ let color = Color::from(SRGBA8::new(v[0], v[1], v[2], v[3]));
+ color.map_rgb(|channel| channel * color.a())
})
.collect();
</file context>
|
Superseded by #4518. |
Superseded by #4518.