diff options
-rw-r--r-- | src/lib.rs | 40 | ||||
-rw-r--r-- | tests/image.rs | 49 |
2 files changed, 79 insertions, 10 deletions
@@ -1,5 +1,6 @@ | |||
1 | #![allow(unreachable_patterns)] | 1 | #![allow(unreachable_patterns)] |
2 | #![allow(non_snake_case)] | 2 | #![allow(non_snake_case)] |
3 | #![allow(dead_code)] | ||
3 | 4 | ||
4 | use std::io; | 5 | use std::io; |
5 | 6 | ||
@@ -24,6 +25,7 @@ impl OBIVersion { | |||
24 | } | 25 | } |
25 | 26 | ||
26 | #[non_exhaustive] | 27 | #[non_exhaustive] |
28 | #[derive(Debug)] | ||
27 | pub struct FileHeader { | 29 | pub struct FileHeader { |
28 | pub file_size: u32, | 30 | pub file_size: u32, |
29 | pub data_offset: u32, | 31 | pub data_offset: u32, |
@@ -45,6 +47,7 @@ impl FileHeader { | |||
45 | } | 47 | } |
46 | 48 | ||
47 | #[non_exhaustive] | 49 | #[non_exhaustive] |
50 | #[derive(Debug)] | ||
48 | pub struct ImageInfoHeader { | 51 | pub struct ImageInfoHeader { |
49 | pub width: u32, | 52 | pub width: u32, |
50 | pub height: u32, | 53 | pub height: u32, |
@@ -82,6 +85,7 @@ impl CompressionType { | |||
82 | } | 85 | } |
83 | } | 86 | } |
84 | 87 | ||
88 | #[derive(Debug)] | ||
85 | pub struct Image { | 89 | pub struct Image { |
86 | pub file_header: FileHeader, | 90 | pub file_header: FileHeader, |
87 | pub image_info_header: ImageInfoHeader, | 91 | pub image_info_header: ImageInfoHeader, |
@@ -90,11 +94,15 @@ pub struct Image { | |||
90 | 94 | ||
91 | impl Image { | 95 | impl Image { |
92 | pub fn new(width: u32, height: u32) -> Self { | 96 | pub fn new(width: u32, height: u32) -> Self { |
97 | Self::new_with(width, height, false) | ||
98 | } | ||
99 | |||
100 | pub fn new_with(width: u32, height: u32, default_val: bool) -> Self { | ||
93 | // round to the nearest multiple of 8 | 101 | // round to the nearest multiple of 8 |
94 | // convert to number of bytes by dividing by 8 | 102 | // convert to number of bytes by dividing by 8 |
95 | let mut data_size = width * height + 7; | 103 | let mut data_size = width * height + 7; |
96 | data_size = data_size - (data_size % 8); | 104 | data_size = data_size - (data_size % 8); |
97 | let data = vec![false; data_size as usize]; | 105 | let data = vec![default_val; data_size as usize]; |
98 | 106 | ||
99 | Self { | 107 | Self { |
100 | file_header: FileHeader::new(OBIVersion::One, data_size / 8), | 108 | file_header: FileHeader::new(OBIVersion::One, data_size / 8), |
@@ -111,20 +119,32 @@ impl Image { | |||
111 | self.image_info_header.height | 119 | self.image_info_header.height |
112 | } | 120 | } |
113 | 121 | ||
114 | fn to_index(&self, x: u32, y: u32) -> usize { | 122 | #[doc(hidden)] |
115 | (y * self.width() + x) as usize | 123 | pub fn index(&self, x: u32, y: u32) -> OBIResult<usize> { |
116 | } | 124 | if x >= self.width() || y >= self.height() { |
117 | |||
118 | pub fn set_pixel(&mut self, x: u32, y: u32, val: bool) -> OBIResult<()> { | ||
119 | if x >= self.width() || y > self.height() { | ||
120 | Err(OBIError::Image) | 125 | Err(OBIError::Image) |
121 | } else { | 126 | } else { |
122 | let index = self.to_index(x, y); | 127 | return Ok((y * self.width() + x) as usize); |
123 | self.data[index] = val; | ||
124 | Ok(()) | ||
125 | } | 128 | } |
126 | } | 129 | } |
127 | 130 | ||
131 | pub fn set(&mut self, x: u32, y: u32, val: bool) -> OBIResult<()> { | ||
132 | let index = self.index(x, y)?; | ||
133 | self.data[index] = val; | ||
134 | Ok(()) | ||
135 | } | ||
136 | |||
137 | pub fn flip(&mut self, x: u32, y: u32) -> OBIResult<()> { | ||
138 | let index = self.index(x, y)?; | ||
139 | self.data[index] = !self.data[index]; | ||
140 | Ok(()) | ||
141 | } | ||
142 | |||
143 | pub fn get(&self, x: u32, y: u32) -> OBIResult<bool> { | ||
144 | let index = self.index(x, y)?; | ||
145 | Ok(self.data[index]) | ||
146 | } | ||
147 | |||
128 | pub fn encode(&self) -> OBIResult<Vec<u8>> { | 148 | pub fn encode(&self) -> OBIResult<Vec<u8>> { |
129 | encode::encode_image(self) | 149 | encode::encode_image(self) |
130 | } | 150 | } |
diff --git a/tests/image.rs b/tests/image.rs new file mode 100644 index 0000000..2006a3b --- /dev/null +++ b/tests/image.rs | |||
@@ -0,0 +1,49 @@ | |||
1 | use obi::Image; | ||
2 | |||
3 | #[test] | ||
4 | fn image_indexing() { | ||
5 | let (width, height) = (30, 50); | ||
6 | let img = Image::new(width, height); | ||
7 | for x in 0..width { | ||
8 | for y in 0..height { | ||
9 | assert_eq!((y * width + x) as usize, img.index(x, y).unwrap()); | ||
10 | } | ||
11 | } | ||
12 | } | ||
13 | |||
14 | #[test] | ||
15 | #[should_panic] | ||
16 | fn x_value_out_of_bounds() { | ||
17 | let img = Image::new(30, 50); | ||
18 | img.index(30, 0).unwrap(); | ||
19 | } | ||
20 | |||
21 | #[test] | ||
22 | #[should_panic] | ||
23 | fn y_value_out_of_bounds() { | ||
24 | let img = Image::new(30, 50); | ||
25 | img.index(0, 50).unwrap(); | ||
26 | } | ||
27 | |||
28 | #[test] | ||
29 | fn pixel_setter_and_getters() { | ||
30 | let mut img = Image::new(100, 200); | ||
31 | img.set(2, 3, true).unwrap(); | ||
32 | assert!(img.get(2, 3).unwrap()); | ||
33 | assert_eq!(1, img.data.iter().filter(|&&x| x).count()); | ||
34 | } | ||
35 | |||
36 | #[test] | ||
37 | fn flip_bits() { | ||
38 | let (width, height) = (100, 200); | ||
39 | let mut img = Image::new(width, height); | ||
40 | img.set(2, 3, true).expect("Indexing error"); | ||
41 | for i in 0..width { | ||
42 | for j in 0..height { | ||
43 | img.flip(i, j).unwrap(); | ||
44 | } | ||
45 | } | ||
46 | let mut expected = Image::new_with(width, height, true); | ||
47 | expected.set(2, 3, false).expect("Indexing error"); | ||
48 | assert_eq!(expected.data, img.data); | ||
49 | } | ||