diff --git a/axum_server/.gitignore b/axum_server/.gitignore index b91269d..0cb7719 100644 --- a/axum_server/.gitignore +++ b/axum_server/.gitignore @@ -15,3 +15,6 @@ Cargo.lock # `dist` folder with the export of SSG dist/ + +# Image generator +generated_images/ diff --git a/axum_server/src/picture_generator/export_format.rs b/axum_server/src/picture_generator/export_format.rs index d38d564..739f0ba 100644 --- a/axum_server/src/picture_generator/export_format.rs +++ b/axum_server/src/picture_generator/export_format.rs @@ -1,27 +1,36 @@ +use image::ImageFormat; #[derive(Debug, PartialEq)] pub enum ExportFormat { - JPG, - AVIF, - SVG, - PNG, + Jpeg, + Avif, + Svg, + Png, } impl ExportFormat { pub fn get_extension(&self) -> &str { match self { - ExportFormat::JPG => "jpg", - ExportFormat::AVIF => "avif", - ExportFormat::SVG => "svg", - ExportFormat::PNG => "png", + ExportFormat::Jpeg => "jpg", + ExportFormat::Avif => "avif", + ExportFormat::Svg => "svg", + ExportFormat::Png => "png", } } pub fn get_type(&self) -> &str { match self { - ExportFormat::JPG => "image/jpeg", - ExportFormat::AVIF => "image/avif", - ExportFormat::SVG => "image/svg+xml", - ExportFormat::PNG => "image/png", + ExportFormat::Jpeg => "image/jpeg", + ExportFormat::Avif => "image/avif", + ExportFormat::Svg => "image/svg+xml", + ExportFormat::Png => "image/png", + } + } + pub fn get_image_format(&self) -> ImageFormat { + match self { + ExportFormat::Jpeg => ImageFormat::Jpeg, + ExportFormat::Avif => ImageFormat::Avif, + ExportFormat::Svg => ImageFormat::Jpeg, // TODO what now? + ExportFormat::Png => ImageFormat::Png, } } } diff --git a/axum_server/src/picture_generator/image_generator.rs b/axum_server/src/picture_generator/image_generator.rs new file mode 100644 index 0000000..705dd80 --- /dev/null +++ b/axum_server/src/picture_generator/image_generator.rs @@ -0,0 +1,47 @@ +use std::{fs::create_dir_all, path::Path}; + +use image::{imageops::FilterType, DynamicImage}; +use tracing::{debug, error}; + +use super::export_format::ExportFormat; + +pub fn generate_images( + image: &DynamicImage, + path_to_generated: &Path, + resolutions: &[(u32, u32, f32)], + formats: &[ExportFormat], +) -> Result<(), anyhow::Error> { + formats.iter().for_each(|format| { + resolutions.iter().for_each(|resolution| { + let (width, height, _) = *resolution; + // let image = image.clone(); + let resized = image.resize_to_fill(width, height, FilterType::Triangle); + let file_name = path_to_generated.file_name().unwrap().to_str().unwrap(); + let save_path = Path::new("./") + .join(path_to_generated.strip_prefix("/").unwrap()) + .with_file_name(format!("{file_name}_{width}x{height}")) + .with_extension(format.get_extension()); + + if save_path.exists() { + return; + } + + let parent_dir = save_path.parent().unwrap(); + if !parent_dir.exists() { + create_dir_all(parent_dir).unwrap(); + } + + let result = resized.save_with_format(&save_path, format.get_image_format()); + match result { + Err(err) => { + error!("Failed to generate {:?} - {:?}", &save_path, err); + } + _ => { + debug!("Generated image {:?}", &save_path); + } + } + }); + }); + + Ok(()) +} diff --git a/axum_server/src/picture_generator/mod.rs b/axum_server/src/picture_generator/mod.rs index aeddbeb..2070e6f 100644 --- a/axum_server/src/picture_generator/mod.rs +++ b/axum_server/src/picture_generator/mod.rs @@ -22,4 +22,5 @@ It should be used from the templates as well */ pub mod export_format; +pub mod image_generator; pub mod picture_markup_generator; diff --git a/axum_server/src/picture_generator/picture_markup_generator.rs b/axum_server/src/picture_generator/picture_markup_generator.rs index f819840..0f855b9 100644 --- a/axum_server/src/picture_generator/picture_markup_generator.rs +++ b/axum_server/src/picture_generator/picture_markup_generator.rs @@ -7,7 +7,7 @@ use std::{ use anyhow::Context; use image::{GenericImageView, ImageReader}; -use super::export_format::ExportFormat; +use super::{export_format::ExportFormat, image_generator::generate_images}; pub const PIXEL_DENSITIES: [f32; 5] = [1., 1.5, 2., 3., 4.]; @@ -29,6 +29,15 @@ pub fn generate_picture_markup( let orig_img_dimensions = orig_img.dimensions(); let resolutions = get_resolutions(orig_img_dimensions, width, height); + // TODO lets generate images + generate_images( + &orig_img, + &path_to_generated, + &resolutions, + &exported_formats, + ) + .with_context(|| "Failed to generate images".to_string())?; + let source_tags = exported_formats .iter() .map(|format| { @@ -243,8 +252,8 @@ fn get_export_formats(orig_img_path: &str) -> Vec { .and_then(|ext| ext.to_str()); match path { - Some("jpg" | "jpeg") => vec![ExportFormat::AVIF, ExportFormat::JPG], - Some("png") => vec![ExportFormat::AVIF, ExportFormat::PNG], + Some("jpg" | "jpeg") => vec![ExportFormat::Avif, ExportFormat::Jpeg], + Some("png") => vec![ExportFormat::Avif, ExportFormat::Png], Some(_) | None => vec![], } } @@ -253,13 +262,13 @@ fn get_export_formats(orig_img_path: &str) -> Vec { fn test_get_export_formats() { assert_eq!( get_export_formats("/images/uploads/img_name.jpg"), - vec![ExportFormat::AVIF, ExportFormat::JPG] + vec![ExportFormat::Avif, ExportFormat::Jpeg] ) } #[test] fn test_generate_srcset() { let orig_img_path = PathBuf::from_str("/generated_images/images/uploads/img_name").unwrap(); - let export_format = ExportFormat::AVIF; + let export_format = ExportFormat::Avif; let resolutions = vec![ (320, 200, 1.), (480, 300, 1.5),