zune_core/bit_depth.rs
1/*
2 * Copyright (c) 2023.
3 *
4 * This software is free software;
5 *
6 * You can redistribute it or modify it under terms of the MIT, Apache License or Zlib license
7 */
8
9//! Image bit depth, information and manipulations
10
11use core::cmp::Ordering;
12
13/// The image bit depth.
14///
15/// The library successfully supports depths up to
16/// 16 bits, as the underlying storage is usually a `u16`.
17///
18/// This allows us to comfortably support a wide variety of images
19/// e.g 10 bit av1, 16 bit png and ppm.
20#[derive(Copy, Clone, Debug, Eq, PartialEq,Default)]
21#[non_exhaustive]
22pub enum BitDepth {
23 /// U8 bit depth.
24 ///
25 /// Images with such bit depth use [`u8`] to store
26 /// pixels and use the whole range from 0-255.
27 ///
28 /// It is currently the smallest supported bit depth
29 /// by the library.
30 ///
31 /// For images with bit depths lower than this, they will be scaled
32 /// to this bit depth
33 Eight,
34 /// U16 bit depth
35 ///
36 /// Images with such bit depths use [`u16`] to store values and use the whole range
37 /// i.e 0-65535
38 ///
39 /// Data is stored and processed in native endian.
40 Sixteen,
41 /// Floating point 32 bit data, range is 0.0 to 1.0
42 ///
43 /// Uses f32 to store data
44 Float32,
45 /// Bit depth information is unknown
46 #[default]
47 Unknown,
48}
49
50/// The underlying bit representation of the image
51///
52/// This represents the minimum rust type that
53/// can be used to represent image data, required
54/// by `Channel` struct in zune-image
55#[derive(Copy, Clone, Debug, Eq, PartialEq)]
56#[non_exhaustive]
57pub enum BitType {
58 /// Images represented using a [`u8`] as their
59 /// underlying pixel storage
60 U8,
61 /// Images represented using a [`u16`] as their
62 /// underlying pixel storage.
63 U16,
64 /// Images represented using a [`f32`] as their
65 /// underlying pixel storage
66 F32,
67}
68
69impl BitType {
70 /// Return the equivalent of the image bit type's depth
71 pub fn to_depth(self) -> BitDepth {
72 match self {
73 BitType::U8 => BitDepth::Eight,
74 BitType::U16 => BitDepth::Sixteen,
75 BitType::F32 => BitDepth::Float32,
76 }
77 }
78}
79
80
81impl core::cmp::PartialOrd for BitType {
82 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
83 Some(self.cmp(other))
84 }
85}
86impl core::cmp::Ord for BitType {
87 fn cmp(&self, other: &Self) -> Ordering {
88 if self == other {
89 core::cmp::Ordering::Equal
90 } else if *self == BitType::U8 {
91 // this did not match with the other bit
92 // type so it must be the smaller one
93 // eg Depth u8, depth u16
94 core::cmp::Ordering::Less
95 } else if *self == BitType::U16 && *other == BitType::F32 {
96 core::cmp::Ordering::Less
97 } else if *self == BitType::F32 {
98 core::cmp::Ordering::Greater
99 } else {
100 unreachable!()
101 }
102 }
103}
104impl BitDepth {
105 /// Get the max value supported by the bit depth
106 ///
107 /// During conversion from one bit depth to another
108 ///
109 /// larger values should be clamped to this bit depth
110 #[rustfmt::skip]
111 #[allow(clippy::zero_prefixed_literal)]
112 pub const fn max_value(self) -> u16
113 {
114 match self
115 {
116 Self::Eight => (1 << 08) - 1,
117 Self::Sixteen => u16::MAX,
118 Self::Float32 => 1,
119 Self::Unknown => 0,
120 }
121 }
122
123 /// Return the minimum number of bits that can be used to represent
124 /// each pixel in the image
125 ///
126 /// All bit depths below 8 return a bit type of `BitType::U8`.
127 /// and all those above 8 and below 16 return a bit type of `BitType::SixTeen`
128 ///
129 /// # Returns
130 /// An enum whose variants represent the minimum size for an unsigned integer
131 /// which can store the image pixels without overflow
132 ///
133 /// # Example
134 ///
135 /// ```
136 /// use zune_core::bit_depth::{BitDepth, BitType};
137 /// assert_eq!(BitDepth::Eight.bit_type(),BitType::U8);
138 ///
139 /// assert_eq!(BitDepth::Sixteen.bit_type(),BitType::U16);
140 /// ```
141 ///
142 /// See also [size_of](BitDepth::size_of)
143 pub const fn bit_type(self) -> BitType {
144 match self {
145 Self::Eight => BitType::U8,
146 Self::Sixteen => BitType::U16,
147 Self::Float32 => BitType::F32,
148 Self::Unknown => panic!("Unknown bit type"),
149 }
150 }
151 /// Get the number of bytes needed to store a specific bit depth
152 ///
153 ///
154 /// # Example
155 /// For images less than or equal to 8 bits(1 byte), we can use a [`u8`] to store
156 /// the pixels, and a size_of [`u8`] is 1
157 ///
158 /// For images greater than 8 bits and less than 16 bits(2 bytes), we can use a [`u16`] to
159 /// store the pixels, a size_of [`u16`] is 2.
160 /// ```
161 /// use zune_core::bit_depth::BitDepth;
162 /// let depth = BitDepth::Sixteen;
163 /// // greater 12 bits is greater than 8 and less than 16
164 /// assert_eq!(depth.size_of(),2);
165 /// ```
166 pub const fn size_of(self) -> usize {
167 match self {
168 Self::Eight => core::mem::size_of::<u8>(),
169 Self::Sixteen => core::mem::size_of::<u16>(),
170 Self::Float32 => core::mem::size_of::<f32>(),
171 Self::Unknown => panic!("Unknown bit type"),
172 }
173 }
174 pub const fn bit_size(&self) -> usize {
175 self.size_of() * 8
176 }
177}
178
179/// Byte endianness of returned samples
180/// this is useful when the decoder returns samples which span more
181/// than one byte yet the type returned is `&[u8]`
182///
183/// This helps you interpret how those bytes should be reconstructed
184/// to a higher order type
185#[derive(Copy, Clone, Debug, Eq, PartialEq)]
186pub enum ByteEndian {
187 /// Little Endian byte-order
188 LE,
189 /// Big Endian byte-order
190 BE,
191}