1#[cfg(not(feature = "std"))]
14extern crate core as std;
15
16use std::convert::TryFrom;
17
18#[derive(Debug, Clone, Copy, PartialEq)]
20#[non_exhaustive]
21pub enum PixFmt {
22 Mono8,
23 Mono32f,
24 RGB8,
25 RGBA8,
26 BayerRG8,
27 BayerRG32f,
28 BayerBG8,
29 BayerBG32f,
30 BayerGB8,
31 BayerGB32f,
32 BayerGR8,
33 BayerGR32f,
34 YUV444,
35 YUV422,
36 NV12,
37}
38
39impl PixFmt {
40 pub fn to_static<FMT: PixelFormat>(&self) -> Option<std::marker::PhantomData<FMT>> {
42 let other = pixfmt::<FMT>();
43 if Ok(self) == other.as_ref() {
44 Some(std::marker::PhantomData)
45 } else {
46 None
47 }
48 }
49 pub const fn bits_per_pixel(&self) -> u8 {
51 use PixFmt::*;
52 match self {
53 Mono8 => 8,
54 Mono32f => 32,
55 RGB8 => 24,
56 RGBA8 => 32,
57 BayerRG8 => 8,
58 BayerRG32f => 32,
59 BayerBG8 => 8,
60 BayerBG32f => 32,
61 BayerGB8 => 8,
62 BayerGB32f => 32,
63 BayerGR8 => 8,
64 BayerGR32f => 32,
65 YUV444 => 24,
66 YUV422 => 16,
67 NV12 => 12,
68 }
69 }
70 pub const fn as_str(&self) -> &'static str {
72 use PixFmt::*;
73 match self {
74 Mono8 => "Mono8",
75 Mono32f => "Mono32f",
76 RGB8 => "RGB8",
77 RGBA8 => "RGBA8",
78 BayerRG8 => "BayerRG8",
79 BayerRG32f => "BayerRG32f",
80 BayerBG8 => "BayerBG8",
81 BayerBG32f => "BayerBG32f",
82 BayerGB8 => "BayerGB8",
83 BayerGB32f => "BayerGB32f",
84 BayerGR8 => "BayerGR8",
85 BayerGR32f => "BayerGR32f",
86 YUV444 => "YUV444",
87 YUV422 => "YUV422",
88 NV12 => "NV12",
89 }
90 }
91}
92
93impl std::fmt::Display for PixFmt {
94 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
95 write!(f, "{}", self.as_str())
96 }
97}
98
99impl std::str::FromStr for PixFmt {
100 type Err = &'static str;
101 fn from_str(instr: &str) -> Result<Self, <Self as std::str::FromStr>::Err> {
102 use PixFmt::*;
103 if instr == "Mono8" {
104 Ok(Mono8)
105 } else if instr == "Mono32f" {
106 Ok(Mono32f)
107 } else if instr == "RGB8" {
108 Ok(RGB8)
109 } else if instr == "RGBA8" {
110 Ok(RGBA8)
111 } else if instr == "BayerRG8" {
112 Ok(BayerRG8)
113 } else if instr == "BayerRG32f" {
114 Ok(BayerRG32f)
115 } else if instr == "BayerBG8" {
116 Ok(BayerBG8)
117 } else if instr == "BayerBG32f" {
118 Ok(BayerBG32f)
119 } else if instr == "BayerGB8" {
120 Ok(BayerGB8)
121 } else if instr == "BayerGB32f" {
122 Ok(BayerGB32f)
123 } else if instr == "BayerGR8" {
124 Ok(BayerGR8)
125 } else if instr == "BayerGR32f" {
126 Ok(BayerGR32f)
127 } else if instr == "YUV444" {
128 Ok(YUV444)
129 } else if instr == "YUV422" {
130 Ok(YUV422)
131 } else if instr == "NV12" {
132 Ok(NV12)
133 } else {
134 Err("Cannot parse string")
135 }
136 }
137}
138
139#[test]
140fn test_pixfmt_roundtrip() {
141 use PixFmt::*;
142 let fmts = [
143 Mono8, Mono32f, RGB8, RGBA8, BayerRG8, BayerRG32f, BayerBG8, BayerBG32f, BayerGB8,
144 BayerGB32f, BayerGR8, BayerGR32f, YUV444, YUV422, NV12,
145 ];
146 for fmt in &fmts {
147 let fmt_str = fmt.as_str();
148 dbg!(fmt_str);
149 let fmt2 = std::str::FromStr::from_str(fmt_str).unwrap();
150 assert_eq!(fmt, &fmt2);
151 }
152}
153
154macro_rules! try_downcast {
155 ($name:ident, $orig:expr) => {{
156 if let Some(_) = <dyn std::any::Any>::downcast_ref::<std::marker::PhantomData<$name>>($orig)
157 {
158 return Ok(PixFmt::$name);
159 }
160 }};
161}
162
163impl<FMT> TryFrom<std::marker::PhantomData<FMT>> for PixFmt
164where
165 FMT: PixelFormat,
166{
167 type Error = &'static str;
168
169 fn try_from(orig: std::marker::PhantomData<FMT>) -> Result<PixFmt, Self::Error> {
170 try_downcast!(Mono8, &orig);
171 try_downcast!(Mono32f, &orig);
172 try_downcast!(RGB8, &orig);
173 try_downcast!(RGBA8, &orig);
174 try_downcast!(BayerRG8, &orig);
175 try_downcast!(BayerRG32f, &orig);
176 try_downcast!(BayerBG8, &orig);
177 try_downcast!(BayerBG32f, &orig);
178 try_downcast!(BayerGB8, &orig);
179 try_downcast!(BayerGB32f, &orig);
180 try_downcast!(BayerGR8, &orig);
181 try_downcast!(BayerGR32f, &orig);
182 try_downcast!(YUV444, &orig);
183 try_downcast!(YUV422, &orig);
184 try_downcast!(NV12, &orig);
185 Err("unknown PixelFormat implementation could not be converted to PixFmt")
186 }
187}
188
189#[inline]
191pub fn pixfmt<FMT: PixelFormat>() -> Result<PixFmt, &'static str> {
192 use std::convert::TryInto;
193 let concrete: std::marker::PhantomData<FMT> = std::marker::PhantomData;
194 concrete.try_into()
195}
196
197#[test]
198fn test_compile_runtime_roundtrip() {
199 macro_rules! gen_test {
200 ($name:ident) => {{
201 let x = PixFmt::$name;
202 let y = x.to_static::<$name>().unwrap();
203 let z = PixFmt::try_from(y).unwrap();
204 assert_eq!(x, z);
205 }};
206 }
207 gen_test!(Mono8);
208 gen_test!(Mono32f);
209 gen_test!(RGB8);
210 gen_test!(RGBA8);
211 gen_test!(BayerRG8);
212 gen_test!(BayerRG32f);
213 gen_test!(BayerBG8);
214 gen_test!(BayerBG32f);
215 gen_test!(BayerGB8);
216 gen_test!(BayerGB32f);
217 gen_test!(BayerGR8);
218 gen_test!(BayerGR32f);
219 gen_test!(YUV444);
220 gen_test!(YUV422);
221 gen_test!(NV12);
222}
223
224pub trait PixelFormat: std::any::Any + Clone {}
231
232macro_rules! define_pixel_format {
233 ($name:ident, $comment:literal) => {
234 #[doc = $comment]
235 #[derive(Clone, Debug)]
236 pub struct $name {}
237 impl PixelFormat for $name {}
238 };
239}
240
241define_pixel_format!(
242 Mono8,
243 "Luminance, 1 byte per pixel. Sometimes also called Gray8."
244);
245define_pixel_format!(
246 Mono32f,
247 "Luminance, 32 bytes per pixel, Little-Endian, IEEE-754"
248);
249
250define_pixel_format!(
251 RGB8,
252 "Red, Green, Blue, 1 byte each, total 3 bytes per pixel.
253
254Also sometimes called `RGB8packed`."
255);
256
257define_pixel_format!(
258 RGBA8,
259 "Red, Green, Blue, Alpha, 1 byte each, total 4 bytes per pixel."
260);
261
262define_pixel_format!(BayerRG8, "Bayer Red Green pattern, 1 byte per pixel.");
263define_pixel_format!(BayerRG32f, "Bayer Red Green pattern, 4 bytes per pixel.");
264define_pixel_format!(BayerBG8, "Bayer Blue Green pattern, 1 byte per pixel.");
265define_pixel_format!(BayerBG32f, "Bayer Blue Green pattern, 4 bytes per pixel.");
266define_pixel_format!(BayerGB8, "Bayer Green Blue pattern, 1 byte per pixel.");
267define_pixel_format!(BayerGB32f, "Bayer Green Blue pattern, 4 bytes per pixel.");
268define_pixel_format!(BayerGR8, "Bayer Green Red pattern, 1 byte per pixel.");
269define_pixel_format!(BayerGR32f, "Bayer Green Red pattern, 4 bytes per pixel.");
270define_pixel_format!(YUV444, "YUV 4:4:4 8-bit, total 3 bytes per pixel.");
271define_pixel_format!(YUV422, "YUV 4:2:2 8-bit, total 2 bytes per pixel.");
272define_pixel_format!(NV12, "NV12 format, average 12 bits per pixel");
273
274#[test]
275fn test_debug_types() {
276 let _ = format!("{:?}", BayerRG8 {});
277}