1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
#![allow(unreachable_patterns)]
#![allow(non_snake_case)]
pub mod decode;
pub mod encode;
#[non_exhaustive]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum OBIVersion {
One,
}
impl OBIVersion {
pub fn header_size(&self) -> u32 {
match self {
OBIVersion::One => 26,
}
}
}
#[non_exhaustive]
pub struct FileHeader {
pub file_size: u32,
pub data_offset: u32,
pub version: u16,
}
impl FileHeader {
pub fn new(version: OBIVersion, data_size: u32) -> Self {
let header_size = version.header_size();
Self {
version: match version {
OBIVersion::One => 1u16,
_ => unreachable!("New version has been added!"),
},
file_size: header_size + data_size,
data_offset: header_size,
}
}
}
#[non_exhaustive]
pub struct ImageInfoHeader {
pub width: u32,
pub height: u32,
pub compression_type: u32,
pub post_compression_size: u32,
}
impl ImageInfoHeader {
pub fn new(width: u32, height: u32) -> Self {
Self {
width,
height,
compression_type: 0u32,
post_compression_size: 0u32,
}
}
}
#[non_exhaustive]
pub enum CompressionType {
RLE,
Kosinki,
None,
}
impl CompressionType {
pub fn from_u32(kind: u32) -> Self {
match kind {
0 => CompressionType::None,
1 => CompressionType::RLE,
10 => CompressionType::Kosinki,
_ => panic!("Invalid compression algorithm"),
}
}
}
pub struct Image {
pub file_header: FileHeader,
pub image_info_header: ImageInfoHeader,
pub data: Vec<bool>,
}
impl Image {
pub fn new(width: u32, height: u32) -> Self {
// round to the nearest multiple of 8
// convert to number of bytes by dividing by 8
let mut data_size = width * height + 7;
data_size = data_size - (data_size % 8);
let data = vec![false; data_size as usize];
Self {
file_header: FileHeader::new(OBIVersion::One, data_size / 8),
image_info_header: ImageInfoHeader::new(width, height),
data,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::mem::size_of;
#[test]
fn size_of_image_info_header() {
let file_header_size = size_of::<ImageInfoHeader>();
assert_eq!(16, file_header_size);
}
#[test]
fn encode_decode() {
let img = Image::new(100, 80);
let encoded = encode::encode_image(img).unwrap();
assert_eq!(encoded.len(), 1026);
}
}
|