amélioration de la webapp
This commit is contained in:
@@ -43,12 +43,14 @@ fn create_webp_transformer() -> StreamTransformer {
|
||||
// Convertir en WebP
|
||||
let img = image::load_from_memory(&bytes)
|
||||
.map_err(|e| format!("Image decode error: {}", e))?;
|
||||
let webp_data = crate::webp::encode_webp(&img)
|
||||
.map_err(|e| format!("WebP encode error: {}", e))?;
|
||||
let webp_data =
|
||||
crate::webp::encode_webp(&img).map_err(|e| format!("WebP encode error: {}", e))?;
|
||||
|
||||
// Écrire et mettre à jour la progression
|
||||
use tokio::io::AsyncWriteExt;
|
||||
file.write_all(&webp_data).await.map_err(|e| e.to_string())?;
|
||||
file.write_all(&webp_data)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
file.flush().await.map_err(|e| e.to_string())?;
|
||||
progress(webp_data.len() as u64);
|
||||
|
||||
|
||||
@@ -42,15 +42,15 @@ pub mod webp;
|
||||
#[cfg(feature = "pmoserver")]
|
||||
pub mod openapi;
|
||||
|
||||
pub use cache::{Cache, CoversConfig, new_cache};
|
||||
pub use cache::{new_cache, Cache, CoversConfig};
|
||||
|
||||
#[cfg(feature = "pmoserver")]
|
||||
pub use openapi::ApiDoc;
|
||||
|
||||
#[cfg(feature = "pmoserver")]
|
||||
use utoipa::OpenApi;
|
||||
#[cfg(feature = "pmoserver")]
|
||||
use std::sync::Arc;
|
||||
#[cfg(feature = "pmoserver")]
|
||||
use utoipa::OpenApi;
|
||||
|
||||
/// Générateur de variantes d'images
|
||||
///
|
||||
@@ -64,7 +64,13 @@ fn create_variant_generator() -> pmocache::pmoserver_ext::ParamGenerator<CoversC
|
||||
match webp::generate_variant(&cache, &pk, size).await {
|
||||
Ok(data) => return Some(data),
|
||||
Err(e) => {
|
||||
tracing::warn!("Cannot generate variant {}x{} for {}: {}", size, size, pk, e);
|
||||
tracing::warn!(
|
||||
"Cannot generate variant {}x{} for {}: {}",
|
||||
size,
|
||||
size,
|
||||
pk,
|
||||
e
|
||||
);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
@@ -98,21 +104,26 @@ pub trait CoverCacheExt {
|
||||
/// - `DELETE /api/covers/{pk}` - Supprimer une image (API REST)
|
||||
/// - `GET /api/covers/{pk}/status` - Statut du téléchargement
|
||||
/// - `GET /swagger-ui/covers` - Documentation interactive
|
||||
async fn init_cover_cache(&mut self, cache_dir: &str, limit: usize)
|
||||
-> anyhow::Result<Arc<Cache>>;
|
||||
async fn init_cover_cache(
|
||||
&mut self,
|
||||
cache_dir: &str,
|
||||
limit: usize,
|
||||
) -> anyhow::Result<Arc<Cache>>;
|
||||
|
||||
/// Initialise le cache d'images avec la configuration par défaut
|
||||
///
|
||||
/// Utilise automatiquement les paramètres de `pmoconfig::Config`
|
||||
async fn init_cover_cache_configured(&mut self)
|
||||
-> anyhow::Result<Arc<Cache>>;
|
||||
async fn init_cover_cache_configured(&mut self) -> anyhow::Result<Arc<Cache>>;
|
||||
}
|
||||
|
||||
#[cfg(feature = "pmoserver")]
|
||||
impl CoverCacheExt for pmoserver::Server {
|
||||
async fn init_cover_cache(&mut self, cache_dir: &str, limit: usize)
|
||||
-> anyhow::Result<Arc<Cache>> {
|
||||
use pmocache::pmoserver_ext::{create_file_router_with_generator, create_api_router};
|
||||
async fn init_cover_cache(
|
||||
&mut self,
|
||||
cache_dir: &str,
|
||||
limit: usize,
|
||||
) -> anyhow::Result<Arc<Cache>> {
|
||||
use pmocache::pmoserver_ext::{create_api_router, create_file_router_with_generator};
|
||||
|
||||
let cache = Arc::new(cache::new_cache(cache_dir, limit)?);
|
||||
|
||||
@@ -121,7 +132,7 @@ impl CoverCacheExt for pmoserver::Server {
|
||||
let file_router = create_file_router_with_generator(
|
||||
cache.clone(),
|
||||
"image/webp",
|
||||
Some(create_variant_generator())
|
||||
Some(create_variant_generator()),
|
||||
);
|
||||
self.add_router("/", file_router).await;
|
||||
|
||||
@@ -134,8 +145,7 @@ impl CoverCacheExt for pmoserver::Server {
|
||||
Ok(cache)
|
||||
}
|
||||
|
||||
async fn init_cover_cache_configured(&mut self)
|
||||
-> anyhow::Result<Arc<Cache>> {
|
||||
async fn init_cover_cache_configured(&mut self) -> anyhow::Result<Arc<Cache>> {
|
||||
let config = pmoconfig::get_config();
|
||||
let cache_dir = config.get_cover_cache_dir()?;
|
||||
let limit = config.get_cover_cache_size()?;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use anyhow::Result;
|
||||
use image::{DynamicImage, imageops::FilterType};
|
||||
use image::{imageops::FilterType, DynamicImage};
|
||||
use webp::{Encoder, WebPMemory};
|
||||
|
||||
pub fn encode_webp(img: &DynamicImage) -> Result<Vec<u8>> {
|
||||
@@ -11,34 +11,38 @@ pub fn encode_webp(img: &DynamicImage) -> Result<Vec<u8>> {
|
||||
|
||||
pub fn ensure_square(img: &DynamicImage, size: u32) -> DynamicImage {
|
||||
let (width, height) = (img.width(), img.height());
|
||||
|
||||
|
||||
// Calculer le ratio de mise à l'échelle
|
||||
let scale = if width > height {
|
||||
size as f32 / width as f32
|
||||
} else {
|
||||
size as f32 / height as f32
|
||||
};
|
||||
|
||||
|
||||
let new_width = (width as f32 * scale) as u32;
|
||||
let new_height = (height as f32 * scale) as u32;
|
||||
|
||||
|
||||
// Redimensionner l'image
|
||||
let resized = img.resize(new_width, new_height, FilterType::Lanczos3);
|
||||
|
||||
|
||||
// Créer une image carrée avec fond transparent
|
||||
let mut square = DynamicImage::new_rgba8(size, size);
|
||||
|
||||
|
||||
// Calculer la position pour centrer l'image redimensionnée
|
||||
let x = (size - new_width) / 2;
|
||||
let y = (size - new_height) / 2;
|
||||
|
||||
|
||||
// Copier l'image redimensionnée au centre du carré
|
||||
image::imageops::overlay(&mut square, &resized, x.into(), y.into());
|
||||
|
||||
|
||||
square
|
||||
}
|
||||
|
||||
pub async fn generate_variant(cache: &super::cache::Cache, pk: &str, size: usize) -> Result<Vec<u8>> {
|
||||
pub async fn generate_variant(
|
||||
cache: &super::cache::Cache,
|
||||
pk: &str,
|
||||
size: usize,
|
||||
) -> Result<Vec<u8>> {
|
||||
// Utiliser file_path_with_qualifier pour obtenir le chemin
|
||||
let variant_path = cache.file_path_with_qualifier(pk, &size.to_string());
|
||||
|
||||
@@ -49,10 +53,7 @@ pub async fn generate_variant(cache: &super::cache::Cache, pk: &str, size: usize
|
||||
let orig_path = cache.file_path_with_qualifier(pk, "orig");
|
||||
|
||||
// Charger l'image de manière synchrone (image::open n'est pas async)
|
||||
let img = tokio::task::spawn_blocking(move || {
|
||||
image::open(orig_path)
|
||||
})
|
||||
.await??;
|
||||
let img = tokio::task::spawn_blocking(move || image::open(orig_path)).await??;
|
||||
|
||||
let square = ensure_square(&img, size as u32);
|
||||
let webp_data = encode_webp(&square)?;
|
||||
|
||||
Reference in New Issue
Block a user