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 yazi_shared::env_exists;
use super::{Iip, Kgp, KgpOld};
use super::{Iip, Image, Kgp, KgpOld};
use crate::{Chafa, Emulator, SHOWN, Sixel, TMUX, Ueberzug, WSL};
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
@ -36,6 +36,20 @@ impl Display for 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> {
if max.is_empty() {
return Ok(Rect::default());

View file

@ -11,7 +11,11 @@ use crate::{Adapter, Emulator};
pub(super) struct 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")
.args([
"-f",
@ -52,16 +56,26 @@ impl Chafa {
width: first.width() as u16,
height: lines.len() as u16,
};
cb((lines, area))
}
Adapter::Chafa.image_hide()?;
Adapter::shown_store(area);
Emulator::move_lock((max.x, max.y), |stderr| {
for (i, line) in lines.into_iter().enumerate() {
stderr.write_all(line)?;
queue!(stderr, MoveTo(max.x, max.y + i as u16 + 1))?;
}
Ok(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::shown_store(area);
Emulator::move_lock((max.x, max.y), |stderr| {
for (i, line) in lines.into_iter().enumerate() {
stderr.write_all(line)?;
queue!(stderr, MoveTo(max.x, max.y + i as u16 + 1))?;
}
Ok(area)
})
})
.await
}
pub(super) fn image_erase(area: Rect) -> Result<()> {

View file

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

View file

@ -84,6 +84,13 @@ impl Image {
.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]
fn filter() -> FilterType {
match PREVIEW.image_filter.as_str() {

View file

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

View file

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

View file

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

View file

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