Skip to content

Commit 8dcc73c

Browse files
committed
Preserve exact RGB source samples when working profiles match
1 parent e0570be commit 8dcc73c

2 files changed

Lines changed: 36 additions & 8 deletions

File tree

‎crates/editor/src/workspace/mod.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ use std::sync::Arc;
3535
use viewport_frame::ViewportKey;
3636

3737
mod adjustments;
38-
mod smart_objects;
3938
#[cfg(not(sandboxed))]
4039
mod ai;
4140
#[cfg(sandboxed)]
@@ -46,6 +45,7 @@ mod camera_import;
4645
#[cfg(not(target_arch = "wasm32"))]
4746
pub(crate) mod camera_sync;
4847
pub(crate) mod recorded_actions;
48+
mod smart_objects;
4949
#[cfg(target_os = "android")]
5050
pub(crate) use schist_camera_sync::android as camera_sync_android;
5151
#[cfg(target_os = "ios")]

‎crates/editor/src/workspace/smart_objects.rs‎

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -85,12 +85,21 @@ fn source_pixels(
8585
.transpose()?
8686
.unwrap_or_else(schist_colormgmt::Profile::srgb)
8787
};
88-
schist_colormgmt::ColorTransform::new(
89-
&source_profile,
90-
&target_profile,
91-
schist_colormgmt::Intent::Perceptual,
92-
)?
93-
.apply(&mut floats);
88+
// Even an equal-profile CMS transform evaluates transfer curves and clips
89+
// extended-range samples. Identical working profiles require no conversion:
90+
// retain the compositor's exact floating-point source values instead.
91+
let same_profile = source_profile
92+
.icc_bytes()
93+
.zip(target_profile.icc_bytes())
94+
.is_some_and(|(source, target)| source == target);
95+
if !same_profile {
96+
schist_colormgmt::ColorTransform::new(
97+
&source_profile,
98+
&target_profile,
99+
schist_colormgmt::Intent::Perceptual,
100+
)?
101+
.apply(&mut floats);
102+
}
94103
let mut source = TileMap::new_in_mode(target.mode);
95104
let region = IntRect::from_xywh(origin[0], origin[1], doc.width, doc.height);
96105
if matches!(target.mode, ColorMode::Cmyk | ColorMode::Lab) {
@@ -836,7 +845,7 @@ mod tests {
836845
"red"
837846
}
838847
fn apply(&self, pixels: &mut [f32], _: usize, _: usize, _: &FilterValues) {
839-
for p in pixels.chunks_exact_mut(4) {
848+
for p in pixels.as_chunks_mut::<4>().0 {
840849
if p[3] > 0.0 {
841850
p[0] = 1.0;
842851
}
@@ -1187,6 +1196,25 @@ mod tests {
11871196
}
11881197
}
11891198

1199+
#[test]
1200+
fn matching_rgb_profiles_preserve_hdr_and_exact_float_samples() {
1201+
let color = Rgba::new(1.25, -0.2, 0.712345, 1.0);
1202+
for icc in [
1203+
None,
1204+
schist_colormgmt::Profile::display_p3()
1205+
.icc_bytes()
1206+
.map(<[u8]>::to_vec),
1207+
] {
1208+
let mut child = Document::new("HDR source", 1, 1, Depth::ThirtyTwo);
1209+
child.icc_profile = icc;
1210+
let mut layer = Layer::new_raster("source");
1211+
layer.as_raster_mut().unwrap().tiles = pixels(color);
1212+
child.push_layer(layer);
1213+
let restored = source_pixels(&child, &SourceColor::from(&child), [-3, -5]).unwrap();
1214+
assert_eq!(restored.pixel(-3, -5), color);
1215+
}
1216+
}
1217+
11901218
#[test]
11911219
fn legacy_edit_normalizes_negative_origin_and_keeps_unfiltered_canvas() {
11921220
let mut doc = Document::new("parent", 8, 8, Depth::ThirtyTwo);

0 commit comments

Comments
 (0)