ff_format/pixel.rs
1//! Pixel format definitions for video processing.
2//!
3//! This module provides the [`PixelFormat`] enum which represents various
4//! pixel formats used in video processing. It supports both packed (RGB/BGRA)
5//! and planar (YUV) formats commonly used in video editing.
6//!
7//! # Examples
8//!
9//! ```
10//! use ff_format::PixelFormat;
11//!
12//! let format = PixelFormat::Yuv420p;
13//! assert!(format.is_planar());
14//! assert!(!format.is_packed());
15//! assert_eq!(format.num_planes(), 3);
16//!
17//! let rgba = PixelFormat::Rgba;
18//! assert!(rgba.has_alpha());
19//! assert_eq!(rgba.bits_per_pixel(), Some(32));
20//! ```
21
22use std::fmt;
23
24/// Pixel format for video frames.
25///
26/// This enum represents various pixel formats used in video processing.
27/// It is designed to cover the most common formats used in video editing
28/// while remaining extensible via the `Other` variant.
29///
30/// # Format Categories
31///
32/// - **Packed RGB**: Data stored contiguously (Rgb24, Rgba, Bgr24, Bgra)
33/// - **Planar YUV**: Separate planes for Y, U, V components (Yuv420p, Yuv422p, Yuv444p)
34/// - **Semi-planar**: Y plane + interleaved UV (Nv12, Nv21)
35/// - **High bit depth**: 10-bit formats for HDR content (Yuv420p10le, Yuv422p10le, Yuv444p10le, Yuva444p10le, P010le)
36#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
37#[non_exhaustive]
38pub enum PixelFormat {
39 // Packed RGB
40 /// 24-bit RGB (8:8:8) - 3 bytes per pixel
41 Rgb24,
42 /// 32-bit RGBA (8:8:8:8) - 4 bytes per pixel with alpha
43 Rgba,
44 /// 24-bit BGR (8:8:8) - 3 bytes per pixel, reversed channel order
45 Bgr24,
46 /// 32-bit BGRA (8:8:8:8) - 4 bytes per pixel with alpha, reversed channel order
47 Bgra,
48
49 // Planar YUV
50 /// YUV 4:2:0 planar - most common video format (H.264, etc.)
51 Yuv420p,
52 /// YUV 4:2:2 planar - higher chroma resolution
53 Yuv422p,
54 /// YUV 4:4:4 planar - full chroma resolution
55 Yuv444p,
56
57 // Semi-planar (NV12/NV21)
58 /// Y plane + interleaved UV - common in hardware decoders
59 Nv12,
60 /// Y plane + interleaved VU - Android camera format
61 Nv21,
62
63 // High bit depth
64 /// 10-bit YUV 4:2:0 planar - HDR content
65 Yuv420p10le,
66 /// 10-bit YUV 4:2:2 planar - `ProRes` 422 profiles
67 Yuv422p10le,
68 /// 10-bit YUV 4:4:4 planar - `ProRes` 4444 (no alpha)
69 Yuv444p10le,
70 /// 10-bit YUVA 4:4:4 planar with alpha - `ProRes` 4444 with alpha
71 Yuva444p10le,
72 /// 10-bit semi-planar NV12 - HDR hardware decoding
73 P010le,
74
75 // Grayscale
76 /// 8-bit grayscale
77 Gray8,
78
79 // Float formats
80 /// 32-bit float planar GBR — native output of the `OpenEXR` decoder
81 Gbrpf32le,
82
83 // Extensibility
84 /// Unknown or unsupported format with `FFmpeg`'s `AVPixelFormat` value
85 Other(u32),
86}
87
88impl PixelFormat {
89 /// Returns the format name as a human-readable string.
90 ///
91 /// # Examples
92 ///
93 /// ```
94 /// use ff_format::PixelFormat;
95 ///
96 /// assert_eq!(PixelFormat::Yuv420p.name(), "yuv420p");
97 /// assert_eq!(PixelFormat::Rgba.name(), "rgba");
98 /// ```
99 #[must_use]
100 pub const fn name(&self) -> &'static str {
101 match self {
102 Self::Rgb24 => "rgb24",
103 Self::Rgba => "rgba",
104 Self::Bgr24 => "bgr24",
105 Self::Bgra => "bgra",
106 Self::Yuv420p => "yuv420p",
107 Self::Yuv422p => "yuv422p",
108 Self::Yuv444p => "yuv444p",
109 Self::Nv12 => "nv12",
110 Self::Nv21 => "nv21",
111 Self::Yuv420p10le => "yuv420p10le",
112 Self::Yuv422p10le => "yuv422p10le",
113 Self::Yuv444p10le => "yuv444p10le",
114 Self::Yuva444p10le => "yuva444p10le",
115 Self::P010le => "p010le",
116 Self::Gray8 => "gray8",
117 Self::Gbrpf32le => "gbrpf32le",
118 Self::Other(_) => "unknown",
119 }
120 }
121
122 /// Returns the number of planes for this format.
123 ///
124 /// - Packed formats (RGB, RGBA, etc.) have 1 plane
125 /// - Planar YUV formats have 3 planes (Y, U, V)
126 /// - Semi-planar formats (NV12, NV21) have 2 planes (Y, UV)
127 /// - Grayscale has 1 plane
128 ///
129 /// # Examples
130 ///
131 /// ```
132 /// use ff_format::PixelFormat;
133 ///
134 /// assert_eq!(PixelFormat::Rgba.num_planes(), 1);
135 /// assert_eq!(PixelFormat::Yuv420p.num_planes(), 3);
136 /// assert_eq!(PixelFormat::Nv12.num_planes(), 2);
137 /// ```
138 #[must_use]
139 pub const fn num_planes(&self) -> usize {
140 match self {
141 // Planar YUV - Y, U, V planes (and YUVA with alpha as 4th plane)
142 Self::Yuv420p
143 | Self::Yuv422p
144 | Self::Yuv444p
145 | Self::Yuv420p10le
146 | Self::Yuv422p10le
147 | Self::Yuv444p10le
148 | Self::Gbrpf32le => 3,
149 Self::Yuva444p10le => 4,
150 // Semi-planar - Y plane + interleaved UV plane
151 Self::Nv12 | Self::Nv21 | Self::P010le => 2,
152 // Packed formats and unknown - single plane
153 Self::Rgb24 | Self::Rgba | Self::Bgr24 | Self::Bgra | Self::Gray8 | Self::Other(_) => 1,
154 }
155 }
156
157 /// Alias for [`num_planes`](Self::num_planes) for API compatibility.
158 ///
159 /// # Examples
160 ///
161 /// ```
162 /// use ff_format::PixelFormat;
163 ///
164 /// assert_eq!(PixelFormat::Yuv420p.plane_count(), 3);
165 /// ```
166 #[must_use]
167 #[inline]
168 pub const fn plane_count(&self) -> usize {
169 self.num_planes()
170 }
171
172 /// Returns `true` if this is a packed format (single plane with interleaved components).
173 ///
174 /// Packed formats store all color components contiguously in memory,
175 /// making them suitable for direct rendering but less efficient for
176 /// video compression.
177 ///
178 /// # Examples
179 ///
180 /// ```
181 /// use ff_format::PixelFormat;
182 ///
183 /// assert!(PixelFormat::Rgba.is_packed());
184 /// assert!(!PixelFormat::Yuv420p.is_packed());
185 /// ```
186 #[must_use]
187 pub const fn is_packed(&self) -> bool {
188 matches!(
189 self,
190 Self::Rgb24 | Self::Rgba | Self::Bgr24 | Self::Bgra | Self::Gray8
191 )
192 }
193
194 /// Returns `true` if this is a planar format (separate planes for each component).
195 ///
196 /// Planar formats store each color component in a separate memory region,
197 /// which is more efficient for video codecs and some GPU operations.
198 ///
199 /// Note: Semi-planar formats (NV12, NV21, P010le) are considered planar
200 /// as they have multiple planes, even though UV is interleaved.
201 ///
202 /// # Examples
203 ///
204 /// ```
205 /// use ff_format::PixelFormat;
206 ///
207 /// assert!(PixelFormat::Yuv420p.is_planar());
208 /// assert!(PixelFormat::Nv12.is_planar()); // Semi-planar is also planar
209 /// assert!(!PixelFormat::Rgba.is_planar());
210 /// ```
211 #[must_use]
212 pub const fn is_planar(&self) -> bool {
213 !self.is_packed()
214 }
215
216 /// Returns `true` if this format has an alpha (transparency) channel.
217 ///
218 /// # Examples
219 ///
220 /// ```
221 /// use ff_format::PixelFormat;
222 ///
223 /// assert!(PixelFormat::Rgba.has_alpha());
224 /// assert!(PixelFormat::Bgra.has_alpha());
225 /// assert!(!PixelFormat::Rgb24.has_alpha());
226 /// assert!(!PixelFormat::Yuv420p.has_alpha());
227 /// ```
228 #[must_use]
229 pub const fn has_alpha(&self) -> bool {
230 matches!(self, Self::Rgba | Self::Bgra | Self::Yuva444p10le)
231 }
232
233 /// Returns `true` if this is an RGB-based format.
234 ///
235 /// # Examples
236 ///
237 /// ```
238 /// use ff_format::PixelFormat;
239 ///
240 /// assert!(PixelFormat::Rgb24.is_rgb());
241 /// assert!(PixelFormat::Rgba.is_rgb());
242 /// assert!(PixelFormat::Bgra.is_rgb()); // BGR is still RGB family
243 /// assert!(!PixelFormat::Yuv420p.is_rgb());
244 /// ```
245 #[must_use]
246 pub const fn is_rgb(&self) -> bool {
247 matches!(
248 self,
249 Self::Rgb24 | Self::Rgba | Self::Bgr24 | Self::Bgra | Self::Gbrpf32le
250 )
251 }
252
253 /// Returns `true` if this is a YUV-based format.
254 ///
255 /// # Examples
256 ///
257 /// ```
258 /// use ff_format::PixelFormat;
259 ///
260 /// assert!(PixelFormat::Yuv420p.is_yuv());
261 /// assert!(PixelFormat::Nv12.is_yuv());
262 /// assert!(!PixelFormat::Rgba.is_yuv());
263 /// ```
264 #[must_use]
265 pub const fn is_yuv(&self) -> bool {
266 matches!(
267 self,
268 Self::Yuv420p
269 | Self::Yuv422p
270 | Self::Yuv444p
271 | Self::Nv12
272 | Self::Nv21
273 | Self::Yuv420p10le
274 | Self::Yuv422p10le
275 | Self::Yuv444p10le
276 | Self::Yuva444p10le
277 | Self::P010le
278 )
279 }
280
281 /// Returns the bits per pixel for packed formats.
282 ///
283 /// For planar formats, this returns `None` because the concept of
284 /// "bits per pixel" doesn't apply directly - use [`bytes_per_pixel`](Self::bytes_per_pixel)
285 /// to get the average bytes per pixel instead.
286 ///
287 /// # Examples
288 ///
289 /// ```
290 /// use ff_format::PixelFormat;
291 ///
292 /// assert_eq!(PixelFormat::Rgb24.bits_per_pixel(), Some(24));
293 /// assert_eq!(PixelFormat::Rgba.bits_per_pixel(), Some(32));
294 /// assert_eq!(PixelFormat::Yuv420p.bits_per_pixel(), None);
295 /// ```
296 #[must_use]
297 pub const fn bits_per_pixel(&self) -> Option<usize> {
298 match self {
299 Self::Rgb24 | Self::Bgr24 => Some(24),
300 Self::Rgba | Self::Bgra => Some(32),
301 Self::Gray8 => Some(8),
302 // Planar formats don't have a simple bits-per-pixel value
303 _ => None,
304 }
305 }
306
307 /// Returns the average bytes per pixel.
308 ///
309 /// For packed formats, this is exact. For planar YUV formats, this
310 /// returns the average considering subsampling:
311 /// - YUV 4:2:0: 1.5 bytes/pixel (12 bits)
312 /// - YUV 4:2:2: 2 bytes/pixel (16 bits)
313 /// - YUV 4:4:4: 3 bytes/pixel (24 bits)
314 ///
315 /// Note: For formats with non-integer bytes per pixel (like `Yuv420p`),
316 /// this rounds up to the nearest byte.
317 ///
318 /// # Examples
319 ///
320 /// ```
321 /// use ff_format::PixelFormat;
322 ///
323 /// assert_eq!(PixelFormat::Rgba.bytes_per_pixel(), 4);
324 /// assert_eq!(PixelFormat::Rgb24.bytes_per_pixel(), 3);
325 /// assert_eq!(PixelFormat::Yuv420p.bytes_per_pixel(), 2); // Actually 1.5, rounded up
326 /// assert_eq!(PixelFormat::Yuv444p.bytes_per_pixel(), 3);
327 /// ```
328 #[must_use]
329 pub const fn bytes_per_pixel(&self) -> usize {
330 match self {
331 // Grayscale - 1 byte per pixel
332 Self::Gray8 => 1,
333
334 // YUV 4:2:0 (8-bit and 10-bit) and YUV 4:2:2 - average ~2 bytes per pixel
335 Self::Yuv420p
336 | Self::Nv12
337 | Self::Nv21
338 | Self::Yuv420p10le
339 | Self::P010le
340 | Self::Yuv422p
341 | Self::Yuv422p10le => 2,
342
343 // RGB24/BGR24 and YUV 4:4:4 (8-bit and 10-bit) - 3 bytes per pixel
344 Self::Rgb24 | Self::Bgr24 | Self::Yuv444p | Self::Yuv444p10le => 3,
345
346 // 32-bit float planar GBR - 12 bytes per pixel (3 channels × 4 bytes)
347 Self::Gbrpf32le => 12,
348
349 // RGBA/BGRA, YUVA 4:4:4 with alpha, and unknown formats - 4 bytes per pixel
350 Self::Yuva444p10le | Self::Rgba | Self::Bgra | Self::Other(_) => 4,
351 }
352 }
353
354 /// Returns `true` if this is a high bit depth format (> 8 bits per component).
355 ///
356 /// # Examples
357 ///
358 /// ```
359 /// use ff_format::PixelFormat;
360 ///
361 /// assert!(PixelFormat::Yuv420p10le.is_high_bit_depth());
362 /// assert!(PixelFormat::P010le.is_high_bit_depth());
363 /// assert!(!PixelFormat::Yuv420p.is_high_bit_depth());
364 /// ```
365 #[must_use]
366 pub const fn is_high_bit_depth(&self) -> bool {
367 matches!(
368 self,
369 Self::Yuv420p10le
370 | Self::Yuv422p10le
371 | Self::Yuv444p10le
372 | Self::Yuva444p10le
373 | Self::P010le
374 | Self::Gbrpf32le
375 )
376 }
377
378 /// Returns the bit depth per component.
379 ///
380 /// Most formats use 8 bits per component, while high bit depth
381 /// formats use 10 bits.
382 ///
383 /// # Examples
384 ///
385 /// ```
386 /// use ff_format::PixelFormat;
387 ///
388 /// assert_eq!(PixelFormat::Rgba.bit_depth(), 8);
389 /// assert_eq!(PixelFormat::Yuv420p10le.bit_depth(), 10);
390 /// ```
391 #[must_use]
392 pub const fn bit_depth(&self) -> usize {
393 match self {
394 Self::Yuv420p10le
395 | Self::Yuv422p10le
396 | Self::Yuv444p10le
397 | Self::Yuva444p10le
398 | Self::P010le => 10,
399 Self::Gbrpf32le => 32,
400 // All other formats including unknown are 8-bit
401 _ => 8,
402 }
403 }
404}
405
406impl fmt::Display for PixelFormat {
407 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
408 write!(f, "{}", self.name())
409 }
410}
411
412impl Default for PixelFormat {
413 /// Returns the default pixel format.
414 ///
415 /// The default is [`PixelFormat::Yuv420p`] as it's the most common
416 /// format used in video encoding.
417 fn default() -> Self {
418 Self::Yuv420p
419 }
420}
421
422#[cfg(test)]
423mod tests {
424 use super::*;
425
426 #[test]
427 fn test_format_names() {
428 assert_eq!(PixelFormat::Rgb24.name(), "rgb24");
429 assert_eq!(PixelFormat::Rgba.name(), "rgba");
430 assert_eq!(PixelFormat::Bgr24.name(), "bgr24");
431 assert_eq!(PixelFormat::Bgra.name(), "bgra");
432 assert_eq!(PixelFormat::Yuv420p.name(), "yuv420p");
433 assert_eq!(PixelFormat::Yuv422p.name(), "yuv422p");
434 assert_eq!(PixelFormat::Yuv444p.name(), "yuv444p");
435 assert_eq!(PixelFormat::Nv12.name(), "nv12");
436 assert_eq!(PixelFormat::Nv21.name(), "nv21");
437 assert_eq!(PixelFormat::Yuv420p10le.name(), "yuv420p10le");
438 assert_eq!(PixelFormat::P010le.name(), "p010le");
439 assert_eq!(PixelFormat::Gray8.name(), "gray8");
440 assert_eq!(PixelFormat::Other(999).name(), "unknown");
441 }
442
443 #[test]
444 fn test_plane_count() {
445 // Packed formats - 1 plane
446 assert_eq!(PixelFormat::Rgb24.num_planes(), 1);
447 assert_eq!(PixelFormat::Rgba.num_planes(), 1);
448 assert_eq!(PixelFormat::Bgr24.num_planes(), 1);
449 assert_eq!(PixelFormat::Bgra.num_planes(), 1);
450 assert_eq!(PixelFormat::Gray8.num_planes(), 1);
451
452 // Planar YUV - 3 planes
453 assert_eq!(PixelFormat::Yuv420p.num_planes(), 3);
454 assert_eq!(PixelFormat::Yuv422p.num_planes(), 3);
455 assert_eq!(PixelFormat::Yuv444p.num_planes(), 3);
456 assert_eq!(PixelFormat::Yuv420p10le.num_planes(), 3);
457
458 // Semi-planar - 2 planes
459 assert_eq!(PixelFormat::Nv12.num_planes(), 2);
460 assert_eq!(PixelFormat::Nv21.num_planes(), 2);
461 assert_eq!(PixelFormat::P010le.num_planes(), 2);
462
463 // plane_count is alias for num_planes
464 assert_eq!(PixelFormat::Yuv420p.plane_count(), 3);
465 }
466
467 #[test]
468 fn test_packed_vs_planar() {
469 // Packed formats
470 assert!(PixelFormat::Rgb24.is_packed());
471 assert!(PixelFormat::Rgba.is_packed());
472 assert!(PixelFormat::Bgr24.is_packed());
473 assert!(PixelFormat::Bgra.is_packed());
474 assert!(PixelFormat::Gray8.is_packed());
475 assert!(!PixelFormat::Rgb24.is_planar());
476
477 // Planar formats
478 assert!(PixelFormat::Yuv420p.is_planar());
479 assert!(PixelFormat::Yuv422p.is_planar());
480 assert!(PixelFormat::Yuv444p.is_planar());
481 assert!(PixelFormat::Nv12.is_planar());
482 assert!(PixelFormat::Nv21.is_planar());
483 assert!(!PixelFormat::Yuv420p.is_packed());
484 }
485
486 #[test]
487 fn test_has_alpha() {
488 assert!(PixelFormat::Rgba.has_alpha());
489 assert!(PixelFormat::Bgra.has_alpha());
490 assert!(!PixelFormat::Rgb24.has_alpha());
491 assert!(!PixelFormat::Bgr24.has_alpha());
492 assert!(!PixelFormat::Yuv420p.has_alpha());
493 assert!(!PixelFormat::Gray8.has_alpha());
494 }
495
496 #[test]
497 fn test_is_rgb() {
498 assert!(PixelFormat::Rgb24.is_rgb());
499 assert!(PixelFormat::Rgba.is_rgb());
500 assert!(PixelFormat::Bgr24.is_rgb());
501 assert!(PixelFormat::Bgra.is_rgb());
502 assert!(!PixelFormat::Yuv420p.is_rgb());
503 assert!(!PixelFormat::Nv12.is_rgb());
504 assert!(!PixelFormat::Gray8.is_rgb());
505 }
506
507 #[test]
508 fn test_is_yuv() {
509 assert!(PixelFormat::Yuv420p.is_yuv());
510 assert!(PixelFormat::Yuv422p.is_yuv());
511 assert!(PixelFormat::Yuv444p.is_yuv());
512 assert!(PixelFormat::Nv12.is_yuv());
513 assert!(PixelFormat::Nv21.is_yuv());
514 assert!(PixelFormat::Yuv420p10le.is_yuv());
515 assert!(PixelFormat::P010le.is_yuv());
516 assert!(!PixelFormat::Rgb24.is_yuv());
517 assert!(!PixelFormat::Rgba.is_yuv());
518 assert!(!PixelFormat::Gray8.is_yuv());
519 }
520
521 #[test]
522 fn test_bits_per_pixel() {
523 // Packed formats have defined bits per pixel
524 assert_eq!(PixelFormat::Rgb24.bits_per_pixel(), Some(24));
525 assert_eq!(PixelFormat::Bgr24.bits_per_pixel(), Some(24));
526 assert_eq!(PixelFormat::Rgba.bits_per_pixel(), Some(32));
527 assert_eq!(PixelFormat::Bgra.bits_per_pixel(), Some(32));
528 assert_eq!(PixelFormat::Gray8.bits_per_pixel(), Some(8));
529
530 // Planar formats don't have simple bits per pixel
531 assert_eq!(PixelFormat::Yuv420p.bits_per_pixel(), None);
532 assert_eq!(PixelFormat::Nv12.bits_per_pixel(), None);
533 }
534
535 #[test]
536 fn test_bytes_per_pixel() {
537 // Packed formats
538 assert_eq!(PixelFormat::Rgb24.bytes_per_pixel(), 3);
539 assert_eq!(PixelFormat::Bgr24.bytes_per_pixel(), 3);
540 assert_eq!(PixelFormat::Rgba.bytes_per_pixel(), 4);
541 assert_eq!(PixelFormat::Bgra.bytes_per_pixel(), 4);
542 assert_eq!(PixelFormat::Gray8.bytes_per_pixel(), 1);
543
544 // YUV 4:2:0 - 1.5 bytes average, rounded to 2
545 assert_eq!(PixelFormat::Yuv420p.bytes_per_pixel(), 2);
546 assert_eq!(PixelFormat::Nv12.bytes_per_pixel(), 2);
547 assert_eq!(PixelFormat::Nv21.bytes_per_pixel(), 2);
548
549 // YUV 4:2:2 - 2 bytes
550 assert_eq!(PixelFormat::Yuv422p.bytes_per_pixel(), 2);
551
552 // YUV 4:4:4 - 3 bytes
553 assert_eq!(PixelFormat::Yuv444p.bytes_per_pixel(), 3);
554
555 // High bit depth
556 assert_eq!(PixelFormat::Yuv420p10le.bytes_per_pixel(), 2);
557 assert_eq!(PixelFormat::P010le.bytes_per_pixel(), 2);
558 }
559
560 #[test]
561 fn test_high_bit_depth() {
562 assert!(PixelFormat::Yuv420p10le.is_high_bit_depth());
563 assert!(PixelFormat::P010le.is_high_bit_depth());
564 assert!(!PixelFormat::Yuv420p.is_high_bit_depth());
565 assert!(!PixelFormat::Rgba.is_high_bit_depth());
566 }
567
568 #[test]
569 fn test_bit_depth() {
570 assert_eq!(PixelFormat::Rgba.bit_depth(), 8);
571 assert_eq!(PixelFormat::Yuv420p.bit_depth(), 8);
572 assert_eq!(PixelFormat::Yuv420p10le.bit_depth(), 10);
573 assert_eq!(PixelFormat::P010le.bit_depth(), 10);
574 }
575
576 #[test]
577 fn test_display() {
578 assert_eq!(format!("{}", PixelFormat::Yuv420p), "yuv420p");
579 assert_eq!(format!("{}", PixelFormat::Rgba), "rgba");
580 assert_eq!(format!("{}", PixelFormat::Other(123)), "unknown");
581 }
582
583 #[test]
584 fn test_default() {
585 assert_eq!(PixelFormat::default(), PixelFormat::Yuv420p);
586 }
587
588 #[test]
589 fn test_debug() {
590 assert_eq!(format!("{:?}", PixelFormat::Rgba), "Rgba");
591 assert_eq!(format!("{:?}", PixelFormat::Yuv420p), "Yuv420p");
592 assert_eq!(format!("{:?}", PixelFormat::Other(42)), "Other(42)");
593 }
594
595 #[test]
596 fn test_equality_and_hash() {
597 use std::collections::HashSet;
598
599 assert_eq!(PixelFormat::Rgba, PixelFormat::Rgba);
600 assert_ne!(PixelFormat::Rgba, PixelFormat::Bgra);
601 assert_eq!(PixelFormat::Other(1), PixelFormat::Other(1));
602 assert_ne!(PixelFormat::Other(1), PixelFormat::Other(2));
603
604 // Test Hash implementation
605 let mut set = HashSet::new();
606 set.insert(PixelFormat::Rgba);
607 set.insert(PixelFormat::Yuv420p);
608 assert!(set.contains(&PixelFormat::Rgba));
609 assert!(!set.contains(&PixelFormat::Bgra));
610 }
611
612 #[test]
613 fn test_copy() {
614 let format = PixelFormat::Yuv420p;
615 let copied = format;
616 // Both original and copy are still usable (Copy semantics)
617 assert_eq!(format, copied);
618 assert_eq!(format.name(), copied.name());
619 }
620
621 #[test]
622 fn gbrpf32le_name_should_return_gbrpf32le() {
623 assert_eq!(PixelFormat::Gbrpf32le.name(), "gbrpf32le");
624 }
625
626 #[test]
627 fn gbrpf32le_should_have_three_planes() {
628 assert_eq!(PixelFormat::Gbrpf32le.num_planes(), 3);
629 assert_eq!(PixelFormat::Gbrpf32le.plane_count(), 3);
630 }
631
632 #[test]
633 fn gbrpf32le_should_be_planar_not_packed() {
634 assert!(!PixelFormat::Gbrpf32le.is_packed());
635 assert!(PixelFormat::Gbrpf32le.is_planar());
636 }
637
638 #[test]
639 fn gbrpf32le_should_be_rgb_family() {
640 assert!(PixelFormat::Gbrpf32le.is_rgb());
641 assert!(!PixelFormat::Gbrpf32le.is_yuv());
642 }
643
644 #[test]
645 fn gbrpf32le_should_not_have_alpha() {
646 assert!(!PixelFormat::Gbrpf32le.has_alpha());
647 }
648
649 #[test]
650 fn gbrpf32le_should_have_twelve_bytes_per_pixel() {
651 assert_eq!(PixelFormat::Gbrpf32le.bytes_per_pixel(), 12);
652 }
653
654 #[test]
655 fn gbrpf32le_should_be_high_bit_depth() {
656 assert!(PixelFormat::Gbrpf32le.is_high_bit_depth());
657 }
658
659 #[test]
660 fn gbrpf32le_should_have_bit_depth_32() {
661 assert_eq!(PixelFormat::Gbrpf32le.bit_depth(), 32);
662 }
663
664 #[test]
665 fn gbrpf32le_bits_per_pixel_should_be_none() {
666 assert_eq!(PixelFormat::Gbrpf32le.bits_per_pixel(), None);
667 }
668}