1#[cfg(debug_assertions)]
18macro_rules! debug_println {
19 ($($args:tt)*) => { println!($($args)*) };
20}
21
22mod processor {
23 use image::{imageops::FilterType, GenericImageView, ImageError, ImageFormat};
24 use std::path::{Path, PathBuf};
25
26 pub enum SqueezeFactor {
27 X1_33,
28 X1_5,
29 X1_75,
30 X2,
31 }
32
33 impl SqueezeFactor {
34 fn value(&self) -> f32 {
35 match *self {
36 SqueezeFactor::X1_33 => 1.33,
37 SqueezeFactor::X1_5 => 1.5,
38 SqueezeFactor::X1_75 => 1.75,
39 SqueezeFactor::X2 => 2.0,
40 }
41 }
42 }
43
44 pub fn desqueeze_image(
45 image_path: &str,
46 output_path: &str,
47 image_format: Option<ImageFormat>,
48 squeeze_factor: SqueezeFactor,
49 ) -> Result<String, ImageError> {
50 debug_println!("Identifying file name...");
51
52 let image_path = Path::new(image_path);
53
54 let target_image_format = image_format
55 .unwrap_or_else(|| {
56 image::ImageFormat::from_path(image_path).unwrap_or(ImageFormat::Png)
57 })
58 .extensions_str()
59 .first()
60 .unwrap_or(&"png")
61 .to_string();
62
63 let file_name = image_path
64 .file_stem()
65 .unwrap_or_else(|| image_path.as_os_str())
66 .to_str()
67 .unwrap_or("")
68 .to_string();
69
70 let output_path = Path::new(output_path);
71
72 debug_println!("{}", output_path.to_string_lossy());
73 debug_println!("Checking if output directory exists...");
74 if !output_path.try_exists()? {
75 debug_println!("Creating output directory...");
76 std::fs::create_dir(output_path)?;
77 }
78
79 debug_println!("Checking if outputh path is directory...");
80 let output_file_path: PathBuf;
81
82 if output_path.is_dir() {
83 debug_println!("Output path is directory");
84 output_file_path = output_path.join(format!("{}.{}", file_name, target_image_format));
85 debug_println!("Output path: {}", output_file_path.to_string_lossy());
86 } else {
87 debug_println!("Output path is not directory. Creating a new directory...");
88 output_file_path = output_path.join(format!("/{}.{}", file_name, target_image_format));
89 debug_println!("Output path: {}", output_file_path.to_string_lossy());
90 }
91
92 debug_println!("Desqueezing {}...", file_name);
93
94 let image = image::open(image_path)?;
95 let (width, height) = image.dimensions();
96
97 let mut width = width as f32;
98 let mut height = height as f32;
99
100 if width > height {
101 width *= squeeze_factor.value();
102 } else if height > width {
103 height *= squeeze_factor.value();
104 } else {
105 debug_println!("Do not desqueeze square images");
106 }
107
108 let path_ref = output_file_path.as_path();
109 debug_println!("{}", path_ref.to_string_lossy());
110 let new_image = image.resize_exact(width as u32, height as u32, FilterType::Nearest);
111 new_image.save(path_ref)?;
112 return Ok(path_ref.to_string_lossy().to_string());
113 }
114}
115#[cfg(test)]
116mod processor_tests {
117 use super::processor;
118
119 #[test]
120 fn should_desqueeze_landscape_image() {
121 let result = processor::desqueeze_image(
122 "src/tests/squeezedLandscape.jpeg",
123 "src/tests/output/",
124 None,
125 processor::SqueezeFactor::X1_33,
126 );
127
128 assert_eq!(result.is_ok(), true);
129 std::fs::remove_file("src/tests/output/squeezedLandscape.jpg").unwrap_or_else(|error| {
130 println!("Error: {}", error);
131 return ();
132 });
133 }
134
135 #[test]
136 fn should_desqueeze_portrait_image() {
137 let result = processor::desqueeze_image(
138 "src/tests/squeezedPortrait.jpeg",
139 "src/tests/output/",
140 None,
141 processor::SqueezeFactor::X1_33,
142 );
143 assert_eq!(result.is_ok(), true);
144 std::fs::remove_file("src/tests/output/squeezedPortrait.jpg").unwrap_or_else(|error| {
145 println!("Error: {}", error);
146 return ();
147 });
148 }
149}