Repository: sxyazi/yazi
File: yazi-adapter/src/image.rs (Rust)

Code before:

pub struct Image;

impl Image {
	pub async fn precache(src: PathBuf, cache: &Path) -> Result<()> {
		let (mut img, orientation, icc) = Self::decode_from(src.clone()).await?;
		let (w, h) = Self::flip_size(orientation, (YAZI.preview.max_width, YAZI.preview.max_height));

		let buf = tokio::task::spawn_blocking(move || {
			if img.width() > w || img.height() > h {
				img = img.resize(w, h, Self::filter());
			}
			if orientation != Orientation::NoTransforms {
				img.apply_orientation(orientation);
			}

			let mut buf = Vec::new();
			if img.color().has_alpha() {
				let rgba = img.into_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 {
				let mut encoder = JpegEncoder::new_with_quality(&mut buf, YAZI.preview.image_quality);

				let mut data = img.to_rgb8().into_raw();

				// If ICC profile is present and it's not srgb, perform color transformation
				if let Some(ref icc_profile) = icc
					&& let Some(input) = Profile::new_from_slice(icc_profile, false)
					&& !input.is_sRGB()
				{
					let mut output = Profile::new_sRGB();
					output.precache_output_transform();

					let xfm = Transform::new(&input, &output, qcms::DataType::RGB8, qcms::Intent::default())
						.context("Failed creating the ICC transformer")?;
					xfm.apply(&mut data);
				}
				encoder.encode(&data, img.width(), img.height(), ExtendedColorType::Rgb8)?
			}

			Ok::<_, anyhow::Error>(buf)
		})
		.await??;

		Ok(Local::regular(&cache).write(buf).await?)
	}

	pub(super) async fn downscale(path: PathBuf, rect: Rect) -> Result<DynamicImage> {
		let (mut img, orientation, _) = Self::decode_from(path).await?;

Review comment (suggestion):
```suggestion
				let mut data = img.into_rgb8().into_raw();
```

Code after:
pub struct Image;

impl Image {
	pub async fn precache(src: PathBuf, cache: &Path) -> Result<()> {
		let (mut img, orientation) = Self::decode_from(src).await?;
		let (w, h) = Self::flip_size(orientation, (YAZI.preview.max_width, YAZI.preview.max_height));

		let buf = tokio::task::spawn_blocking(move || {
			if img.width() > w || img.height() > h {
				img = img.resize(w, h, Self::filter());
			}
			if orientation != Orientation::NoTransforms {
				img.apply_orientation(orientation);
			}

			let mut buf = Vec::new();
			if img.color().has_alpha() {
				let encoder = PngEncoder::new(&mut buf);
				img.write_with_encoder(encoder)?;
			} else {
				let encoder = JpegEncoder::new_with_quality(&mut buf, YAZI.preview.image_quality);
				img.write_with_encoder(encoder)?;
			}

			Ok::<_, ImageError>(buf)
		})
		.await??;

		Ok(Local::regular(&cache).write(buf).await?)
	}

	pub(super) async fn downscale(path: PathBuf, rect: Rect) -> Result<DynamicImage> {
		let (mut img, orientation) = Self::decode_from(path).await?;
		let (w, h) = Self::flip_size(orientation, Self::max_pixel(rect));

		// Fast path.
		if img.width() <= w && img.height() <= h && orientation == Orientation::NoTransforms {
			return Ok(img);
		}

		let img = tokio::task::spawn_blocking(move || {
			if img.width() > w || img.height() > h {
				img = img.resize(w, h, Self::filter())
			}
			if orientation != Orientation::NoTransforms {
				img.apply_orientation(orientation);
			}
			img
		})
		.await?;