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