burnt_chroma/
lib.rs

1/*
2   Copyright 2023 Jasper Valdivia
3
4   Licensed under the Apache License, Version 2.0 (the "License");
5   you may not use this file except in compliance with the License.
6   You may obtain a copy of the License at
7
8       http://www.apache.org/licenses/LICENSE-2.0
9
10   Unless required by applicable law or agreed to in writing, software
11   distributed under the License is distributed on an "AS IS" BASIS,
12   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   See the License for the specific language governing permissions and
14   limitations under the License.
15*/
16
17#[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}