- Commit
- 497770438ca689ac5654f3f2e07b7d4eeed4b31b
- Parent
- 791bf7edf2bb285bc126af9baa3bfdde1a147479
- Author
- Pablo <pablo-escobar@riseup.net>
- Date
Moved the rendering code back to the main file
Custum build of stapix for tikz.pablopie.xyz
Moved the rendering code back to the main file
2 files changed, 87 insertions, 93 deletions
Status | File Name | N° Changes | Insertions | Deletions |
Modified | src/main.rs | 91 | 86 | 5 |
Modified | src/picture.rs | 89 | 1 | 88 |
diff --git a/src/main.rs b/src/main.rs @@ -1,3 +1,5 @@ +use image::io::Reader as ImageReader; +use image::DynamicImage; use std::env; use std::fmt::{self, Display}; use std::fs::{self, File}; @@ -25,6 +27,14 @@ 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(); @@ -89,9 +99,6 @@ fn render_gallery(pics: Vec<Picture>) -> io::Result<()> { } // ======================================================================== - let mut thumb_path = PathBuf::from(TARGET_PATH); - thumb_path.push(THUMBS_PATH); - let rendering_pool = ThreadPool::with_name( String::from("thumbnails renderer"), num_cpus::get() + 1 @@ -101,9 +108,8 @@ fn render_gallery(pics: Vec<Picture>) -> io::Result<()> { for pic in &pics { let sender = sender.clone(); let pic = pic.clone(); - let thumb_path = thumb_path.clone(); rendering_pool.execute(move || { - sender.send(pic.render_thumbnail(&thumb_path)) + sender.send(render_thumbnail(pic)) .expect("channel should still be alive awaiting for the completion of this task"); }); } @@ -314,6 +320,81 @@ fn usage_config() { eprintln!(" ..."); } +/// Returns `true` if rendering succeded (or was skipped) and `false` +/// otherwise. All warinings and error messages should be logged in here. +// TODO: Render GIF files as mp4 instead +fn render_thumbnail(pic: Picture) -> bool { + let mut thumb_path = PathBuf::from(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)) { + let thumb_mod_date = thumb_meta.modified() + .expect("os should support file modification date"); + let img_mod_date = img_meta.modified() + .expect("os should support file modification date"); + + if thumb_mod_date > img_mod_date { + println!("WARNING: Skipped rendering the WebP thumbnail for {name:?}.\nUpdate {path:?} to overwrite this behaviour", + name = pic.file_name, path = pic.path); + return true; + } + } + + 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}"); + return false; + } + }; + + 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 + ); + return false; + } + }; + + let img = match img_reader.decode() { + Ok(img) => img, + Err(err) => { + eprintln!( + "ERROR: Faileded to decode image file {name:?}: {err}", + name = pic.file_name + ); + return false; + } + }; + + 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}"); + return false; + } + + true +} + impl<'a> Display for Escaped<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { for c in self.0.chars() {
diff --git a/src/picture.rs b/src/picture.rs @@ -1,20 +1,8 @@ -use image::io::Reader as ImageReader; -use image::DynamicImage; use serde::{ de::{Deserializer, Error, Unexpected}, Deserialize, }; -use std::fs::{self, File}; -use std::io::Write; -use std::path::{PathBuf, Path}; - -/// 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; +use std::path::PathBuf; #[derive(Debug, Clone, PartialEq, Eq)] pub struct Picture { @@ -23,81 +11,6 @@ pub struct Picture { pub alt: String, } -impl Picture { - // TODO: Render GIF files as mp4 instead - /// Returns `true` if rendering succeded (or was skipped) and `false` - /// otherwise. All warinings and error messages should be logged in here. - pub fn render_thumbnail(&self, target_dir: &Path) -> bool { - 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)) { - let thumb_mod_date = thumb_meta.modified() - .expect("os should support file modification date"); - let img_mod_date = img_meta.modified() - .expect("os should support file modification date"); - - if thumb_mod_date > img_mod_date { - println!("WARNING: Skipped rendering the WebP thumbnail for {name:?}.\nUpdate {path:?} to overwrite this behaviour", - name = self.file_name, path = self.path); - return true; - } - } - - 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}"); - return false; - } - }; - - 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 - ); - return false; - } - }; - - let img = match img_reader.decode() { - Ok(img) => img, - Err(err) => { - eprintln!( - "ERROR: Faileded to decode image file {name:?}: {err}", - name = self.file_name - ); - return false; - } - }; - - 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}"); - return false; - } - - true - } -} - impl<'de> Deserialize<'de> for Picture { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where