1use deku::prelude::*;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, DekuRead)]
5#[deku(endian = "little", id_type = "u8", ctx = "endian: deku::ctx::Endian")]
6pub enum DecodeType {
7 #[deku(id = 1)]
9 None,
10 #[deku(id = 2)]
12 Default,
13 #[deku(id = 3)]
15 Lossless,
16 #[deku(id = 4)]
18 Palette,
19 #[deku(id_pat = "_")]
21 Unknown { tag: u8 },
22}
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq, DekuRead)]
26#[deku(endian = "little", id_type = "u8", ctx = "endian: deku::ctx::Endian")]
27pub enum PixelFormat {
28 #[deku(id = 1)]
30 G8,
31 #[deku(id = 2)]
33 GA88,
34 #[deku(id = 3)]
36 Rgb888,
37 #[deku(id = 4)]
39 Rgba8888,
40 #[deku(id_pat = "_")]
42 Unknown { tag: u8 },
43}
44
45impl PixelFormat {
46 pub fn bytes_per_pixel(self) -> usize {
47 match self {
48 Self::G8 => 1,
49 Self::GA88 => 2,
50 Self::Rgb888 => 3,
51 Self::Rgba8888 => 4,
52 Self::Unknown { tag } => tag as usize,
53 }
54 }
55
56 pub fn has_alpha(self) -> bool {
57 matches!(self, Self::GA88 | Self::Rgba8888)
58 }
59
60 pub fn is_color(self) -> bool {
61 matches!(self, Self::Rgb888 | Self::Rgba8888)
62 }
63
64 pub fn split_stream_components(self) -> usize {
66 if self.is_color() { 3 } else { 1 }
67 }
68}
69
70#[derive(Debug, Clone, Copy, PartialEq, Eq, DekuRead)]
72#[deku(endian = "little", id_type = "u8", ctx = "endian: deku::ctx::Endian")]
73pub enum Predictor {
74 #[deku(id = 0)]
75 None,
76 #[deku(id = 1)]
77 Paeth,
78 #[deku(id = 2)]
79 Left,
80 #[deku(id = 3)]
81 Up,
82 #[deku(id = 4)]
83 Mean,
84 #[deku(id_pat = "_")]
85 Unknown { tag: u8 },
86}
87
88#[derive(Debug, Clone, DekuRead)]
106#[deku(magic = b"dmp2", endian = "little")]
107pub struct Deepmap2Header {
108 pub decode_type: DecodeType,
109 pub version: u8,
111 pub predictor_type: u8,
113 pub pixel_format: PixelFormat,
114 pub width: u16,
115 pub height: u16,
116 #[deku(cond = "matches!(decode_type, DecodeType::Palette)")]
118 pub palette_size: Option<u16>,
119 #[deku(cond = "matches!(decode_type, DecodeType::Palette)")]
120 pub palette_type: Option<u16>,
121 #[deku(count = "palette_size.unwrap_or(0) as usize")]
122 pub palette: Vec<u32>,
123}
124
125impl Deepmap2Header {
126 pub fn header_size(&self) -> usize {
128 if matches!(self.decode_type, DecodeType::Palette) {
129 16 + self.palette_size.unwrap_or(0) as usize * 4
130 } else {
131 12
132 }
133 }
134
135 pub fn chroma_scale(&self) -> u8 {
137 if self.version != 0 { 1 } else { 0 }
138 }
139
140 pub fn pixel_count(&self) -> usize {
141 self.width as usize * self.height as usize
142 }
143}
144
145#[cfg(test)]
146mod tests {
147 use super::*;
148
149 fn parse_header(bytes: &[u8]) -> Deepmap2Header {
150 let mut cursor = std::io::Cursor::new(bytes);
151 let mut reader = Reader::new(&mut cursor);
152 Deepmap2Header::from_reader_with_ctx(&mut reader, ()).unwrap()
153 }
154
155 #[test]
156 fn parse_known_header_default_type() {
157 let bytes: &[u8] = &[
159 0x64, 0x6d, 0x70, 0x32, 0x02, 0x01, 0x0a, 0x02, 0x64, 0x00, 0x90, 0x01, ];
167 let header = parse_header(bytes);
168 assert_eq!(header.decode_type, DecodeType::Default);
169 assert_eq!(header.version, 1);
170 assert_eq!(header.predictor_type, 10);
171 assert_eq!(header.pixel_format, PixelFormat::GA88);
172 assert_eq!(header.width, 100);
173 assert_eq!(header.height, 400);
174 assert_eq!(header.header_size(), 12);
175 assert_eq!(header.chroma_scale(), 1);
176 }
177
178 #[test]
179 fn parse_known_header_lossless_type() {
180 let bytes: &[u8] = &[
182 0x64, 0x6d, 0x70, 0x32, 0x03, 0x01, 0x0a, 0x02, 0x1e, 0x00, 0x32, 0x00, ];
186 let header = parse_header(bytes);
187 assert_eq!(header.decode_type, DecodeType::Lossless);
188 assert_eq!(header.width, 30);
189 assert_eq!(header.height, 50);
190 assert_eq!(header.header_size(), 12);
191 }
192
193 #[test]
194 fn parse_unknown_decode_type_returns_unknown_variant() {
195 let bytes: &[u8] = &[
196 0x64, 0x6d, 0x70, 0x32, 0xFF, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, ];
200 let header = parse_header(bytes);
201 assert!(matches!(
202 header.decode_type,
203 DecodeType::Unknown { tag: 0xFF }
204 ));
205 }
206
207 #[test]
208 fn header_size_palette_type() {
209 let mut bytes = vec![
211 0x64, 0x6d, 0x70, 0x32, 0x04, 0x01, 0x0a, 0x04, 0x10, 0x00, 0x10, 0x00, 0x02, 0x00, 0x04, 0x00, ];
217 bytes.extend_from_slice(&[0x00, 0x00, 0x00, 0xFF]); bytes.extend_from_slice(&[0xFF, 0x00, 0x00, 0xFF]); let header = parse_header(&bytes);
221 assert_eq!(header.decode_type, DecodeType::Palette);
222 assert_eq!(header.palette_size, Some(2));
223 assert_eq!(header.palette_type, Some(4));
224 assert_eq!(header.palette.len(), 2);
225 assert_eq!(header.header_size(), 24);
226 }
227}