mirror of
https://github.com/mfontanini/presenterm.git
synced 2025-05-05 23:42:59 +00:00
perf: cache ascii image resizes
This commit is contained in:
parent
a5e89eb5a3
commit
73211528a4
@ -43,8 +43,7 @@ vte = "0.15"
|
|||||||
rstest = { version = "0.25", default-features = false }
|
rstest = { version = "0.25", default-features = false }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
# TODO
|
default = []
|
||||||
default = ["sixel"]
|
|
||||||
sixel = ["sixel-rs"]
|
sixel = ["sixel-rs"]
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
|
@ -5,26 +5,34 @@ use crate::{
|
|||||||
printer::{TerminalCommand, TerminalIo},
|
printer::{TerminalCommand, TerminalIo},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use image::{DynamicImage, GenericImageView, Pixel, Rgba, imageops::FilterType};
|
use image::{DynamicImage, GenericImageView, Pixel, Rgba, RgbaImage, imageops::FilterType};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use std::{fs, ops::Deref, sync::Arc};
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
fs,
|
||||||
|
ops::Deref,
|
||||||
|
sync::{Arc, Mutex},
|
||||||
|
};
|
||||||
|
|
||||||
const TOP_CHAR: &str = "▀";
|
const TOP_CHAR: &str = "▀";
|
||||||
const BOTTOM_CHAR: &str = "▄";
|
const BOTTOM_CHAR: &str = "▄";
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub(crate) struct AsciiImage(Arc<DynamicImage>);
|
pub(crate) struct AsciiImage {
|
||||||
|
image: Arc<DynamicImage>,
|
||||||
|
cached_sizes: Arc<Mutex<HashMap<(u16, u16), RgbaImage>>>,
|
||||||
|
}
|
||||||
|
|
||||||
impl ImageProperties for AsciiImage {
|
impl ImageProperties for AsciiImage {
|
||||||
fn dimensions(&self) -> (u32, u32) {
|
fn dimensions(&self) -> (u32, u32) {
|
||||||
self.0.dimensions()
|
self.image.dimensions()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<DynamicImage> for AsciiImage {
|
impl From<DynamicImage> for AsciiImage {
|
||||||
fn from(image: DynamicImage) -> Self {
|
fn from(image: DynamicImage) -> Self {
|
||||||
let image = image.into_rgba8();
|
let image = image.into_rgba8();
|
||||||
Self(Arc::new(image.into()))
|
Self { image: Arc::new(image.into()), cached_sizes: Default::default() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,7 +40,7 @@ impl Deref for AsciiImage {
|
|||||||
type Target = DynamicImage;
|
type Target = DynamicImage;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.0
|
&self.image
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,18 +82,29 @@ impl PrintImage for AsciiPrinter {
|
|||||||
image::load_from_memory(&contents)?
|
image::load_from_memory(&contents)?
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok(AsciiImage(image.into()))
|
Ok(AsciiImage::from(image))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print<T>(&self, image: &Self::Image, options: &PrintOptions, terminal: &mut T) -> Result<(), PrintImageError>
|
fn print<T>(&self, image: &Self::Image, options: &PrintOptions, terminal: &mut T) -> Result<(), PrintImageError>
|
||||||
where
|
where
|
||||||
T: TerminalIo,
|
T: TerminalIo,
|
||||||
{
|
{
|
||||||
|
let columns = options.columns;
|
||||||
|
let rows = options.rows * 2;
|
||||||
|
let mut cached_sizes = image.cached_sizes.lock().unwrap();
|
||||||
|
// lookup on cache/resize the image and store it in cache
|
||||||
|
let cache_key = (columns, rows);
|
||||||
|
let image = match cached_sizes.get(&cache_key) {
|
||||||
|
Some(image) => image,
|
||||||
|
None => {
|
||||||
|
let image = image.image.resize_exact(columns as u32, rows as u32, FilterType::Triangle);
|
||||||
|
cached_sizes.insert(cache_key, image.into_rgba8());
|
||||||
|
cached_sizes.get(&cache_key).unwrap()
|
||||||
|
}
|
||||||
|
};
|
||||||
// The strategy here is taken from viuer: use half vertical ascii blocks in combination
|
// The strategy here is taken from viuer: use half vertical ascii blocks in combination
|
||||||
// with foreground/background colors to fit 2 vertical pixels per cell. That is, cell (x, y)
|
// with foreground/background colors to fit 2 vertical pixels per cell. That is, cell (x, y)
|
||||||
// will contain the pixels at (x, y) and (x, y + 1) combined.
|
// will contain the pixels at (x, y) and (x, y + 1) combined.
|
||||||
let image = image.0.resize_exact(options.columns as u32, 2 * options.rows as u32, FilterType::Triangle);
|
|
||||||
let image = image.into_rgba8();
|
|
||||||
let default_background = options.background_color.map(Color::from);
|
let default_background = options.background_color.map(Color::from);
|
||||||
|
|
||||||
// Iterate pixel rows in pairs to be able to merge both pixels in a single iteration.
|
// Iterate pixel rows in pairs to be able to merge both pixels in a single iteration.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user