aboutsummaryrefslogtreecommitdiff
path: root/transcoder/src/image.rs
diff options
context:
space:
mode:
Diffstat (limited to 'transcoder/src/image.rs')
-rw-r--r--transcoder/src/image.rs89
1 files changed, 48 insertions, 41 deletions
diff --git a/transcoder/src/image.rs b/transcoder/src/image.rs
index 6da1be7..3865348 100644
--- a/transcoder/src/image.rs
+++ b/transcoder/src/image.rs
@@ -1,53 +1,60 @@
use anyhow::Context;
use image::{imageops::FilterType, ImageFormat};
-use jellybase::{cache_file, AssetLocationExt};
+use jellybase::{async_cache_file, AssetLocationExt};
use jellycommon::AssetLocation;
use log::{debug, info};
use rgb::FromSlice;
-use std::{
- fs::File,
- io::{BufReader, Write},
- path::PathBuf,
-};
+use std::{fs::File, io::BufReader};
+use tokio::io::AsyncWriteExt;
-pub fn transcode(
+pub async fn transcode(
asset: AssetLocation,
quality: f32,
speed: u8,
width: usize,
-) -> anyhow::Result<PathBuf> {
+) -> anyhow::Result<AssetLocation> {
let original_path = asset.path();
- let path = cache_file(&[
- original_path.as_os_str().to_str().unwrap(),
- &format!("{width} {quality} {speed}"),
- ])
- .path();
- if !path.exists() {
- info!("encoding {path:?} (speed={speed}, quality={quality}, width={width})");
- // TODO shouldn't be neccessary with guessed format.
- let file = BufReader::new(File::open(&original_path).context("opening source")?);
- let mut reader = image::io::Reader::new(file);
- reader.set_format(ImageFormat::Avif);
- let reader = reader.with_guessed_format().context("guessing format")?;
- debug!("guessed format (or fallback): {:?}", reader.format());
- let original = reader.decode().context("decoding image")?.to_rgba8();
- let image = image::imageops::resize(
- &original,
- width as u32,
- width as u32 * original.height() / original.width(),
- FilterType::Lanczos3,
- );
- let pixels = image.to_vec();
- let encoded = ravif::Encoder::new()
- .with_speed(speed.clamp(1, 10))
- .with_quality(quality.clamp(1., 100.))
- .encode_rgba(imgref::Img::new(
- pixels.as_rgba(),
- image.width() as usize,
- image.height() as usize,
- ))?;
- info!("transcode finished");
- File::create(&path)?.write_all(&encoded.avif_file)?;
- }
- Ok(path)
+ let asset = asset.clone();
+ Ok(async_cache_file(
+ &[
+ original_path.as_os_str().to_str().unwrap(),
+ &format!("{width} {quality} {speed}"),
+ ],
+ move |mut output| async move {
+ let encoded = tokio::task::spawn_blocking(move || {
+ let original_path = asset.path();
+ info!(
+ "encoding {original_path:?} (speed={speed}, quality={quality}, width={width})"
+ );
+ // TODO shouldn't be neccessary with guessed format.
+ let file = BufReader::new(File::open(&original_path).context("opening source")?);
+ let mut reader = image::io::Reader::new(file);
+ reader.set_format(ImageFormat::Avif);
+ let reader = reader.with_guessed_format().context("guessing format")?;
+ debug!("guessed format (or fallback): {:?}", reader.format());
+ let original = reader.decode().context("decoding image")?.to_rgba8();
+ let image = image::imageops::resize(
+ &original,
+ width as u32,
+ width as u32 * original.height() / original.width(),
+ FilterType::Lanczos3,
+ );
+ let pixels = image.to_vec();
+ let encoded = ravif::Encoder::new()
+ .with_speed(speed.clamp(1, 10))
+ .with_quality(quality.clamp(1., 100.))
+ .encode_rgba(imgref::Img::new(
+ pixels.as_rgba(),
+ image.width() as usize,
+ image.height() as usize,
+ ))?;
+ info!("transcode finished");
+ Ok::<_, anyhow::Error>(encoded)
+ })
+ .await??;
+ output.write_all(&encoded.avif_file).await?;
+ Ok(())
+ },
+ )
+ .await?)
}