diff options
-rw-r--r-- | Cargo.toml | 2 | ||||
-rw-r--r-- | src/encode.rs | 34 | ||||
-rw-r--r-- | src/lib.rs | 32 |
3 files changed, 54 insertions, 14 deletions
@@ -7,3 +7,5 @@ edition = "2018" | |||
7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html |
8 | 8 | ||
9 | [dependencies] | 9 | [dependencies] |
10 | byteorder = "1.4.2" | ||
11 | bitvec = "0.21.0" | ||
diff --git a/src/encode.rs b/src/encode.rs new file mode 100644 index 0000000..24d3792 --- /dev/null +++ b/src/encode.rs | |||
@@ -0,0 +1,34 @@ | |||
1 | use std::io; | ||
2 | |||
3 | use bitvec::prelude::*; | ||
4 | use bitvec::slice::BitSlice; | ||
5 | use byteorder::{LittleEndian, WriteBytesExt}; | ||
6 | |||
7 | use crate::Image; | ||
8 | |||
9 | pub fn encode_image(obi_image: Image) -> io::Result<Vec<u8>> { | ||
10 | let mut obi_data = Vec::with_capacity(obi_image.file_header.file_size as usize); | ||
11 | |||
12 | // file header | ||
13 | let file_header = obi_image.file_header; | ||
14 | obi_data.write_u16::<LittleEndian>(file_header.version)?; | ||
15 | obi_data.write_u32::<LittleEndian>(file_header.file_size)?; | ||
16 | obi_data.write_u32::<LittleEndian>(file_header.data_offset)?; | ||
17 | |||
18 | // image info header | ||
19 | let image_info_header = obi_image.image_info_header; | ||
20 | obi_data.write_u32::<LittleEndian>(image_info_header.width)?; | ||
21 | obi_data.write_u32::<LittleEndian>(image_info_header.height)?; | ||
22 | obi_data.write_u32::<LittleEndian>(image_info_header.compression_type)?; | ||
23 | obi_data.write_u32::<LittleEndian>(image_info_header.post_compression_size)?; | ||
24 | |||
25 | // pixmap data | ||
26 | let pixmap = obi_image.data; | ||
27 | for byte in pixmap.chunks(8) { | ||
28 | let bits_as_u8 = byte.iter().map(|&e| e as u8).collect::<Vec<_>>(); | ||
29 | let slice = BitSlice::<Lsb0, _>::from_slice(&bits_as_u8).unwrap(); | ||
30 | obi_data.write_u8(slice.load::<u8>())?; | ||
31 | } | ||
32 | |||
33 | return Ok(obi_data); | ||
34 | } | ||
@@ -1,11 +1,7 @@ | |||
1 | #![allow(unreachable_patterns)] | 1 | #![allow(unreachable_patterns)] |
2 | #![allow(non_snake_case)] | 2 | #![allow(non_snake_case)] |
3 | #[non_exhaustive] | 3 | |
4 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] | 4 | pub mod encode; |
5 | pub enum Pixel { | ||
6 | On, | ||
7 | Off, | ||
8 | } | ||
9 | 5 | ||
10 | #[non_exhaustive] | 6 | #[non_exhaustive] |
11 | #[derive(Copy, Clone, Debug, PartialEq)] | 7 | #[derive(Copy, Clone, Debug, PartialEq)] |
@@ -16,16 +12,16 @@ pub enum OBIVersion { | |||
16 | impl OBIVersion { | 12 | impl OBIVersion { |
17 | pub fn header_size(&self) -> u32 { | 13 | pub fn header_size(&self) -> u32 { |
18 | match self { | 14 | match self { |
19 | One => 26, | 15 | OBIVersion::One => 26, |
20 | } | 16 | } |
21 | } | 17 | } |
22 | } | 18 | } |
23 | 19 | ||
24 | #[non_exhaustive] | 20 | #[non_exhaustive] |
25 | pub struct FileHeader { | 21 | pub struct FileHeader { |
26 | pub version: u16, | ||
27 | pub file_size: u32, | 22 | pub file_size: u32, |
28 | pub data_offset: u32, | 23 | pub data_offset: u32, |
24 | pub version: u16, | ||
29 | } | 25 | } |
30 | 26 | ||
31 | impl FileHeader { | 27 | impl FileHeader { |
@@ -82,15 +78,19 @@ impl CompressionType { | |||
82 | pub struct Image { | 78 | pub struct Image { |
83 | pub file_header: FileHeader, | 79 | pub file_header: FileHeader, |
84 | pub image_info_header: ImageInfoHeader, | 80 | pub image_info_header: ImageInfoHeader, |
85 | pub data: Vec<Pixel>, | 81 | pub data: Vec<bool>, |
86 | } | 82 | } |
87 | 83 | ||
88 | impl Image { | 84 | impl Image { |
89 | pub fn new(width: u32, height: u32) -> Self { | 85 | pub fn new(width: u32, height: u32) -> Self { |
90 | let data_size = width * height; | 86 | // round to the nearest multiple of 8 |
91 | let data = vec![Pixel::Off; data_size as usize]; | 87 | // convert to number of bytes by dividing by 8 |
88 | let mut data_size = width * height + 7; | ||
89 | data_size = data_size - (data_size % 8); | ||
90 | let data = vec![false; data_size as usize]; | ||
91 | |||
92 | Self { | 92 | Self { |
93 | file_header: FileHeader::new(OBIVersion::One, data_size), | 93 | file_header: FileHeader::new(OBIVersion::One, data_size / 8), |
94 | image_info_header: ImageInfoHeader::new(width, height), | 94 | image_info_header: ImageInfoHeader::new(width, height), |
95 | data, | 95 | data, |
96 | } | 96 | } |
@@ -99,8 +99,12 @@ impl Image { | |||
99 | 99 | ||
100 | #[cfg(test)] | 100 | #[cfg(test)] |
101 | mod tests { | 101 | mod tests { |
102 | use super::*; | ||
103 | use std::mem::size_of; | ||
104 | |||
102 | #[test] | 105 | #[test] |
103 | fn it_works() { | 106 | fn size_of_image_info_header() { |
104 | assert_eq!(2 + 2, 4); | 107 | let file_header_size = size_of::<ImageInfoHeader>(); |
108 | assert_eq!(16, file_header_size); | ||
105 | } | 109 | } |
106 | } | 110 | } |