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 #[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 #[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 #[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 #[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 #[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 #[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}