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

Code before:
		let mut img = tokio::task::spawn_blocking(move || {
			Self::set_limits(image::io::Reader::open(path)?.with_guessed_format()?).decode()
		})
		.await??;

		let (mut w, mut h) = (PREVIEW.max_width, PREVIEW.max_height);
		if (5..=8).contains(&orientation) {
			(w, h) = (h, w);
		}

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

			img = Self::rotate(img, orientation);
			if !matches!(img, DynamicImage::ImageRgb8(_) | DynamicImage::ImageRgba8(_)) {
				img = DynamicImage::ImageRgb8(img.into_rgb8());
			}

			let mut buf = Vec::new();
			JpegEncoder::new_with_quality(&mut buf, PREVIEW.image_quality).encode(
				img.as_bytes(),
				img.width(),
				img.height(),
				img.color(),
			)?;
			Ok::<_, anyhow::Error>(buf)
		})
		.await??;

		Ok(tokio::fs::write(cache, buf).await?)
	}

	pub(super) async fn downscale(path: &Path, rect: Rect) -> Result<DynamicImage> {
		let orientation = Self::orientation(path).await?;

		let path = path.to_owned();
		let mut img = tokio::task::spawn_blocking(move || {
			Self::set_limits(image::io::Reader::open(path)?.with_guessed_format()?).decode()
		})
		.await??;

		let (mut w, mut h) = Self::max_pixel(rect);
		if (5..=8).contains(&orientation) {
			(w, h) = (h, w);
		}

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

Review comment (bug):
This is intentional because the `image` crate v0.25 changed the type, and Yazi downgraded quickly after an upgrade since `image` v0.25.1 [contains a bug](https://github.com/etemesi254/zune-image/issues/184) that causes the program to crash. 

However, once they fix it, we won't need to change this part when we upgrade again.

Code after:
		let mut img = tokio::task::spawn_blocking(move || {
			Self::set_limits(image::io::Reader::open(path)?.with_guessed_format()?).decode()
		})
		.await??;

		let (mut w, mut h) = (PREVIEW.max_width, PREVIEW.max_height);
		if (5..=8).contains(&orientation) {
			(w, h) = (h, w);
		}

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

			img = Self::rotate(img, orientation);
			if !matches!(img, DynamicImage::ImageRgb8(_) | DynamicImage::ImageRgba8(_)) {
				img = DynamicImage::ImageRgb8(img.into_rgb8());
			}

			let mut buf = Vec::new();
			JpegEncoder::new_with_quality(&mut buf, PREVIEW.image_quality).encode(
				img.as_bytes(),
				img.width(),
				img.height(),
				img.color().into(),
			)?;
			Ok::<_, anyhow::Error>(buf)
		})
		.await??;

		Ok(tokio::fs::write(cache, buf).await?)
	}

	pub(super) async fn downscale(path: &Path, rect: Rect) -> Result<DynamicImage> {
		let orientation = Self::orientation(path).await?;

		let path = path.to_owned();
		let mut img = tokio::task::spawn_blocking(move || {
			Self::set_limits(image::io::Reader::open(path)?.with_guessed_format()?).decode()
		})
		.await??;

		let (mut w, mut h) = Self::max_pixel(rect);
		if (5..=8).contains(&orientation) {
			(w, h) = (h, w);
		}

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