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