1use crate::common::{read_size, read_variable_sized_unsigned_number};
2use crate::TinyVgParseError;
3use byteorder::ReadBytesExt;
4use std::io::{Cursor, Read};
5
6#[repr(u8)]
7#[derive(Debug, Copy, Clone, PartialEq)]
8pub enum ColorEncoding {
9 Rgba8888 = 0,
12
13 Rgb565 = 1,
19 RgbaF32 = 2,
24
25 Custom = 3
28}
29
30impl ColorEncoding {
31 fn from_u8(value: u8) -> ColorEncoding {
32 match value {
33 0 => ColorEncoding::Rgba8888,
34 1 => ColorEncoding::Rgb565,
35 2 => ColorEncoding::RgbaF32,
36 3 => ColorEncoding::Custom,
37 _ => unreachable!("ColorEncoding::from_u8 must be a 2-bit value.")
38 }
39 }
40}
41
42#[repr(u8)]
43#[derive(Debug, Copy, Clone)]
44pub enum CoordinateRange {
45 Default = 0,
47
48 Reduced = 1,
50
51 Enhanced = 2,
53}
54
55impl CoordinateRange {
56 fn from_u8(value: u8) -> CoordinateRange {
57 match value {
58 0 => CoordinateRange::Default,
59 1 => CoordinateRange::Reduced,
60 2 => CoordinateRange::Enhanced,
61 _ => unreachable!("CoordinateRange::from_u8 must be a 2-bit value.")
62 }
63 }
64}
65
66#[derive(Debug)]
67pub struct TinyVgHeader {
68 pub magic: [u8; 2],
70
71 pub version: u8,
73
74 pub scale: u8,
76
77 pub color_encoding: ColorEncoding,
79
80 pub coordinate_range: CoordinateRange,
83
84 pub width: u32,
88
89 pub height: u32,
93
94 pub color_count: u64,
96}
97
98impl TinyVgHeader {
99 pub(crate) fn parse(cursor: &mut Cursor<&[u8]>) -> Result<Self, TinyVgParseError> {
100 let mut magic = [0u8; 2];
101 cursor.read_exact(&mut magic).map_err(|_| TinyVgParseError::InvalidHeader)?;
102
103 if magic[0] != 0x72 || magic[1] != 0x56 {
105 return Err(TinyVgParseError::InvalidHeader);
106 }
107
108 let version = cursor.read_u8().map_err(|_| TinyVgParseError::InvalidHeader)?;
109
110 let scc = cursor.read_u8().map_err(|_| TinyVgParseError::InvalidHeader)?;
112
113 let scale: u8 = scc & 0x0F;
115
116 let color_encoding_raw = (scc & 0b00_11_00_00) >> 4;
118 let color_encoding = ColorEncoding::from_u8(color_encoding_raw);
119
120 let coordinate_range_raw = (scc & 0b11_00_00_00) >> 6;
122 let coordinate_range = CoordinateRange::from_u8(coordinate_range_raw);
123
124 let width: u32 = read_size(&coordinate_range, cursor)?;
125 let height: u32 = read_size(&coordinate_range, cursor)?;
126
127 let color_count = read_variable_sized_unsigned_number(cursor)?;
128
129 let header = TinyVgHeader {
130 magic,
131 version,
132 scale,
133 color_encoding,
134 coordinate_range,
135 width,
136 height,
137 color_count,
138 };
139
140 Ok(header)
141 }
142}