use edgefirst_tensor::DType;
use std::fmt;
pub trait ImagePixel: num_traits::Num + Clone + fmt::Debug + Send + Sync + 'static {
fn from_u8(v: u8) -> Self;
fn from_u16(v: u16) -> Self {
Self::from_u8((v >> 8) as u8)
}
fn dtype() -> DType;
}
impl ImagePixel for u8 {
#[inline]
fn from_u8(v: u8) -> Self {
v
}
#[inline]
fn from_u16(v: u16) -> Self {
(v >> 8) as u8
}
fn dtype() -> DType {
DType::U8
}
}
impl ImagePixel for u16 {
#[inline]
fn from_u8(v: u8) -> Self {
v as u16 * 257
}
#[inline]
fn from_u16(v: u16) -> Self {
v
}
fn dtype() -> DType {
DType::U16
}
}
impl ImagePixel for i8 {
#[inline]
fn from_u8(v: u8) -> Self {
(v ^ 0x80) as i8
}
#[inline]
fn from_u16(v: u16) -> Self {
Self::from_u8((v >> 8) as u8)
}
fn dtype() -> DType {
DType::I8
}
}
impl ImagePixel for i16 {
#[inline]
fn from_u8(v: u8) -> Self {
((v as u16 * 257) ^ 0x8000) as i16
}
#[inline]
fn from_u16(v: u16) -> Self {
(v ^ 0x8000) as i16
}
fn dtype() -> DType {
DType::I16
}
}
impl ImagePixel for f32 {
#[inline]
fn from_u8(v: u8) -> Self {
v as f32 / 255.0
}
#[inline]
fn from_u16(v: u16) -> Self {
v as f32 / 65535.0
}
fn dtype() -> DType {
DType::F32
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn u8_identity() {
assert_eq!(u8::from_u8(0), 0);
assert_eq!(u8::from_u8(128), 128);
assert_eq!(u8::from_u8(255), 255);
}
#[test]
fn u8_from_u16() {
assert_eq!(u8::from_u16(0), 0);
assert_eq!(u8::from_u16(32768), 128);
assert_eq!(u8::from_u16(65535), 255);
}
#[test]
fn u16_from_u8_scaling() {
assert_eq!(u16::from_u8(0), 0);
assert_eq!(u16::from_u8(1), 257);
assert_eq!(u16::from_u8(128), 32896);
assert_eq!(u16::from_u8(255), 65535);
}
#[test]
fn u16_identity() {
assert_eq!(u16::from_u16(0), 0);
assert_eq!(u16::from_u16(32768), 32768);
assert_eq!(u16::from_u16(65535), 65535);
}
#[test]
fn i8_xor_trick() {
assert_eq!(i8::from_u8(0), -128);
assert_eq!(i8::from_u8(128), 0);
assert_eq!(i8::from_u8(255), 127);
assert_eq!(i8::from_u8(1), -127);
assert_eq!(i8::from_u8(127), -1);
}
#[test]
fn i16_xor_trick() {
assert_eq!(i16::from_u8(0), -32768);
assert_eq!(i16::from_u8(128), 128); assert_eq!(i16::from_u8(255), 32767);
assert_eq!(i16::from_u16(0), -32768);
assert_eq!(i16::from_u16(32768), 0);
assert_eq!(i16::from_u16(65535), 32767);
}
#[test]
fn f32_normalised() {
assert!((f32::from_u8(0) - 0.0).abs() < f32::EPSILON);
assert!((f32::from_u8(255) - 1.0).abs() < f32::EPSILON);
assert!((f32::from_u8(128) - 128.0 / 255.0).abs() < f32::EPSILON);
}
#[test]
fn f32_from_u16_normalised() {
assert!((f32::from_u16(0) - 0.0).abs() < f32::EPSILON);
assert!((f32::from_u16(65535) - 1.0).abs() < 1e-5);
assert!((f32::from_u16(32768) - 32768.0 / 65535.0).abs() < 1e-5);
}
#[test]
fn dtype_matches() {
assert_eq!(u8::dtype(), DType::U8);
assert_eq!(u16::dtype(), DType::U16);
assert_eq!(i8::dtype(), DType::I8);
assert_eq!(i16::dtype(), DType::I16);
assert_eq!(f32::dtype(), DType::F32);
}
}