@@ -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