- Commit
- fc9009e6359bae934c6429aebd389846669d5b63
- Parent
- fe35f1247de21a19dac98f566076deb1de6ddce5
- Author
- Pablo <pablo-escobar@riseup.net>
- Date
Moved the code to render the thumbnails to the types module
Yet another static page generator for photo galleries
Moved the code to render the thumbnails to the types module
2 files changed, 83 insertions, 78 deletions
Status | File Name | N° Changes | Insertions | Deletions |
Modified | src/main.rs | 82 | 4 | 78 |
Modified | src/types.rs | 79 | 79 | 0 |
diff --git a/src/main.rs b/src/main.rs @@ -1,5 +1,3 @@ -use image::io::Reader as ImageReader; -use image::DynamicImage; use std::env; use std::fs::{self, File}; use std::io::{self, Write}; @@ -21,14 +19,6 @@ const PAGE_TITLE: &str = "Pablo's Photo Gallery"; const AUTHOR: &str = "Pablo"; const LICENSE: &str = "GPLv3"; -/// WebP image quality -const IMAGE_QUALITY: f32 = 50.0; - -/// Target height of the thumbnails, depending on wether the image is vertical -/// or horizontal -const HORIZONTAL_THUMB_HEIGHT: u32 = 300; -const VERTICAL_THUMB_HEIGHT: u32 = 800; - fn main() -> io::Result<()> { let args: Vec<String> = env::args().collect(); @@ -93,8 +83,11 @@ fn render_gallery(pic_infos: Vec<PictureInfo>) -> io::Result<()> { } // TODO: Parallelize this + let mut thumb_path = PathBuf::new(); + thumb_path.push(TARGET_PATH); + thumb_path.push(THUMBS_PATH); for pic in &pic_infos { - render_thumbnail(pic)?; + pic.render_thumbnail(&thumb_path)?; } render_index(&pic_infos)?; @@ -210,73 +203,6 @@ fn render_pic_page(pic: &PictureInfo) -> io::Result<()> { writeln!(f, "</html>") } -fn render_thumbnail(pic: &PictureInfo) -> io::Result<()> { - let mut thumb_path = PathBuf::new(); - thumb_path.push(TARGET_PATH); - thumb_path.push(THUMBS_PATH); - thumb_path.push(pic.file_name.clone() + ".webp"); - - // Only try to render thumbnail in case the thumbnail file in the machine - // is older than the source file - if let (Ok(thumb_meta), Ok(img_meta)) = (fs::metadata(&thumb_path), fs::metadata(&pic.path)) { - if thumb_meta.modified()? > img_meta.modified()? { - // TODO: Report a warning to the user - return Ok(()); - } - } - - let mut thumb_file = match File::create(&thumb_path) { - Ok(f) => f, - Err(err) => { - eprintln!("ERROR: Couldn't open WebP thumbnail file {thumb_path:?}: {err}"); - exit(1); - } - }; - - let img_reader = match ImageReader::open(&pic.path) { - Ok(r) => r, - Err(err) => { - eprintln!( - "ERROR: Couldn't open file {path:?} to render WebP thumbnail: {err}", - path = pic.file_name - ); - exit(1); - } - }; - - let img = match img_reader.decode() { - Ok(img) => img, - Err(err) => { - eprintln!( - "ERROR: Failed to decode image file {name:?}: {err}", - name = pic.file_name - ); - exit(1); - } - }; - - let h = if img.width() > img.height() { - HORIZONTAL_THUMB_HEIGHT - } else { - VERTICAL_THUMB_HEIGHT - }; - let w = (h * img.width()) / img.height(); - - // We should make sure that the image is in the RGBA8 format so that - // the webp crate can encode it - let img = DynamicImage::from(img.thumbnail(w, h).into_rgba8()); - let mem = webp::Encoder::from_image(&img) - .expect("image should be in the RGBA8 format") - .encode(IMAGE_QUALITY); - - if let Err(err) = thumb_file.write_all(&mem) { - eprintln!("ERROR: Couldn't write WebP thumnail to file {thumb_path:?}: {err}"); - exit(1); - } - - Ok(()) -} - fn write_nav(f: &mut File) -> io::Result<()> { writeln!(f, "<header>")?; writeln!(f, "<nav>")?;
diff --git a/src/types.rs b/src/types.rs @@ -1,9 +1,22 @@ +use image::io::Reader as ImageReader; +use image::DynamicImage; use serde::{ de::{Deserializer, Error, Unexpected}, Deserialize, }; use std::fmt::{self, Display}; +use std::fs::{self, File}; +use std::io::{self, Write}; use std::path::PathBuf; +use std::process::exit; + +/// WebP image quality +const IMAGE_QUALITY: f32 = 50.0; + +/// Target height of the thumbnails, depending on wether the image is vertical +/// or horizontal +const HORIZONTAL_THUMB_HEIGHT: u32 = 300; +const VERTICAL_THUMB_HEIGHT: u32 = 800; #[derive(Debug, Clone, PartialEq, Eq)] pub struct PictureInfo { @@ -14,6 +27,72 @@ pub struct PictureInfo { pub struct Escaped<'a>(pub &'a str); +impl PictureInfo { + pub fn render_thumbnail(&self, target_dir: &PathBuf) -> io::Result<()> { + let thumb_path = target_dir.join(self.file_name.clone() + ".webp"); + + // Only try to render thumbnail in case the thumbnail file in the machine + // is older than the source file + if let (Ok(thumb_meta), Ok(img_meta)) = (fs::metadata(&thumb_path), fs::metadata(&self.path)) { + if thumb_meta.modified()? > img_meta.modified()? { + // TODO: Report a warning to the user + return Ok(()); + } + } + + let mut thumb_file = match File::create(&thumb_path) { + Ok(f) => f, + Err(err) => { + eprintln!("ERROR: Couldn't open WebP thumbnail file {thumb_path:?}: {err}"); + exit(1); + } + }; + + let img_reader = match ImageReader::open(&self.path) { + Ok(r) => r, + Err(err) => { + eprintln!( + "ERROR: Couldn't open file {path:?} to render WebP thumbnail: {err}", + path = self.file_name + ); + exit(1); + } + }; + + let img = match img_reader.decode() { + Ok(img) => img, + Err(err) => { + eprintln!( + "ERROR: Failed to decode image file {name:?}: {err}", + name = self.file_name + ); + exit(1); + } + }; + + let h = if img.width() > img.height() { + HORIZONTAL_THUMB_HEIGHT + } else { + VERTICAL_THUMB_HEIGHT + }; + let w = (h * img.width()) / img.height(); + + // We should make sure that the image is in the RGBA8 format so that + // the webp crate can encode it + let img = DynamicImage::from(img.thumbnail(w, h).into_rgba8()); + let mem = webp::Encoder::from_image(&img) + .expect("image should be in the RGBA8 format") + .encode(IMAGE_QUALITY); + + if let Err(err) = thumb_file.write_all(&mem) { + eprintln!("ERROR: Couldn't write WebP thumnail to file {thumb_path:?}: {err}"); + exit(1); + } + + Ok(()) + } +} + impl<'de> Deserialize<'de> for PictureInfo { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where