11use std:: path:: { Path , PathBuf } ;
22
3- use anyhow:: Result ;
4- use image:: { DynamicImage , ExtendedColorType , ImageDecoder , ImageEncoder , ImageError , ImageReader , ImageResult , Limits , codecs:: { jpeg:: JpegEncoder , png:: PngEncoder } , imageops:: FilterType , metadata:: Orientation } ;
3+ use anyhow:: { Context , Result } ;
4+ use image:: {
5+ DynamicImage , ImageBuffer , ImageDecoder , ImageError , ImageReader , Limits , RgbImage , RgbaImage ,
6+ codecs:: { jpeg:: JpegEncoder , png:: PngEncoder } ,
7+ imageops:: FilterType ,
8+ metadata:: { Cicp , Orientation } ,
9+ } ;
10+ use qcms:: { Profile , Transform } ;
511use ratatui:: layout:: Rect ;
612use yazi_config:: YAZI ;
713use yazi_fs:: provider:: { Provider , local:: Local } ;
@@ -12,7 +18,7 @@ pub struct Image;
1218
1319impl Image {
1420 pub async fn precache ( src : PathBuf , cache : & Path ) -> Result < ( ) > {
15- let ( mut img, orientation, icc ) = Self :: decode_from ( src) . await ?;
21+ let ( mut img, orientation) = Self :: decode_from ( src) . await ?;
1622 let ( w, h) = Self :: flip_size ( orientation, ( YAZI . preview . max_width , YAZI . preview . max_height ) ) ;
1723
1824 let buf = tokio:: task:: spawn_blocking ( move || {
@@ -25,14 +31,11 @@ impl Image {
2531
2632 let mut buf = Vec :: new ( ) ;
2733 if img. color ( ) . has_alpha ( ) {
28- let rgba = img. into_rgba8 ( ) ;
29- let mut encoder = PngEncoder :: new ( & mut buf) ;
30- icc. map ( |b| encoder. set_icc_profile ( b) ) ;
31- encoder. write_image ( & rgba, rgba. width ( ) , rgba. height ( ) , ExtendedColorType :: Rgba8 ) ?;
34+ let encoder = PngEncoder :: new ( & mut buf) ;
35+ img. write_with_encoder ( encoder) ?
3236 } else {
33- let mut encoder = JpegEncoder :: new_with_quality ( & mut buf, YAZI . preview . image_quality ) ;
34- icc. map ( |b| encoder. set_icc_profile ( b) ) ;
35- encoder. encode_image ( & img. into_rgb8 ( ) ) ?;
37+ let encoder = JpegEncoder :: new_with_quality ( & mut buf, YAZI . preview . image_quality ) ;
38+ img. write_with_encoder ( encoder) ?
3639 }
3740
3841 Ok :: < _ , ImageError > ( buf)
@@ -43,7 +46,7 @@ impl Image {
4346 }
4447
4548 pub ( super ) async fn downscale ( path : PathBuf , rect : Rect ) -> Result < DynamicImage > {
46- let ( mut img, orientation, _ ) = Self :: decode_from ( path) . await ?;
49+ let ( mut img, orientation) = Self :: decode_from ( path) . await ?;
4750 let ( w, h) = Self :: flip_size ( orientation, Self :: max_pixel ( rect) ) ;
4851
4952 // Fast path.
@@ -77,9 +80,9 @@ impl Image {
7780 pub ( super ) fn pixel_area ( size : ( u32 , u32 ) , rect : Rect ) -> Rect {
7881 Dimension :: cell_size ( )
7982 . map ( |( cw, ch) | Rect {
80- x : rect. x ,
81- y : rect. y ,
82- width : ( size. 0 as f64 / cw) . ceil ( ) as u16 ,
83+ x : rect. x ,
84+ y : rect. y ,
85+ width : ( size. 0 as f64 / cw) . ceil ( ) as u16 ,
8386 height : ( size. 1 as f64 / ch) . ceil ( ) as u16 ,
8487 } )
8588 . unwrap_or ( rect)
@@ -96,7 +99,52 @@ impl Image {
9699 }
97100 }
98101
99- async fn decode_from ( path : PathBuf ) -> ImageResult < ( DynamicImage , Orientation , Option < Vec < u8 > > ) > {
102+ fn _decode ( mut decoder : impl ImageDecoder ) -> Result < DynamicImage > {
103+ let data_type = match decoder. color_type ( ) {
104+ image:: ColorType :: L8 => Some ( qcms:: DataType :: Gray8 ) ,
105+ image:: ColorType :: La8 => Some ( qcms:: DataType :: GrayA8 ) ,
106+ image:: ColorType :: Rgb8 => Some ( qcms:: DataType :: RGB8 ) ,
107+ image:: ColorType :: Rgba8 => Some ( qcms:: DataType :: RGBA8 ) ,
108+ _ => None ,
109+ } ;
110+ let icc = decoder. icc_profile ( ) . unwrap_or_default ( ) ;
111+
112+ if let Some ( dt) = data_type
113+ && let Some ( icc_profile) = icc
114+ && let Some ( input) = Profile :: new_from_slice ( & icc_profile, false )
115+ && !input. is_sRGB ( )
116+ {
117+ let mut data = vec ! [ 0u8 ; decoder. total_bytes( ) as usize ] ;
118+ let ( w, h) = decoder. dimensions ( ) ;
119+ let has_alpha = decoder. color_type ( ) . has_alpha ( ) ;
120+ let mut output = Profile :: new_sRGB ( ) ;
121+ output. precache_output_transform ( ) ;
122+ decoder. read_image ( & mut data) ?;
123+
124+ let xfm = Transform :: new ( & input, & output, dt, qcms:: Intent :: default ( ) )
125+ . context ( "Couldn't make a profile transformer" ) ?;
126+
127+ xfm. apply ( & mut data) ;
128+
129+ let mut image = if has_alpha {
130+ let buf =
131+ RgbaImage :: from_raw ( w, h, data) . context ( "Couldn't read the transformed image data" ) ?;
132+ DynamicImage :: ImageRgba8 ( buf)
133+ } else {
134+ let buf =
135+ RgbImage :: from_raw ( w, h, data) . context ( "Couldn't read the transformed image data" ) ?;
136+ DynamicImage :: ImageRgb8 ( buf)
137+ } ;
138+
139+ image. set_rgb_primaries ( Cicp :: SRGB . primaries ) ;
140+ image. set_transfer_function ( Cicp :: SRGB . transfer ) ;
141+ Ok ( image)
142+ } else {
143+ Ok ( DynamicImage :: from_decoder ( decoder) ?)
144+ }
145+ }
146+
147+ async fn decode_from ( path : PathBuf ) -> Result < ( DynamicImage , Orientation ) > {
100148 let mut limits = Limits :: no_limits ( ) ;
101149 if YAZI . tasks . image_alloc > 0 {
102150 limits. max_alloc = Some ( YAZI . tasks . image_alloc as u64 ) ;
@@ -114,9 +162,7 @@ impl Image {
114162
115163 let mut decoder = reader. with_guessed_format ( ) ?. into_decoder ( ) ?;
116164 let orientation = decoder. orientation ( ) . unwrap_or ( Orientation :: NoTransforms ) ;
117- let icc = decoder. icc_profile ( ) . unwrap_or_default ( ) ;
118-
119- Ok ( ( DynamicImage :: from_decoder ( decoder) ?, orientation, icc) )
165+ Ok ( ( Self :: _decode ( decoder) ?, orientation) )
120166 } )
121167 . await
122168 . map_err ( |e| ImageError :: IoError ( e. into ( ) ) ) ?
0 commit comments