1#![cfg_attr(docsrs, feature(doc_cfg))]
2use core::fmt;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
8#[repr(u32)]
9pub enum PixelFormat {
10 Mono8 = 0x0108_0001,
11 Mono16 = 0x0110_0007,
12 BayerRG8 = 0x0108_0009,
13 BayerGB8 = 0x0108_000A,
14 BayerBG8 = 0x0108_000B,
15 BayerGR8 = 0x0108_0008,
16 RGB8Packed = 0x0218_0014,
17 BGR8Packed = 0x0218_0015,
18 Unknown(u32),
20}
21
22impl PixelFormat {
23 pub const fn from_code(code: u32) -> PixelFormat {
25 match code {
26 0x0108_0001 => PixelFormat::Mono8,
27 0x0110_0007 => PixelFormat::Mono16,
28 0x0108_0009 => PixelFormat::BayerRG8,
29 0x0108_000A => PixelFormat::BayerGB8,
30 0x0108_000B => PixelFormat::BayerBG8,
31 0x0108_0008 => PixelFormat::BayerGR8,
32 0x0218_0014 => PixelFormat::RGB8Packed,
33 0x0218_0015 => PixelFormat::BGR8Packed,
34 other => PixelFormat::Unknown(other),
35 }
36 }
37
38 pub const fn code(self) -> u32 {
40 match self {
41 PixelFormat::Mono8 => 0x0108_0001,
42 PixelFormat::Mono16 => 0x0110_0007,
43 PixelFormat::BayerRG8 => 0x0108_0009,
44 PixelFormat::BayerGB8 => 0x0108_000A,
45 PixelFormat::BayerBG8 => 0x0108_000B,
46 PixelFormat::BayerGR8 => 0x0108_0008,
47 PixelFormat::RGB8Packed => 0x0218_0014,
48 PixelFormat::BGR8Packed => 0x0218_0015,
49 PixelFormat::Unknown(code) => code,
50 }
51 }
52
53 pub const fn bytes_per_pixel(self) -> Option<usize> {
55 match self {
56 PixelFormat::Mono8 => Some(1),
57 PixelFormat::Mono16 => Some(2),
58 PixelFormat::RGB8Packed | PixelFormat::BGR8Packed => Some(3),
59 PixelFormat::BayerRG8
60 | PixelFormat::BayerGB8
61 | PixelFormat::BayerBG8
62 | PixelFormat::BayerGR8 => Some(1),
63 PixelFormat::Unknown(_) => None,
64 }
65 }
66
67 pub const fn is_bayer(self) -> bool {
69 matches!(
70 self,
71 PixelFormat::BayerRG8
72 | PixelFormat::BayerGB8
73 | PixelFormat::BayerBG8
74 | PixelFormat::BayerGR8
75 )
76 }
77
78 pub const fn cfa_pattern(self) -> Option<(&'static str, u8, u8)> {
84 match self {
85 PixelFormat::BayerRG8 => Some(("RGGB", 0, 0)),
86 PixelFormat::BayerGR8 => Some(("RGGB", 1, 0)),
87 PixelFormat::BayerGB8 => Some(("RGGB", 0, 1)),
88 PixelFormat::BayerBG8 => Some(("RGGB", 1, 1)),
89 _ => None,
90 }
91 }
92}
93
94impl fmt::Display for PixelFormat {
95 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96 match self {
97 PixelFormat::Mono8 => f.write_str("Mono8"),
98 PixelFormat::Mono16 => f.write_str("Mono16"),
99 PixelFormat::BayerRG8 => f.write_str("BayerRG8"),
100 PixelFormat::BayerGB8 => f.write_str("BayerGB8"),
101 PixelFormat::BayerBG8 => f.write_str("BayerBG8"),
102 PixelFormat::BayerGR8 => f.write_str("BayerGR8"),
103 PixelFormat::RGB8Packed => f.write_str("RGB8Packed"),
104 PixelFormat::BGR8Packed => f.write_str("BGR8Packed"),
105 PixelFormat::Unknown(code) => write!(f, "Unknown(0x{code:08X})"),
106 }
107 }
108}
109
110#[cfg(test)]
111mod tests {
112 use super::PixelFormat;
113
114 #[test]
115 fn roundtrip_known_codes() {
116 let formats = [
117 PixelFormat::Mono8,
118 PixelFormat::Mono16,
119 PixelFormat::BayerRG8,
120 PixelFormat::BayerGB8,
121 PixelFormat::BayerBG8,
122 PixelFormat::BayerGR8,
123 PixelFormat::RGB8Packed,
124 PixelFormat::BGR8Packed,
125 ];
126
127 for fmt in formats {
128 let code = fmt.code();
129 assert_eq!(PixelFormat::from_code(code), fmt);
130 }
131 }
132
133 #[test]
134 fn unknown_code_roundtrip() {
135 let code = 0xDEAD_BEEF;
136 let fmt = PixelFormat::from_code(code);
137 assert!(matches!(fmt, PixelFormat::Unknown(value) if value == code));
138 assert_eq!(fmt.code(), code);
139 }
140
141 #[test]
142 fn bytes_per_pixel_matches_expectations() {
143 assert_eq!(PixelFormat::Mono8.bytes_per_pixel(), Some(1));
144 assert_eq!(PixelFormat::Mono16.bytes_per_pixel(), Some(2));
145 assert_eq!(PixelFormat::RGB8Packed.bytes_per_pixel(), Some(3));
146 assert_eq!(PixelFormat::BayerRG8.bytes_per_pixel(), Some(1));
147 assert_eq!(PixelFormat::Unknown(0).bytes_per_pixel(), None);
148 }
149
150 #[test]
151 fn cfa_offsets_align_to_rggb() {
152 assert_eq!(PixelFormat::BayerRG8.cfa_pattern(), Some(("RGGB", 0, 0)));
153 assert_eq!(PixelFormat::BayerGR8.cfa_pattern(), Some(("RGGB", 1, 0)));
154 assert_eq!(PixelFormat::BayerGB8.cfa_pattern(), Some(("RGGB", 0, 1)));
155 assert_eq!(PixelFormat::BayerBG8.cfa_pattern(), Some(("RGGB", 1, 1)));
156 assert_eq!(PixelFormat::Mono8.cfa_pattern(), None);
157 }
158}