glance_core/
lib.rs

1pub mod drawing;
2mod error;
3pub mod img;
4
5pub use self::error::{CoreError, Result};
6
7#[cfg(test)]
8mod tests {
9    use rayon::iter::{IndexedParallelIterator, ParallelIterator};
10
11    use super::*;
12    use crate::drawing::shapes::Circle;
13    use crate::img::Image;
14    use crate::img::pixel::{Luma, Rgba};
15    use std::path::PathBuf;
16
17    // Open an image
18    #[test]
19    fn open_valid_image() -> Result<()> {
20        let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
21        path.push("../media/test_imgs/lichtenstein.png");
22
23        let img: Image<Rgba<u8>> = Image::open(&path)?;
24
25        if std::env::var("NO_DISPLAY").is_err() {
26            img.display("open_valid_image")?;
27        }
28
29        assert!(!img.is_empty());
30        Ok(())
31    }
32
33    // Open an invalid image path
34    #[test]
35    fn open_invalid_path() {
36        let result = Image::<Rgba<u8>>::open("non_existent_file.jpg");
37        assert!(result.is_err());
38    }
39
40    // Draw shapes on an image
41    #[test]
42    fn draw_shapes() -> Result<()> {
43        let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
44        path.push("../media/test_imgs/eye_orange.png");
45
46        let mut img = Image::open(&path)?;
47        let dims = img.dimensions();
48
49        let center = (dims.0 / 2, dims.1 / 2);
50        let green = Rgba {
51            r: 0u8,
52            g: 255u8,
53            b: 0u8,
54            a: 150u8,
55        };
56
57        img.draw(Circle {
58            position: center,
59            color: green,
60            radius: 100,
61            filled: true,
62            thickness: 5,
63        })?;
64
65        if std::env::var("NO_DISPLAY").is_err() {
66            img.display("draw_shapes")?;
67        }
68
69        assert!(img.get_pixel(center.into())? == &green);
70        Ok(())
71    }
72
73    // Convert an image to grayscale by making use of parallel iterators
74    #[test]
75    fn cvt_grayscale() -> Result<()> {
76        let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
77        path.push("../media/test_imgs/lichtenstein.png");
78
79        let mut img = Image::<Rgba<u8>>::open(&path)?;
80        img.par_pixels_mut().for_each(|pixel| {
81            let (r, g, b, _) = (pixel.r, pixel.g, pixel.b, pixel.a);
82            let l = 0.299f32 * r as f32 + 0.587f32 * g as f32 + 0.114f32 * b as f32;
83            let l = l as u8;
84            *pixel = Rgba {
85                r: l,
86                g: l,
87                b: l,
88                a: l,
89            };
90        });
91
92        if std::env::var("NO_DISPLAY").is_err() {
93            img.display("cvt_grayscale")?;
94        }
95
96        Ok(())
97    }
98
99    // Draw a point out of bounds, should still pass, as shape may be partially visible
100    #[test]
101    fn draw_partially_out_of_bounds_shape() -> Result<()> {
102        let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
103        path.push("../media/test_imgs/eye_orange.png");
104
105        let mut img = Image::<Rgba<u8>>::open(&path)?;
106        let center = img.dimensions();
107
108        let green = Rgba {
109            r: 0u8,
110            g: 255u8,
111            b: 0u8,
112            a: 150u8,
113        };
114
115        let black = Rgba {
116            r: 0u8,
117            g: 0u8,
118            b: 0u8,
119            a: 0u8,
120        };
121
122        img.draw(Circle {
123            position: center,
124            color: green,
125            radius: 100,
126            filled: false,
127            thickness: 5,
128        })?;
129
130        if std::env::var("NO_DISPLAY").is_err() {
131            img.display("draw_partially_out_of_bounds_shape")?;
132        }
133
134        assert!(img.get_pixel((center.0 - 1, center.1 - 1))? == &black);
135        Ok(())
136    }
137
138    // Create a Luma image and convert it to RGBA8
139    #[test]
140    fn create_luma_image_and_convert() -> Result<()> {
141        let mut img = Image::<Luma<u8>>::new(512, 512);
142        img.par_pixels_mut().enumerate().for_each(|(idx, pixel)| {
143            let x = idx % 512;
144            let value = (x as f32 / 511.0 * 255.0) as u8;
145            *pixel = Luma { l: value };
146        });
147
148        assert!(!img.is_empty());
149        assert_eq!(img.dimensions(), (512, 512));
150        assert_eq!(img.get_pixel((0, 0))?.l, 0);
151        assert_eq!(img.get_pixel((511, 0))?.l, 255);
152        if std::env::var("NO_DISPLAY").is_err() {
153            img.display("create_luma_image_and_convert")?;
154        }
155
156        Ok(())
157    }
158}