perf: precache small images to avoid cache misses; use symlink_metadata instead of metadata (#367)

This commit is contained in:
三咲雅 · Misaki Masa 2023-11-15 08:47:55 +08:00 committed by GitHub
parent 5968b82b0e
commit ff30b244b1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 16 additions and 30 deletions

View file

@ -170,7 +170,7 @@ impl Adaptor {
pub async fn image_show(self, mut path: &Path, rect: Rect) -> Result<()> { pub async fn image_show(self, mut path: &Path, rect: Rect) -> Result<()> {
let cache = PREVIEW.cache(path, 0); let cache = PREVIEW.cache(path, 0);
if fs::metadata(&cache).await.is_ok() { if fs::symlink_metadata(&cache).await.is_ok() {
path = cache.as_path(); path = cache.as_path();
} }

View file

@ -9,7 +9,7 @@ use yazi_shared::Term;
pub struct Image; pub struct Image;
impl Image { impl Image {
pub(super) async fn crop(path: &Path, size: (u16, u16)) -> Result<DynamicImage> { pub(super) async fn downscale(path: &Path, size: (u16, u16)) -> Result<DynamicImage> {
let (w, h) = Term::ratio() let (w, h) = Term::ratio()
.map(|(w, h)| { .map(|(w, h)| {
let (w, h) = ((size.0 as f64 * w) as u32, (size.1 as f64 * h) as u32); let (w, h) = ((size.0 as f64 * w) as u32, (size.1 as f64 * h) as u32);
@ -30,33 +30,19 @@ impl Image {
img.await? img.await?
} }
pub async fn precache(img: Arc<Vec<u8>>, cache: impl AsRef<Path>) -> Result<bool> { pub async fn precache(img: Arc<Vec<u8>>, cache: impl AsRef<Path>) -> Result<()> {
let cache = cache.as_ref().to_owned(); let cache = cache.as_ref().to_owned();
let result = tokio::task::spawn_blocking(move || { let result = tokio::task::spawn_blocking(move || {
let img = image::load_from_memory(&img)?; let img = image::load_from_memory(&img)?;
let (w, h) = (PREVIEW.max_width, PREVIEW.max_height); let (w, h) = (PREVIEW.max_width, PREVIEW.max_height);
if img.width() <= w && img.height() <= h { Ok(match img.resize(w, h, FilterType::Triangle) {
return Ok(false);
}
match img.resize(w, h, FilterType::Triangle) {
DynamicImage::ImageRgb8(buf) => buf.save_with_format(cache, ImageFormat::Jpeg), DynamicImage::ImageRgb8(buf) => buf.save_with_format(cache, ImageFormat::Jpeg),
DynamicImage::ImageRgba8(buf) => buf.save_with_format(cache, ImageFormat::Jpeg), DynamicImage::ImageRgba8(buf) => buf.save_with_format(cache, ImageFormat::Jpeg),
buf => buf.to_rgb8().save_with_format(cache, ImageFormat::Jpeg), buf => buf.to_rgb8().save_with_format(cache, ImageFormat::Jpeg),
}?; }?)
Ok(true)
}); });
result.await? result.await?
} }
#[inline]
pub async fn precache_anyway(img: Arc<Vec<u8>>, cache: impl AsRef<Path>) -> Result<()> {
Ok(match Self::precache(img.clone(), &cache).await {
Ok(true) => (),
_ => fs::write(cache, &*img).await?,
})
}
} }

View file

@ -13,7 +13,7 @@ pub(super) struct Iterm2;
impl Iterm2 { impl Iterm2 {
pub(super) async fn image_show(path: &Path, rect: Rect) -> Result<()> { pub(super) async fn image_show(path: &Path, rect: Rect) -> Result<()> {
let img = Image::crop(path, (rect.width, rect.height)).await?; let img = Image::downscale(path, (rect.width, rect.height)).await?;
let b = Self::encode(img).await?; let b = Self::encode(img).await?;
Self::image_hide(rect)?; Self::image_hide(rect)?;

View file

@ -313,7 +313,7 @@ pub(super) struct Kitty;
impl Kitty { impl Kitty {
pub(super) async fn image_show(path: &Path, rect: Rect) -> Result<()> { pub(super) async fn image_show(path: &Path, rect: Rect) -> Result<()> {
let img = Image::crop(path, (rect.width, rect.height)).await?; let img = Image::downscale(path, (rect.width, rect.height)).await?;
let b = Self::encode(img).await?; let b = Self::encode(img).await?;
Self::image_hide(rect)?; Self::image_hide(rect)?;

View file

@ -13,7 +13,7 @@ pub(super) struct KittyOld;
impl KittyOld { impl KittyOld {
pub(super) async fn image_show(path: &Path, rect: Rect) -> Result<()> { pub(super) async fn image_show(path: &Path, rect: Rect) -> Result<()> {
let img = Image::crop(path, (rect.width, rect.height)).await?; let img = Image::downscale(path, (rect.width, rect.height)).await?;
let b = Self::encode(img).await?; let b = Self::encode(img).await?;
Self::image_hide()?; Self::image_hide()?;

View file

@ -12,7 +12,7 @@ pub(super) struct Sixel;
impl Sixel { impl Sixel {
pub(super) async fn image_show(path: &Path, rect: Rect) -> Result<()> { pub(super) async fn image_show(path: &Path, rect: Rect) -> Result<()> {
let img = Image::crop(path, (rect.width, rect.height)).await?; let img = Image::downscale(path, (rect.width, rect.height)).await?;
let b = Self::encode(img).await?; let b = Self::encode(img).await?;
Self::image_hide(rect)?; Self::image_hide(rect)?;

View file

@ -25,5 +25,5 @@ pub async fn pdftoppm(src: &Path, dest: impl AsRef<Path>, skip: usize) -> Result
return if pages > 0 { Err(PeekError::Exceed(pages - 1)) } else { Err(s.to_string().into()) }; return if pages > 0 { Err(PeekError::Exceed(pages - 1)) } else { Err(s.to_string().into()) };
} }
Ok(Image::precache_anyway(Arc::new(output.stdout), dest).await?) Ok(Image::precache(Arc::new(output.stdout), dest).await?)
} }

View file

@ -144,7 +144,7 @@ impl Manager {
let mut failed = Vec::new(); let mut failed = Vec::new();
for (o, n) in todo { for (o, n) in todo {
if fs::metadata(&n).await.is_ok() { if fs::symlink_metadata(&n).await.is_ok() {
failed.push((o, n, anyhow!("Destination already exists"))); failed.push((o, n, anyhow!("Destination already exists")));
continue; continue;
} }

View file

@ -48,7 +48,7 @@ impl Provider {
pub(super) async fn video(path: &Path, skip: usize) -> Result<PreviewData, PeekError> { pub(super) async fn video(path: &Path, skip: usize) -> Result<PreviewData, PeekError> {
let cache = PREVIEW.cache(path, skip); let cache = PREVIEW.cache(path, skip);
if fs::metadata(&cache).await.is_err() { if fs::symlink_metadata(&cache).await.is_err() {
external::ffmpegthumbnailer(path, &cache, skip).await?; external::ffmpegthumbnailer(path, &cache, skip).await?;
} }
@ -57,7 +57,7 @@ impl Provider {
pub(super) async fn pdf(path: &Path, skip: usize) -> Result<PreviewData, PeekError> { pub(super) async fn pdf(path: &Path, skip: usize) -> Result<PreviewData, PeekError> {
let cache = PREVIEW.cache(path, skip); let cache = PREVIEW.cache(path, skip);
if fs::metadata(&cache).await.is_err() { if fs::symlink_metadata(&cache).await.is_err() {
external::pdftoppm(path, &cache, skip).await?; external::pdftoppm(path, &cache, skip).await?;
} }

View file

@ -75,7 +75,7 @@ impl Precache {
match task { match task {
PrecacheOp::Image(task) => { PrecacheOp::Image(task) => {
let cache = PREVIEW.cache(&task.target, 0); let cache = PREVIEW.cache(&task.target, 0);
if fs::metadata(&cache).await.is_ok() { if fs::symlink_metadata(&cache).await.is_ok() {
return Ok(self.sch.send(TaskOp::Adv(task.id, 1, 0))?); return Ok(self.sch.send(TaskOp::Adv(task.id, 1, 0))?);
} }
if let Ok(img) = fs::read(&task.target).await { if let Ok(img) = fs::read(&task.target).await {
@ -85,7 +85,7 @@ impl Precache {
} }
PrecacheOp::Video(task) => { PrecacheOp::Video(task) => {
let cache = PREVIEW.cache(&task.target, 0); let cache = PREVIEW.cache(&task.target, 0);
if fs::metadata(&cache).await.is_ok() { if fs::symlink_metadata(&cache).await.is_ok() {
return Ok(self.sch.send(TaskOp::Adv(task.id, 1, 0))?); return Ok(self.sch.send(TaskOp::Adv(task.id, 1, 0))?);
} }
@ -94,7 +94,7 @@ impl Precache {
} }
PrecacheOp::Pdf(task) => { PrecacheOp::Pdf(task) => {
let cache = PREVIEW.cache(&task.target, 0); let cache = PREVIEW.cache(&task.target, 0);
if fs::metadata(&cache).await.is_ok() { if fs::symlink_metadata(&cache).await.is_ok() {
return Ok(self.sch.send(TaskOp::Adv(task.id, 1, 0))?); return Ok(self.sch.send(TaskOp::Adv(task.id, 1, 0))?);
} }