Create a proper type to hold the target dimension
- ID
aac0292- date
2024-08-20 11:14:18+00:00- author
Alex Chan <alex@alexwlchan.net>- parent
7861191- message
Create a proper type to hold the target dimension- changed files
2 files, 53 additions, 77 deletions
Changed files
src/get_thumbnail_dimensions.rs (4497) → src/get_thumbnail_dimensions.rs (3810)
diff --git a/src/get_thumbnail_dimensions.rs b/src/get_thumbnail_dimensions.rs
index d596f7c..95c9f1e 100644
--- a/src/get_thumbnail_dimensions.rs
+++ b/src/get_thumbnail_dimensions.rs
@@ -2,6 +2,14 @@ use std::path::PathBuf;
use image::GenericImageView;
+/// Represents the target dimensions of the thumbnail.
+///
+/// The user can choose a max width, or a max height, but not both.
+pub enum TargetDimension {
+ MaxWidth(u32),
+ MaxHeight(u32),
+}
+
/// Given the path to the original image and the target width/height,
/// calculate the dimensions of the new image.
///
@@ -17,25 +25,16 @@ use image::GenericImageView;
///
pub fn get_thumbnail_dimensions(
path: &PathBuf,
- target_width: Option<u32>,
- target_height: Option<u32>,
+ target: TargetDimension,
) -> Result<(u32, u32), image::error::ImageError> {
- // Assert that exactly one of `target_width` and `target_height` are defined
- assert!(target_width.is_some() || target_height.is_some());
- assert!(target_width.is_none() || target_height.is_none());
-
- // Open the image, and compare its dimensions to the target
let img = image::open(path)?;
- // Calculate the new width/height of the image
- let (new_width, new_height) = match (target_width, target_height) {
- (Some(w), None) if w >= img.width() => img.dimensions(),
- (None, Some(h)) if h >= img.height() => img.dimensions(),
-
- (Some(w), None) => (w, w * img.height() / img.width()),
- (None, Some(h)) => (h * img.width() / img.height(), h),
+ let (new_width, new_height) = match target {
+ TargetDimension::MaxWidth(w) if w >= img.width() => img.dimensions(),
+ TargetDimension::MaxHeight(h) if h >= img.height() => img.dimensions(),
- _ => unreachable!(),
+ TargetDimension::MaxWidth(w) => (w, w * img.height() / img.width()),
+ TargetDimension::MaxHeight(h) => (h * img.width() / img.height(), h),
};
Ok((new_width, new_height))
@@ -53,10 +52,9 @@ mod test_get_thumbnail_dimensions {
fn with_target_width() {
let p = PathBuf::from("src/tests/red.png");
- let target_width: Option<u32> = Some(50);
- let target_height: Option<u32> = None;
+ let target = TargetDimension::MaxWidth(50);
- let dimensions = get_thumbnail_dimensions(&p, target_width, target_height);
+ let dimensions = get_thumbnail_dimensions(&p, target);
assert_eq!(dimensions.unwrap(), (50, 100));
}
@@ -64,10 +62,9 @@ mod test_get_thumbnail_dimensions {
fn with_target_height() {
let p = PathBuf::from("src/tests/red.png");
- let target_width: Option<u32> = None;
- let target_height: Option<u32> = Some(100);
+ let target = TargetDimension::MaxHeight(100);
- let dimensions = get_thumbnail_dimensions(&p, target_width, target_height);
+ let dimensions = get_thumbnail_dimensions(&p, target);
assert_eq!(dimensions.unwrap(), (50, 100));
}
@@ -75,10 +72,9 @@ mod test_get_thumbnail_dimensions {
fn leaves_image_as_is_if_target_width_greater_than_width() {
let p = PathBuf::from("src/tests/red.png");
- let target_width: Option<u32> = Some(500);
- let target_height: Option<u32> = None;
+ let target = TargetDimension::MaxWidth(500);
- let dimensions = get_thumbnail_dimensions(&p, target_width, target_height);
+ let dimensions = get_thumbnail_dimensions(&p, target);
assert_eq!(dimensions.unwrap(), (100, 200));
}
@@ -86,10 +82,9 @@ mod test_get_thumbnail_dimensions {
fn leaves_image_as_is_if_target_width_equal_to_width() {
let p = PathBuf::from("src/tests/red.png");
- let target_width: Option<u32> = Some(500);
- let target_height: Option<u32> = None;
+ let target = TargetDimension::MaxWidth(500);
- let dimensions = get_thumbnail_dimensions(&p, target_width, target_height);
+ let dimensions = get_thumbnail_dimensions(&p, target);
assert_eq!(dimensions.unwrap(), (100, 200));
}
@@ -97,10 +92,9 @@ mod test_get_thumbnail_dimensions {
fn leaves_image_as_is_if_target_height_greater_than_height() {
let p = PathBuf::from("src/tests/red.png");
- let target_width: Option<u32> = None;
- let target_height: Option<u32> = Some(500);
+ let target = TargetDimension::MaxHeight(500);
- let dimensions = get_thumbnail_dimensions(&p, target_width, target_height);
+ let dimensions = get_thumbnail_dimensions(&p, target);
assert_eq!(dimensions.unwrap(), (100, 200));
}
@@ -108,10 +102,9 @@ mod test_get_thumbnail_dimensions {
fn leaves_image_as_is_if_target_height_equal_to_height() {
let p = PathBuf::from("src/tests/red.png");
- let target_width: Option<u32> = None;
- let target_height: Option<u32> = Some(500);
+ let target = TargetDimension::MaxHeight(500);
- let dimensions = get_thumbnail_dimensions(&p, target_width, target_height);
+ let dimensions = get_thumbnail_dimensions(&p, target);
assert_eq!(dimensions.unwrap(), (100, 200));
}
@@ -119,10 +112,9 @@ mod test_get_thumbnail_dimensions {
fn errors_if_image_does_not_exist() {
let p = PathBuf::from("src/tests/doesnotexist.png");
- let target_width: Option<u32> = Some(50);
- let target_height: Option<u32> = None;
+ let target = TargetDimension::MaxWidth(50);
- let dimensions = get_thumbnail_dimensions(&p, target_width, target_height);
+ let dimensions = get_thumbnail_dimensions(&p, target);
assert!(dimensions.is_err());
}
@@ -130,10 +122,9 @@ mod test_get_thumbnail_dimensions {
fn errors_if_cannot_read_image() {
let p = PathBuf::from("README.md");
- let target_width: Option<u32> = Some(50);
- let target_height: Option<u32> = None;
+ let target = TargetDimension::MaxWidth(50);
- let dimensions = get_thumbnail_dimensions(&p, target_width, target_height);
+ let dimensions = get_thumbnail_dimensions(&p, target);
assert!(dimensions.is_err());
}
}
src/main.rs (8684) → src/main.rs (8332)
diff --git a/src/main.rs b/src/main.rs
index 6d0f2d1..9d5a40b 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -11,19 +11,15 @@ mod get_thumbnail_dimensions;
mod is_animated_gif;
use crate::create_parent_directory::create_parent_directory;
-use crate::get_thumbnail_dimensions::get_thumbnail_dimensions;
+use crate::get_thumbnail_dimensions::{get_thumbnail_dimensions, TargetDimension};
use crate::is_animated_gif::is_animated_gif;
/// Create a thumbnail for the image, and return the relative path of
/// the thumbnail within the collection folder.
-///
-/// TODO: Having two Option<u32> arguments is confusing because they could
-/// easily be swapped. Replace this with some sort of struct!
pub fn create_thumbnail(
path: &PathBuf,
out_dir: &PathBuf,
- width: Option<u32>,
- height: Option<u32>,
+ target: TargetDimension,
) -> io::Result<PathBuf> {
let thumbnail_path = out_dir.join(path.file_name().unwrap());
create_parent_directory(&thumbnail_path)?;
@@ -31,15 +27,9 @@ pub fn create_thumbnail(
// TODO: Does this check do what I think?
assert!(*path != thumbnail_path);
- println!("w = {:?}", width);
- println!("h = {:?}", height);
-
- let (new_width, new_height) = get_thumbnail_dimensions(&path, width, height)
+ let (new_width, new_height) = get_thumbnail_dimensions(&path, target)
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e.to_string()))?;
- println!("w = {:?}, h = {:?}", new_width, new_height);
-
- //
if is_animated_gif(path)? {
create_thumbnail::create_animated_gif_thumbnail(path, out_dir, new_width, new_height)
} else {
@@ -52,17 +42,16 @@ mod test_create_thumbnail {
use std::path::PathBuf;
use super::create_thumbnail;
+ use crate::get_thumbnail_dimensions::TargetDimension;
use crate::test_utils::{get_dimensions, test_dir};
#[test]
fn creates_an_animated_gif_thumbnail() {
let gif_path = PathBuf::from("src/tests/animated_squares.gif");
let out_dir = test_dir();
- let target_width = Some(16);
- let target_height = None;
+ let target = TargetDimension::MaxWidth(16);
- let thumbnail_path =
- create_thumbnail(&gif_path, &out_dir, target_width, target_height).unwrap();
+ let thumbnail_path = create_thumbnail(&gif_path, &out_dir, target).unwrap();
assert_eq!(thumbnail_path, out_dir.join("animated_squares.mp4"));
assert!(thumbnail_path.exists());
@@ -72,11 +61,9 @@ mod test_create_thumbnail {
fn creates_a_static_gif_thumbnail() {
let gif_path = PathBuf::from("src/tests/yellow.gif");
let out_dir = test_dir();
- let target_width = Some(16);
- let target_height = None;
+ let target = TargetDimension::MaxWidth(16);
- let thumbnail_path =
- create_thumbnail(&gif_path, &out_dir, target_width, target_height).unwrap();
+ let thumbnail_path = create_thumbnail(&gif_path, &out_dir, target).unwrap();
assert_eq!(thumbnail_path, out_dir.join("yellow.gif"));
assert!(thumbnail_path.exists());
@@ -87,11 +74,9 @@ mod test_create_thumbnail {
fn creates_a_png_thumbnail() {
let gif_path = PathBuf::from("src/tests/red.png");
let out_dir = test_dir();
- let target_width = Some(16);
- let target_height = None;
+ let target = TargetDimension::MaxWidth(16);
- let thumbnail_path =
- create_thumbnail(&gif_path, &out_dir, target_width, target_height).unwrap();
+ let thumbnail_path = create_thumbnail(&gif_path, &out_dir, target).unwrap();
assert_eq!(thumbnail_path, out_dir.join("red.png"));
assert!(thumbnail_path.exists());
@@ -102,11 +87,9 @@ mod test_create_thumbnail {
fn creates_a_jpeg_thumbnail() {
let gif_path = PathBuf::from("src/tests/noise.jpg");
let out_dir = test_dir();
- let target_width = Some(16);
- let target_height = None;
+ let target = TargetDimension::MaxWidth(16);
- let thumbnail_path =
- create_thumbnail(&gif_path, &out_dir, target_width, target_height).unwrap();
+ let thumbnail_path = create_thumbnail(&gif_path, &out_dir, target).unwrap();
assert_eq!(thumbnail_path, out_dir.join("noise.jpg"));
assert!(thumbnail_path.exists());
@@ -117,11 +100,9 @@ mod test_create_thumbnail {
fn creates_a_tif_thumbnail() {
let gif_path = PathBuf::from("src/tests/green.tiff");
let out_dir = test_dir();
- let target_width = Some(16);
- let target_height = None;
+ let target = TargetDimension::MaxHeight(16);
- let thumbnail_path =
- create_thumbnail(&gif_path, &out_dir, target_width, target_height).unwrap();
+ let thumbnail_path = create_thumbnail(&gif_path, &out_dir, target).unwrap();
assert_eq!(thumbnail_path, out_dir.join("green.tiff"));
assert!(thumbnail_path.exists());
@@ -132,11 +113,9 @@ mod test_create_thumbnail {
fn creates_a_webp_thumbnail() {
let gif_path = PathBuf::from("src/tests/purple.webp");
let out_dir = test_dir();
- let target_width = Some(16);
- let target_height = None;
+ let target = TargetDimension::MaxWidth(16);
- let thumbnail_path =
- create_thumbnail(&gif_path, &out_dir, target_width, target_height).unwrap();
+ let thumbnail_path = create_thumbnail(&gif_path, &out_dir, target).unwrap();
assert_eq!(thumbnail_path, out_dir.join("purple.webp"));
assert!(thumbnail_path.exists());
@@ -173,7 +152,13 @@ fn main() {
println!("args = {:?}", cli);
- create_thumbnail(&cli.path, &cli.out_dir, cli.width, cli.height).unwrap();
+ let target = match (cli.width, cli.height) {
+ (Some(w), None) => TargetDimension::MaxWidth(w),
+ (None, Some(h)) => TargetDimension::MaxHeight(h),
+ _ => unreachable!(),
+ };
+
+ create_thumbnail(&cli.path, &cli.out_dir, target).unwrap();
}
#[cfg(test)]