mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
feat(01-01): replace image resize with linear-light fast_image_resize pipeline
This commit is contained in:
parent
ef5dac0a47
commit
189b785cc9
1 changed files with 84 additions and 13 deletions
|
|
@ -1,7 +1,9 @@
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use image::{DynamicImage, ImageDecoder, ImageError, ImageReader, Limits, codecs::{jpeg::JpegEncoder, png::PngEncoder}, imageops::FilterType, metadata::Orientation};
|
use fast_image_resize::images::Image as FirImage;
|
||||||
|
use fast_image_resize::{IntoImageView, ResizeAlg, ResizeOptions, Resizer, create_srgb_mapper};
|
||||||
|
use image::{DynamicImage, ImageDecoder, ImageError, ImageReader, Limits, codecs::{jpeg::JpegEncoder, png::PngEncoder}, metadata::Orientation};
|
||||||
use ratatui::layout::Rect;
|
use ratatui::layout::Rect;
|
||||||
use yazi_config::YAZI;
|
use yazi_config::YAZI;
|
||||||
use yazi_emulator::Dimension;
|
use yazi_emulator::Dimension;
|
||||||
|
|
@ -18,7 +20,7 @@ impl Image {
|
||||||
|
|
||||||
let buf = tokio::task::spawn_blocking(move || {
|
let buf = tokio::task::spawn_blocking(move || {
|
||||||
if img.width() > w || img.height() > h {
|
if img.width() > w || img.height() > h {
|
||||||
img = img.resize(w, h, Self::filter());
|
img = Self::fir_resize(img, w, h, Self::resize_alg())?;
|
||||||
}
|
}
|
||||||
if orientation != Orientation::NoTransforms {
|
if orientation != Orientation::NoTransforms {
|
||||||
img.apply_orientation(orientation);
|
img.apply_orientation(orientation);
|
||||||
|
|
@ -33,7 +35,7 @@ impl Image {
|
||||||
img.write_with_encoder(encoder)?;
|
img.write_with_encoder(encoder)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok::<_, ImageError>(buf)
|
Ok::<_, anyhow::Error>(buf)
|
||||||
})
|
})
|
||||||
.await??;
|
.await??;
|
||||||
|
|
||||||
|
|
@ -51,14 +53,14 @@ impl Image {
|
||||||
|
|
||||||
let img = tokio::task::spawn_blocking(move || {
|
let img = tokio::task::spawn_blocking(move || {
|
||||||
if img.width() > w || img.height() > h {
|
if img.width() > w || img.height() > h {
|
||||||
img = img.resize(w, h, Self::filter())
|
img = Self::fir_resize(img, w, h, Self::resize_alg())?;
|
||||||
}
|
}
|
||||||
if orientation != Orientation::NoTransforms {
|
if orientation != Orientation::NoTransforms {
|
||||||
img.apply_orientation(orientation);
|
img.apply_orientation(orientation);
|
||||||
}
|
}
|
||||||
img
|
Ok::<_, anyhow::Error>(img)
|
||||||
})
|
})
|
||||||
.await?;
|
.await??;
|
||||||
|
|
||||||
Ok(img)
|
Ok(img)
|
||||||
}
|
}
|
||||||
|
|
@ -83,14 +85,83 @@ impl Image {
|
||||||
.unwrap_or(rect)
|
.unwrap_or(rect)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn filter() -> FilterType {
|
fn resize_alg() -> ResizeAlg {
|
||||||
|
use fast_image_resize::FilterType;
|
||||||
match YAZI.preview.image_filter.as_str() {
|
match YAZI.preview.image_filter.as_str() {
|
||||||
"nearest" => FilterType::Nearest,
|
"nearest" => ResizeAlg::Nearest,
|
||||||
"triangle" => FilterType::Triangle,
|
"triangle" => ResizeAlg::Convolution(FilterType::Bilinear),
|
||||||
"catmull-rom" => FilterType::CatmullRom,
|
"catmull-rom" => ResizeAlg::Convolution(FilterType::CatmullRom),
|
||||||
"gaussian" => FilterType::Gaussian,
|
"gaussian" => ResizeAlg::Convolution(FilterType::Gaussian),
|
||||||
"lanczos3" => FilterType::Lanczos3,
|
"lanczos3" => ResizeAlg::Convolution(FilterType::Lanczos3),
|
||||||
_ => FilterType::Triangle,
|
other => {
|
||||||
|
tracing::warn!("unknown image_filter {other:?}, falling back to lanczos3");
|
||||||
|
ResizeAlg::Convolution(FilterType::Lanczos3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fir_resize(img: DynamicImage, w: u32, h: u32, alg: ResizeAlg) -> anyhow::Result<DynamicImage> {
|
||||||
|
let img = match img.pixel_type() {
|
||||||
|
Some(_) => img,
|
||||||
|
None => {
|
||||||
|
tracing::debug!("converting exotic pixel type to rgb8 for resize");
|
||||||
|
img.to_rgb8().into()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let pixel_type = img
|
||||||
|
.pixel_type()
|
||||||
|
.ok_or_else(|| anyhow::anyhow!("unsupported pixel type for fast_image_resize"))?;
|
||||||
|
|
||||||
|
if matches!(alg, ResizeAlg::Nearest) {
|
||||||
|
let mut dst = FirImage::new(w, h, pixel_type);
|
||||||
|
let mut resizer = Resizer::new();
|
||||||
|
resizer.resize(&img, &mut dst, &ResizeOptions::new().resize_alg(alg))?;
|
||||||
|
return Self::reconstruct(w, h, pixel_type, dst.into_vec());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mapper = create_srgb_mapper();
|
||||||
|
|
||||||
|
// sRGB -> linear
|
||||||
|
let mut linear_src = FirImage::new(img.width(), img.height(), pixel_type);
|
||||||
|
mapper.forward_map(&img, &mut linear_src)?;
|
||||||
|
|
||||||
|
// Resize in linear light
|
||||||
|
let mut dst = FirImage::new(w, h, pixel_type);
|
||||||
|
let mut resizer = Resizer::new();
|
||||||
|
let opts = ResizeOptions::new().resize_alg(alg);
|
||||||
|
resizer.resize(&linear_src, &mut dst, &opts)?;
|
||||||
|
|
||||||
|
// linear -> sRGB
|
||||||
|
let mut srgb_dst = FirImage::new(w, h, pixel_type);
|
||||||
|
mapper.backward_map(&dst, &mut srgb_dst)?;
|
||||||
|
|
||||||
|
Self::reconstruct(w, h, pixel_type, srgb_dst.into_vec())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reconstruct(
|
||||||
|
w: u32,
|
||||||
|
h: u32,
|
||||||
|
pixel_type: fast_image_resize::PixelType,
|
||||||
|
buf: Vec<u8>,
|
||||||
|
) -> anyhow::Result<DynamicImage> {
|
||||||
|
use anyhow::Context;
|
||||||
|
use fast_image_resize::PixelType;
|
||||||
|
use image::{GrayAlphaImage, GrayImage, RgbImage, RgbaImage};
|
||||||
|
match pixel_type {
|
||||||
|
PixelType::U8 => {
|
||||||
|
Ok(GrayImage::from_raw(w, h, buf).context("gray reconstruct")?.into())
|
||||||
|
}
|
||||||
|
PixelType::U8x2 => {
|
||||||
|
Ok(GrayAlphaImage::from_raw(w, h, buf).context("graya reconstruct")?.into())
|
||||||
|
}
|
||||||
|
PixelType::U8x3 => {
|
||||||
|
Ok(RgbImage::from_raw(w, h, buf).context("rgb reconstruct")?.into())
|
||||||
|
}
|
||||||
|
PixelType::U8x4 => {
|
||||||
|
Ok(RgbaImage::from_raw(w, h, buf).context("rgba reconstruct")?.into())
|
||||||
|
}
|
||||||
|
_ => Err(anyhow::anyhow!("unexpected pixel type {pixel_type:?}")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue