Skip to content

Commit

Permalink
Use enlargeable types in to_luma functions.
Browse files Browse the repository at this point in the history
This is an attempt to fix image-rs#1214, using the `Enlargeable` trait to
select a suitable type for the calculation in `rgb_to_luma` and
`bgr_to_luma`.

Integer pixel types will use suitable integer pixel types for the
calculation, while floating point pixel types will use floating point
types.

This PR also provides the `Enlargeable` trait for all `Primitive`
types (luckily, `Primitive` is not implemented for 128 bit numeric
types).
  • Loading branch information
kaj committed May 11, 2020
1 parent 514d1ae commit d27bcdb
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 13 deletions.
19 changes: 10 additions & 9 deletions src/color.rs
Original file line number Diff line number Diff line change
Expand Up @@ -379,22 +379,23 @@ where
}

/// Coefficients to transform from sRGB to a CIE Y (luminance) value.
const SRGB_LUMA: [f32; 3] = [0.2126, 0.7152, 0.0722];
const SRGB_LUMA: [u32; 3] = [2126, 7152, 722];
const SRGB_LUMA_DIV: u32 = 10000;

#[inline]
fn rgb_to_luma<T: Primitive>(rgb: &[T]) -> T {
let l = SRGB_LUMA[0] * rgb[0].to_f32().unwrap()
+ SRGB_LUMA[1] * rgb[1].to_f32().unwrap()
+ SRGB_LUMA[2] * rgb[2].to_f32().unwrap();
NumCast::from(l).unwrap()
let l = <T::Larger as NumCast>::from(SRGB_LUMA[0]).unwrap() * rgb[0].to_larger()
+ <T::Larger as NumCast>::from(SRGB_LUMA[1]).unwrap() * rgb[1].to_larger()
+ <T::Larger as NumCast>::from(SRGB_LUMA[2]).unwrap() * rgb[2].to_larger();
T::clamp_from(l / <T::Larger as NumCast>::from(SRGB_LUMA_DIV).unwrap())
}

#[inline]
fn bgr_to_luma<T: Primitive>(bgr: &[T]) -> T {
let l = SRGB_LUMA[0] * bgr[2].to_f32().unwrap()
+ SRGB_LUMA[1] * bgr[1].to_f32().unwrap()
+ SRGB_LUMA[2] * bgr[0].to_f32().unwrap();
NumCast::from(l).unwrap()
let l = <T::Larger as NumCast>::from(SRGB_LUMA[0]).unwrap() * bgr[2].to_larger()
+ <T::Larger as NumCast>::from(SRGB_LUMA[1]).unwrap() * bgr[1].to_larger()
+ <T::Larger as NumCast>::from(SRGB_LUMA[2]).unwrap() * bgr[0].to_larger();
T::clamp_from(l / <T::Larger as NumCast>::from(SRGB_LUMA_DIV).unwrap())
}

#[inline]
Expand Down
41 changes: 37 additions & 4 deletions src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ impl EncodableLayout for [u16] {
}

/// Primitive trait from old stdlib
pub trait Primitive: Copy + NumCast + Num + PartialOrd<Self> + Clone + Bounded {}
pub trait Primitive: Copy + NumCast + Num + PartialOrd<Self> + Clone + Bounded + Enlargeable {}

impl Primitive for usize {}
impl Primitive for u8 {}
Expand All @@ -45,16 +45,20 @@ impl Primitive for f64 {}
/// An Enlargable::Larger value should be enough to calculate
/// the sum (average) of a few hundred or thousand Enlargeable values.
pub trait Enlargeable: Sized + Bounded + NumCast {
type Larger: Primitive + AddAssign + 'static;
type Larger: Copy + NumCast + Num + PartialOrd<Self::Larger> + Clone + Bounded + AddAssign + 'static;

fn clamp_from(n: Self::Larger) -> Self {
// Note: Only unsigned value types supported.
if n > NumCast::from(Self::max_value()).unwrap() {
if n > Self::max_value().to_larger() {
Self::max_value()
} else if n < Self::min_value().to_larger(){
Self::min_value()
} else {
NumCast::from(n).unwrap()
}
}
fn to_larger(self) -> Self::Larger {
NumCast::from(self).unwrap()
}
}

impl Enlargeable for u8 {
Expand All @@ -66,6 +70,35 @@ impl Enlargeable for u16 {
impl Enlargeable for u32 {
type Larger = u64;
}
impl Enlargeable for u64 {
type Larger = u128;
}
impl Enlargeable for usize {
// Note: On 32-bit architectures, u64 should be enough here.
type Larger = u128;
}
impl Enlargeable for i8 {
type Larger = i32;
}
impl Enlargeable for i16 {
type Larger = i32;
}
impl Enlargeable for i32 {
type Larger = i64;
}
impl Enlargeable for i64 {
type Larger = i128;
}
impl Enlargeable for isize {
// Note: On 32-bit architectures, i64 should be enough here.
type Larger = i128;
}
impl Enlargeable for f32 {
type Larger = f64;
}
impl Enlargeable for f64 {
type Larger = f64;
}

/// A generalized pixel.
///
Expand Down

0 comments on commit d27bcdb

Please sign in to comment.