1use edgefirst_tensor::DType;
11
12pub trait ImagePixel: edgefirst_tensor::Element {
37 fn from_u8(v: u8) -> Self;
39
40 fn from_u16(v: u16) -> Self {
45 Self::from_u8((v >> 8) as u8)
46 }
47
48 fn dtype() -> DType;
50}
51
52impl ImagePixel for u8 {
53 #[inline]
54 fn from_u8(v: u8) -> Self {
55 v
56 }
57
58 #[inline]
59 fn from_u16(v: u16) -> Self {
60 (v >> 8) as u8
61 }
62
63 fn dtype() -> DType {
64 DType::U8
65 }
66}
67
68impl ImagePixel for u16 {
69 #[inline]
70 fn from_u8(v: u8) -> Self {
71 v as u16 * 257
73 }
74
75 #[inline]
76 fn from_u16(v: u16) -> Self {
77 v
78 }
79
80 fn dtype() -> DType {
81 DType::U16
82 }
83}
84
85impl ImagePixel for i8 {
86 #[inline]
87 fn from_u8(v: u8) -> Self {
88 (v ^ 0x80) as i8
90 }
91
92 #[inline]
93 fn from_u16(v: u16) -> Self {
94 Self::from_u8((v >> 8) as u8)
95 }
96
97 fn dtype() -> DType {
98 DType::I8
99 }
100}
101
102impl ImagePixel for i16 {
103 #[inline]
104 fn from_u8(v: u8) -> Self {
105 ((v as u16 * 257) ^ 0x8000) as i16
107 }
108
109 #[inline]
110 fn from_u16(v: u16) -> Self {
111 (v ^ 0x8000) as i16
113 }
114
115 fn dtype() -> DType {
116 DType::I16
117 }
118}
119
120impl ImagePixel for f32 {
121 #[inline]
122 fn from_u8(v: u8) -> Self {
123 v as f32 / 255.0
124 }
125
126 #[inline]
127 fn from_u16(v: u16) -> Self {
128 v as f32 / 65535.0
129 }
130
131 fn dtype() -> DType {
132 DType::F32
133 }
134}
135
136#[cfg(test)]
137mod tests {
138 use super::*;
139
140 #[test]
141 fn u8_identity() {
142 assert_eq!(u8::from_u8(0), 0);
143 assert_eq!(u8::from_u8(128), 128);
144 assert_eq!(u8::from_u8(255), 255);
145 }
146
147 #[test]
148 fn u8_from_u16() {
149 assert_eq!(u8::from_u16(0), 0);
150 assert_eq!(u8::from_u16(32768), 128);
151 assert_eq!(u8::from_u16(65535), 255);
152 }
153
154 #[test]
155 fn u16_from_u8_scaling() {
156 assert_eq!(u16::from_u8(0), 0);
157 assert_eq!(u16::from_u8(1), 257);
158 assert_eq!(u16::from_u8(128), 32896);
159 assert_eq!(u16::from_u8(255), 65535);
160 }
161
162 #[test]
163 fn u16_identity() {
164 assert_eq!(u16::from_u16(0), 0);
165 assert_eq!(u16::from_u16(32768), 32768);
166 assert_eq!(u16::from_u16(65535), 65535);
167 }
168
169 #[test]
170 fn i8_xor_trick() {
171 assert_eq!(i8::from_u8(0), -128);
173 assert_eq!(i8::from_u8(128), 0);
174 assert_eq!(i8::from_u8(255), 127);
175 assert_eq!(i8::from_u8(1), -127);
176 assert_eq!(i8::from_u8(127), -1);
177 }
178
179 #[test]
180 fn i16_xor_trick() {
181 assert_eq!(i16::from_u8(0), -32768);
183 assert_eq!(i16::from_u8(128), 128); assert_eq!(i16::from_u8(255), 32767);
185
186 assert_eq!(i16::from_u16(0), -32768);
188 assert_eq!(i16::from_u16(32768), 0);
189 assert_eq!(i16::from_u16(65535), 32767);
190 }
191
192 #[test]
193 fn f32_normalised() {
194 assert!((f32::from_u8(0) - 0.0).abs() < f32::EPSILON);
195 assert!((f32::from_u8(255) - 1.0).abs() < f32::EPSILON);
196 assert!((f32::from_u8(128) - 128.0 / 255.0).abs() < f32::EPSILON);
197 }
198
199 #[test]
200 fn f32_from_u16_normalised() {
201 assert!((f32::from_u16(0) - 0.0).abs() < f32::EPSILON);
202 assert!((f32::from_u16(65535) - 1.0).abs() < 1e-5);
203 assert!((f32::from_u16(32768) - 32768.0 / 65535.0).abs() < 1e-5);
204 }
205
206 #[test]
207 fn dtype_matches() {
208 assert_eq!(u8::dtype(), DType::U8);
209 assert_eq!(u16::dtype(), DType::U16);
210 assert_eq!(i8::dtype(), DType::I8);
211 assert_eq!(i16::dtype(), DType::I16);
212 assert_eq!(f32::dtype(), DType::F32);
213 }
214}