refactor(adapter): extract image_area from image_show

Exposing `image_area` separately allows future Lua integration to handle
image placement more flexibly, without needing to invoke full rendering.
This change promotes modularity and simplifies obtaining image dimensions alone.

This refactor provides the foundation for feature PR #1897, preparing for easier integration.
This commit is contained in:
gaesa 2024-11-11 01:07:05 +00:00
parent fd8871d878
commit 6a4fee4db1
No known key found for this signature in database
8 changed files with 67 additions and 30 deletions

View file

@ -5,7 +5,7 @@ use ratatui::layout::Rect;
use tracing::warn; use tracing::warn;
use yazi_shared::env_exists; use yazi_shared::env_exists;
use super::{Iip, Kgp, KgpOld}; use super::{Iip, Image, Kgp, KgpOld};
use crate::{Chafa, Emulator, SHOWN, Sixel, TMUX, Ueberzug, WSL}; use crate::{Chafa, Emulator, SHOWN, Sixel, TMUX, Ueberzug, WSL};
#[derive(Clone, Copy, PartialEq, Eq, Debug)] #[derive(Clone, Copy, PartialEq, Eq, Debug)]
@ -36,6 +36,20 @@ impl Display for Adapter {
} }
impl Adapter { impl Adapter {
pub async fn image_area(self, path: &Path, max: Rect) -> Result<Rect> {
if max.is_empty() {
return Ok(Rect::default());
}
match self {
Self::Kgp | Self::KgpOld | Self::Iip | Self::Sixel => {
Image::image_area(path, max).await.map(|(_img, area)| area)
}
Self::X11 | Self::Wayland => Ueberzug::image_area(path, max).await,
Self::Chafa => Chafa::image_area(path, max).await,
}
}
pub async fn image_show(self, path: &Path, max: Rect) -> Result<Rect> { pub async fn image_show(self, path: &Path, max: Rect) -> Result<Rect> {
if max.is_empty() { if max.is_empty() {
return Ok(Rect::default()); return Ok(Rect::default());

View file

@ -11,7 +11,11 @@ use crate::{Adapter, Emulator};
pub(super) struct Chafa; pub(super) struct Chafa;
impl Chafa { impl Chafa {
pub(super) async fn image_show(path: &Path, max: Rect) -> Result<Rect> { async fn symbol_bytes_with<F: Fn((Vec<&[u8]>, Rect)) -> Result<Rect>>(
path: &Path,
max: Rect,
cb: F,
) -> Result<Rect> {
let output = Command::new("chafa") let output = Command::new("chafa")
.args([ .args([
"-f", "-f",
@ -52,7 +56,15 @@ impl Chafa {
width: first.width() as u16, width: first.width() as u16,
height: lines.len() as u16, height: lines.len() as u16,
}; };
cb((lines, area))
}
pub(super) async fn image_area(path: &Path, max: Rect) -> Result<Rect> {
Self::symbol_bytes_with(path, max, |(_, area)| Ok(area)).await
}
pub(super) async fn image_show(path: &Path, max: Rect) -> Result<Rect> {
Self::symbol_bytes_with(path, max, |(lines, area)| {
Adapter::Chafa.image_hide()?; Adapter::Chafa.image_hide()?;
Adapter::shown_store(area); Adapter::shown_store(area);
Emulator::move_lock((max.x, max.y), |stderr| { Emulator::move_lock((max.x, max.y), |stderr| {
@ -62,6 +74,8 @@ impl Chafa {
} }
Ok(area) Ok(area)
}) })
})
.await
} }
pub(super) fn image_erase(area: Rect) -> Result<()> { pub(super) fn image_erase(area: Rect) -> Result<()> {

View file

@ -14,8 +14,7 @@ pub(super) struct Iip;
impl Iip { impl Iip {
pub(super) async fn image_show(path: &Path, max: Rect) -> Result<Rect> { pub(super) async fn image_show(path: &Path, max: Rect) -> Result<Rect> {
let img = Image::downscale(path, max).await?; let (img, area) = Image::image_area(path, max).await?;
let area = Image::pixel_area((img.width(), img.height()), max);
let b = Self::encode(img).await?; let b = Self::encode(img).await?;
Adapter::Iip.image_hide()?; Adapter::Iip.image_hide()?;

View file

@ -84,6 +84,13 @@ impl Image {
.unwrap_or(rect) .unwrap_or(rect)
} }
#[inline]
pub(super) async fn image_area(path: &Path, max: Rect) -> Result<(DynamicImage, Rect)> {
let img = Self::downscale(path, max).await?;
let area = Self::pixel_area((img.width(), img.height()), max);
Ok((img, area))
}
#[inline] #[inline]
fn filter() -> FilterType { fn filter() -> FilterType {
match PREVIEW.image_filter.as_str() { match PREVIEW.image_filter.as_str() {

View file

@ -314,8 +314,7 @@ pub(super) struct Kgp;
impl Kgp { impl Kgp {
pub(super) async fn image_show(path: &Path, max: Rect) -> Result<Rect> { pub(super) async fn image_show(path: &Path, max: Rect) -> Result<Rect> {
let img = Image::downscale(path, max).await?; let (img, area) = Image::image_area(path, max).await?;
let area = Image::pixel_area((img.width(), img.height()), max);
let b1 = Self::encode(img).await?; let b1 = Self::encode(img).await?;
let b2 = Self::place(&area)?; let b2 = Self::place(&area)?;

View file

@ -13,8 +13,7 @@ pub(super) struct KgpOld;
impl KgpOld { impl KgpOld {
pub(super) async fn image_show(path: &Path, max: Rect) -> Result<Rect> { pub(super) async fn image_show(path: &Path, max: Rect) -> Result<Rect> {
let img = Image::downscale(path, max).await?; let (img, area) = Image::image_area(path, max).await?;
let area = Image::pixel_area((img.width(), img.height()), max);
let b = Self::encode(img).await?; let b = Self::encode(img).await?;
Adapter::KgpOld.image_hide()?; Adapter::KgpOld.image_hide()?;

View file

@ -13,8 +13,7 @@ pub(super) struct Sixel;
impl Sixel { impl Sixel {
pub(super) async fn image_show(path: &Path, max: Rect) -> Result<Rect> { pub(super) async fn image_show(path: &Path, max: Rect) -> Result<Rect> {
let img = Image::downscale(path, max).await?; let (img, area) = Image::image_area(path, max).await?;
let area = Image::pixel_area((img.width(), img.height()), max);
let b = Self::encode(img).await?; let b = Self::encode(img).await?;
Adapter::Sixel.image_hide()?; Adapter::Sixel.image_hide()?;

View file

@ -41,23 +41,29 @@ impl Ueberzug {
DEMON.init(Some(tx)) DEMON.init(Some(tx))
} }
pub(super) async fn image_show(path: &Path, max: Rect) -> Result<Rect> { pub(super) async fn image_area(path: &Path, max: Rect) -> Result<Rect> {
let Some(tx) = &*DEMON else {
bail!("uninitialized ueberzugpp");
};
let p = path.to_owned(); let p = path.to_owned();
let ImageSize { width: w, height: h } = let ImageSize { width: w, height: h } =
tokio::task::spawn_blocking(move || imagesize::size(p)).await??; tokio::task::spawn_blocking(move || imagesize::size(p)).await??;
let area = Dimension::ratio() Ok(
Dimension::ratio()
.map(|(r1, r2)| Rect { .map(|(r1, r2)| Rect {
x: max.x, x: max.x,
y: max.y, y: max.y,
width: max.width.min((w.min(PREVIEW.max_width as _) as f64 / r1).ceil() as _), width: max.width.min((w.min(PREVIEW.max_width as _) as f64 / r1).ceil() as _),
height: max.height.min((h.min(PREVIEW.max_height as _) as f64 / r2).ceil() as _), height: max.height.min((h.min(PREVIEW.max_height as _) as f64 / r2).ceil() as _),
}) })
.unwrap_or(max); .unwrap_or(max),
)
}
pub(super) async fn image_show(path: &Path, max: Rect) -> Result<Rect> {
let Some(tx) = &*DEMON else {
bail!("uninitialized ueberzugpp");
};
let area = Self::image_area(path, max).await?;
tx.send(Some((path.to_owned(), area)))?; tx.send(Some((path.to_owned(), area)))?;
Adapter::shown_store(area); Adapter::shown_store(area);