mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-21 23:01:05 +00:00
perf: reduce peak memory footprint during decoding large images (#375)
This commit is contained in:
parent
ab7acfec5c
commit
6a64b162be
3 changed files with 38 additions and 22 deletions
|
|
@ -1,8 +1,7 @@
|
|||
use std::{path::Path, sync::Arc};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use anyhow::Result;
|
||||
use image::{imageops::FilterType, DynamicImage, ImageFormat};
|
||||
use tokio::fs;
|
||||
use yazi_config::PREVIEW;
|
||||
use yazi_shared::Term;
|
||||
|
||||
|
|
@ -17,32 +16,51 @@ impl Image {
|
|||
})
|
||||
.unwrap_or((PREVIEW.max_width, PREVIEW.max_height));
|
||||
|
||||
let img = fs::read(path).await?;
|
||||
let img = tokio::task::spawn_blocking(move || -> Result<DynamicImage> {
|
||||
let img = image::load_from_memory(&img)?;
|
||||
let path = path.to_owned();
|
||||
let img = tokio::task::spawn_blocking(move || {
|
||||
image::io::Reader::open(path)?.with_guessed_format()?.decode()
|
||||
})
|
||||
.await??;
|
||||
|
||||
tokio::task::spawn_blocking(move || {
|
||||
Ok(if img.width() > w || img.height() > h {
|
||||
img.resize(w, h, FilterType::Triangle)
|
||||
} else {
|
||||
img
|
||||
})
|
||||
});
|
||||
|
||||
img.await?
|
||||
})
|
||||
.await?
|
||||
}
|
||||
|
||||
pub async fn precache(img: Arc<Vec<u8>>, cache: impl AsRef<Path>) -> Result<()> {
|
||||
let cache = cache.as_ref().to_owned();
|
||||
let result = tokio::task::spawn_blocking(move || {
|
||||
let img = image::load_from_memory(&img)?;
|
||||
let (w, h) = (PREVIEW.max_width, PREVIEW.max_height);
|
||||
pub async fn precache(path: &Path, cache: PathBuf) -> Result<()> {
|
||||
let path = path.to_owned();
|
||||
let img = tokio::task::spawn_blocking(move || {
|
||||
image::io::Reader::open(path)?.with_guessed_format()?.decode()
|
||||
})
|
||||
.await??;
|
||||
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let (w, h) = (PREVIEW.max_width, PREVIEW.max_height);
|
||||
Ok(match img.resize(w, h, FilterType::Triangle) {
|
||||
DynamicImage::ImageRgb8(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.into_rgb8().save_with_format(cache, ImageFormat::Jpeg),
|
||||
}?)
|
||||
});
|
||||
})
|
||||
.await?
|
||||
}
|
||||
|
||||
result.await?
|
||||
pub async fn precache_bin(bin: Vec<u8>, cache: PathBuf) -> Result<()> {
|
||||
let img = tokio::task::spawn_blocking(move || image::load_from_memory(&bin)).await??;
|
||||
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let (w, h) = (PREVIEW.max_width, PREVIEW.max_height);
|
||||
Ok(match img.resize(w, h, FilterType::Triangle) {
|
||||
DynamicImage::ImageRgb8(buf) => buf.save_with_format(cache, ImageFormat::Jpeg),
|
||||
DynamicImage::ImageRgba8(buf) => buf.save_with_format(cache, ImageFormat::Jpeg),
|
||||
buf => buf.into_rgb8().save_with_format(cache, ImageFormat::Jpeg),
|
||||
}?)
|
||||
})
|
||||
.await?
|
||||
}
|
||||
}
|
||||
|
|
|
|||
6
yazi-core/src/external/pdftoppm.rs
vendored
6
yazi-core/src/external/pdftoppm.rs
vendored
|
|
@ -1,11 +1,11 @@
|
|||
use std::{path::Path, sync::Arc};
|
||||
use std::path::Path;
|
||||
|
||||
use regex::Regex;
|
||||
use tokio::process::Command;
|
||||
use yazi_adaptor::Image;
|
||||
use yazi_shared::PeekError;
|
||||
|
||||
pub async fn pdftoppm(src: &Path, dest: impl AsRef<Path>, skip: usize) -> Result<(), PeekError> {
|
||||
pub async fn pdftoppm(src: &Path, dest: &Path, skip: usize) -> Result<(), PeekError> {
|
||||
let output = Command::new("pdftoppm")
|
||||
.args(["-singlefile", "-jpeg", "-jpegopt", "quality=75", "-f"])
|
||||
.arg((skip + 1).to_string())
|
||||
|
|
@ -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()) };
|
||||
}
|
||||
|
||||
Ok(Image::precache(Arc::new(output.stdout), dest).await?)
|
||||
Ok(Image::precache_bin(output.stdout, dest.to_owned()).await?)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,9 +78,7 @@ impl Precache {
|
|||
if fs::symlink_metadata(&cache).await.is_ok() {
|
||||
return Ok(self.sch.send(TaskOp::Adv(task.id, 1, 0))?);
|
||||
}
|
||||
if let Ok(img) = fs::read(&task.target).await {
|
||||
Image::precache(Arc::new(img), cache).await.ok();
|
||||
}
|
||||
Image::precache(&task.target, cache).await.ok();
|
||||
self.sch.send(TaskOp::Adv(task.id, 1, 0))?;
|
||||
}
|
||||
PrecacheOp::Video(task) => {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue