From 24a77d8a5f07f15d3b7d4651c9acf1e372ea5aef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=89=E5=92=B2=E9=9B=85=20=C2=B7=20Misaki=20Masa?= Date: Sat, 19 Oct 2024 21:07:41 +0800 Subject: [PATCH] feat: add ICC profile to images for better color accuracy (#1808) --- yazi-adapter/src/image.rs | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/yazi-adapter/src/image.rs b/yazi-adapter/src/image.rs index 967dda3b..a2ba06e4 100644 --- a/yazi-adapter/src/image.rs +++ b/yazi-adapter/src/image.rs @@ -11,7 +11,7 @@ pub struct Image; impl Image { pub async fn precache(path: &Path, cache: PathBuf) -> Result<()> { - let (mut img, orientation) = Self::decode_from(path).await?; + let (mut img, orientation, icc) = Self::decode_from(path).await?; let (w, h) = Self::flip_size(orientation, (PREVIEW.max_width, PREVIEW.max_height)); let buf = tokio::task::spawn_blocking(move || { @@ -25,15 +25,13 @@ impl Image { let mut buf = Vec::new(); if img.color().has_alpha() { let rgba = img.into_rgba8(); - PngEncoder::new(&mut buf).write_image( - &rgba, - rgba.width(), - rgba.height(), - ExtendedColorType::Rgba8, - )?; + let mut encoder = PngEncoder::new(&mut buf); + icc.map(|b| encoder.set_icc_profile(b)); + encoder.write_image(&rgba, rgba.width(), rgba.height(), ExtendedColorType::Rgba8)?; } else { - JpegEncoder::new_with_quality(&mut buf, PREVIEW.image_quality) - .encode_image(&img.into_rgb8())?; + let mut encoder = JpegEncoder::new_with_quality(&mut buf, PREVIEW.image_quality); + icc.map(|b| encoder.set_icc_profile(b)); + encoder.encode_image(&img.into_rgb8())?; } Ok::<_, ImageError>(buf) @@ -44,7 +42,7 @@ impl Image { } pub(super) async fn downscale(path: &Path, rect: Rect) -> Result { - let (mut img, orientation) = Self::decode_from(path).await?; + let (mut img, orientation, _) = Self::decode_from(path).await?; let (w, h) = Self::flip_size(orientation, Self::max_pixel(rect)); // Fast path. @@ -98,7 +96,7 @@ impl Image { } } - async fn decode_from(path: &Path) -> ImageResult<(DynamicImage, Orientation)> { + async fn decode_from(path: &Path) -> ImageResult<(DynamicImage, Orientation, Option>)> { let mut limits = Limits::no_limits(); if TASKS.image_alloc > 0 { limits.max_alloc = Some(TASKS.image_alloc as u64); @@ -117,8 +115,9 @@ impl Image { let mut decoder = reader.with_guessed_format()?.into_decoder()?; let orientation = decoder.orientation().unwrap_or(Orientation::NoTransforms); + let icc = decoder.icc_profile().unwrap_or_default(); - Ok((DynamicImage::from_decoder(decoder)?, orientation)) + Ok((DynamicImage::from_decoder(decoder)?, orientation, icc)) }) .await .map_err(|e| ImageError::IoError(e.into()))?