add: lossy encode webp images

This commit is contained in:
trisua 2025-05-17 11:28:58 -04:00
parent 03480d32db
commit 24162573ee
8 changed files with 145 additions and 437 deletions

View file

@ -15,7 +15,7 @@ serde = { version = "1.0.219", features = ["derive"] }
tera = "1.20.0"
tracing = "0.1.41"
tracing-subscriber = { version = "0.3.19", features = ["env-filter"] }
tower-http = { version = "0.6.2", features = ["trace", "fs", "catch-panic"] }
tower-http = { version = "0.6.4", features = ["trace", "fs", "catch-panic"] }
axum = { version = "0.8.4", features = ["macros", "ws"] }
tokio = { version = "1.45.0", features = ["macros", "rt-multi-thread"] }
axum-extra = { version = "0.10.1", features = ["cookie", "multipart"] }
@ -47,3 +47,4 @@ async-stripe = { version = "0.41.0", features = [
"runtime-tokio-hyper",
] }
emojis = "0.6.4"
webp = "0.3.0"

View file

@ -57,31 +57,6 @@ where
}
}
/// Create an image buffer given an input of `bytes`
pub fn save_buffer(path: &str, bytes: Vec<u8>, format: image::ImageFormat) -> std::io::Result<()> {
let pre_img_buffer = match image::load_from_memory(&bytes) {
Ok(i) => i,
Err(_) => {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"Image failed",
));
}
};
let file = File::create(path)?;
let mut writer = BufWriter::new(file);
if pre_img_buffer.write_to(&mut writer, format).is_err() {
return Err(std::io::Error::new(
std::io::ErrorKind::Other,
"Image conversion failed",
));
};
Ok(())
}
/// A file extractor accepting:
/// * `multipart/form-data`
///
@ -163,3 +138,64 @@ where
Ok(Self(body, json))
}
}
/// Create an image buffer given an input of `bytes`.
pub fn save_buffer(path: &str, bytes: Vec<u8>, format: image::ImageFormat) -> std::io::Result<()> {
let pre_img_buffer = match image::load_from_memory(&bytes) {
Ok(i) => i,
Err(_) => {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"Image failed",
));
}
};
let file = File::create(path)?;
let mut writer = BufWriter::new(file);
if pre_img_buffer.write_to(&mut writer, format).is_err() {
return Err(std::io::Error::new(
std::io::ErrorKind::Other,
"Image conversion failed",
));
};
Ok(())
}
const WEBP_ENCODE_QUALITY: f32 = 85.0;
/// Create a WEBP image buffer given an input of `bytes`.
pub fn save_webp_buffer(path: &str, bytes: Vec<u8>) -> std::io::Result<()> {
let img = match image::load_from_memory(&bytes) {
Ok(i) => i,
Err(_) => {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"Image failed",
));
}
};
let encoder = match webp::Encoder::from_image(&img) {
Ok(e) => e,
Err(e) => {
return Err(std::io::Error::new(
std::io::ErrorKind::Other,
e.to_string(),
));
}
};
let mem = encoder.encode(WEBP_ENCODE_QUALITY);
if std::fs::write(path, &*mem).is_err() {
return Err(std::io::Error::new(
std::io::ErrorKind::Other,
"Image conversion failed",
));
};
Ok(())
}

View file

@ -1,6 +1,5 @@
use axum::{extract::Path, response::IntoResponse, Extension, Json};
use axum_extra::extract::CookieJar;
use image::ImageFormat;
use tetratto_core::model::{
communities::Post,
permissions::FinePermission,
@ -9,7 +8,7 @@ use tetratto_core::model::{
};
use crate::{
get_user_from_token,
image::{save_buffer, JsonMultipart},
image::{save_webp_buffer, JsonMultipart},
routes::api::v1::{CreatePost, CreateRepost, UpdatePostContent, UpdatePostContext},
State,
};
@ -109,11 +108,8 @@ pub async fn create_request(
Err(e) => return Json(e.into()),
};
if let Err(e) = save_buffer(
&upload.path(&data.0).to_string(),
image.to_vec(),
ImageFormat::WebP,
) {
if let Err(e) = save_webp_buffer(&upload.path(&data.0).to_string(), image.to_vec())
{
return Json(Error::MiscError(e.to_string()).into());
}
}