create_thumbnail: rearrange the tests; unexport a couple of functions
- ID
f89b9c8- date
2026-09-24 05:10:13+00:00- author
Alex Chan <alex@alexwlchan.net>- parent
35224b6- message
create_thumbnail: rearrange the tests; unexport a couple of functions- changed files
1 file, 100 additions, 100 deletions
Changed files
src/create_thumbnail.rs (8803 → 8795)
diff --git a/src/create_thumbnail.rs b/src/create_thumbnail.rs
index eb0d5c8..04fe0c3 100644
--- a/src/create_thumbnail.rs
+++ b/src/create_thumbnail.rs
@@ -35,6 +35,106 @@ pub fn create_thumbnail(
}
}
+/// Create a thumbnail for an animated GIF.
+///
+/// This will use `ffmpeg` to create an MP4 file of the desired dimensions
+/// which plays the GIF on a loop. This is typically much smaller and more
+/// space-efficient than creating a resized GIF.
+///
+/// This function assumes that the original GIF file definitely exists.
+///
+/// TODO: It would be nice to have a test for the case where `ffmpeg` isn't
+/// installed, but I'm not sure how to simulate that.
+///
+fn create_animated_gif_thumbnail(
+ gif_path: &PathBuf,
+ out_dir: &PathBuf,
+ width: u32,
+ height: u32,
+) -> Result<PathBuf, ThumbnailError> {
+ let file_name = gif_path
+ .file_name()
+ .ok_or(ThumbnailError::MissingFileName)?;
+
+ let thumbnail_path = out_dir.join(file_name).with_extension("mp4");
+
+ let gif_path_str = gif_path
+ .to_str()
+ .ok_or(ThumbnailError::PathConversionError)?;
+ let thumbnail_path_str = thumbnail_path
+ .to_str()
+ .ok_or(ThumbnailError::PathConversionError)?;
+
+ // There's a subtlety here with ffmpeg I don't understand fully -- if
+ // the width/height aren't even, it doesn't create the MP4, instead
+ // failing with the error:
+ //
+ // width not divisible by 2
+ //
+ // I don't usually need these files to be pixel-perfect width, so
+ // fudging by a single pixel or two is fine.
+ let dimension_str = format!("scale={}:{}", ensure_even(width), ensure_even(height));
+
+ let output = Command::new("ffmpeg")
+ .args([
+ "-i",
+ gif_path_str,
+ "-movflags",
+ "faststart",
+ "-pix_fmt",
+ "yuv420p",
+ "-vf",
+ &dimension_str,
+ thumbnail_path_str,
+ ])
+ .output()
+ .map_err(|e| ThumbnailError::CommandFailed(format!("Failed to run ffmpeg: {}", e)))?;
+
+ if output.status.success() {
+ Ok(thumbnail_path)
+ } else {
+ let stderr = str::from_utf8(&output.stderr)?;
+ Err(ThumbnailError::CommandFailed(stderr.to_string()))
+ }
+}
+
+/// Return this value if it's even, or the closest value which is even.
+fn ensure_even(x: u32) -> u32 {
+ if x % 2 == 0 {
+ x
+ } else {
+ x + 1
+ }
+}
+
+/// Create a thumbnail for a static (non-animated) image.
+///
+/// This function assumes that the original image file definitely exists.
+///
+fn create_static_thumbnail(
+ image_path: &PathBuf,
+ out_dir: &PathBuf,
+ width: u32,
+ height: u32,
+) -> Result<PathBuf, ThumbnailError> {
+ let file_name = image_path
+ .file_name()
+ .ok_or(ThumbnailError::MissingFileName)?;
+
+ let thumbnail_path = out_dir.join(file_name);
+
+ let mut decoder = ImageReader::open(image_path)?.into_decoder()?;
+ let orientation = decoder.orientation()?;
+ let mut img = DynamicImage::from_decoder(decoder)?;
+ img.apply_orientation(orientation);
+
+ img.resize(width, height, FilterType::Lanczos3)
+ .save(&thumbnail_path)
+ .map_err(ThumbnailError::ImageSaveError)?;
+
+ Ok(thumbnail_path)
+}
+
#[cfg(test)]
mod test_create_thumbnail {
use std::path::PathBuf;
@@ -161,103 +261,3 @@ mod test_create_thumbnail {
assert_eq!(get_dimensions(&thumbnail_path), (180, 120));
}
}
-
-/// Return this value if it's even, or the closest value which is even.
-fn ensure_even(x: u32) -> u32 {
- if x % 2 == 0 {
- x
- } else {
- x + 1
- }
-}
-
-/// Create a thumbnail for an animated GIF.
-///
-/// This will use `ffmpeg` to create an MP4 file of the desired dimensions
-/// which plays the GIF on a loop. This is typically much smaller and more
-/// space-efficient than creating a resized GIF.
-///
-/// This function assumes that the original GIF file definitely exists.
-///
-/// TODO: It would be nice to have a test for the case where `ffmpeg` isn't
-/// installed, but I'm not sure how to simulate that.
-///
-pub fn create_animated_gif_thumbnail(
- gif_path: &PathBuf,
- out_dir: &PathBuf,
- width: u32,
- height: u32,
-) -> Result<PathBuf, ThumbnailError> {
- let file_name = gif_path
- .file_name()
- .ok_or(ThumbnailError::MissingFileName)?;
-
- let thumbnail_path = out_dir.join(file_name).with_extension("mp4");
-
- let gif_path_str = gif_path
- .to_str()
- .ok_or(ThumbnailError::PathConversionError)?;
- let thumbnail_path_str = thumbnail_path
- .to_str()
- .ok_or(ThumbnailError::PathConversionError)?;
-
- // There's a subtlety here with ffmpeg I don't understand fully -- if
- // the width/height aren't even, it doesn't create the MP4, instead
- // failing with the error:
- //
- // width not divisible by 2
- //
- // I don't usually need these files to be pixel-perfect width, so
- // fudging by a single pixel or two is fine.
- let dimension_str = format!("scale={}:{}", ensure_even(width), ensure_even(height));
-
- let output = Command::new("ffmpeg")
- .args([
- "-i",
- gif_path_str,
- "-movflags",
- "faststart",
- "-pix_fmt",
- "yuv420p",
- "-vf",
- &dimension_str,
- thumbnail_path_str,
- ])
- .output()
- .map_err(|e| ThumbnailError::CommandFailed(format!("Failed to run ffmpeg: {}", e)))?;
-
- if output.status.success() {
- Ok(thumbnail_path)
- } else {
- let stderr = str::from_utf8(&output.stderr)?;
- Err(ThumbnailError::CommandFailed(stderr.to_string()))
- }
-}
-
-/// Create a thumbnail for a static (non-animated) image.
-///
-/// This function assumes that the original image file definitely exists.
-///
-pub fn create_static_thumbnail(
- image_path: &PathBuf,
- out_dir: &PathBuf,
- width: u32,
- height: u32,
-) -> Result<PathBuf, ThumbnailError> {
- let file_name = image_path
- .file_name()
- .ok_or(ThumbnailError::MissingFileName)?;
-
- let thumbnail_path = out_dir.join(file_name);
-
- let mut decoder = ImageReader::open(image_path)?.into_decoder()?;
- let orientation = decoder.orientation()?;
- let mut img = DynamicImage::from_decoder(decoder)?;
- img.apply_orientation(orientation);
-
- img.resize(width, height, FilterType::Lanczos3)
- .save(&thumbnail_path)
- .map_err(ThumbnailError::ImageSaveError)?;
-
- Ok(thumbnail_path)
-}