Support fixed point like u8 operates like Real
Description
When we write LinSrgba<u8> we actually want to treat 0u8 like 0.0f32 and 255u8 like 1.0f32, especially when doing multiple, this code would emit wrong result if relax T: Real to things like u8
https://github.com/Ogeon/palette/blob/b8fcb95ce59f84971a7f3d0451804156b1dad296/palette/src/encoding/rec_standards.rs#L140-L146
So we shall introduce a new Real-like wrapping type, just like FixedU8<U8>, except the range of FixedU8 is 0 <= x < 1 while we need 0 <= x <= 1 here.
pub struct Fixed<T>(T);
impl std::ops::Mul for Fixed<u8> {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
Self((self.0 as u16 * rhs.0 as u16 / u8::max_intensity()) as u8)
}
}
impl num::Real for Fixed<u8> {
fn from_f64(n: f64) -> Self {
Self((n / u8::max_intensity() as f64).round() as u8)
}
}
Alternative
We could also write our own num::Mul trait to do mul, instead of relies on std::ops::Mul
Notes
Furthermore, we might also make TransformFn marker in this Fixed.
pub struct Fixed<S=Srgb, T=u8> {
value: T,
transfer_fn: PhantomData<S>,
}
// Fixed<LinearFn, u8>
Hi, thanks for the suggestion, but adding specialized number types is beyond the scope of palette. Even the number traits are and will be moved out at a later point. You could implement it as a third party crate, but I would still advice against using u8 for linear RGB, due to its low resolution. It may cause visible banding in dark colors. That's part of what non-linear encodings, like sRGB, help with. When processing the color in linear space, I recommend to also convert the components to f32.
Is there a particular problem you need to solve that requires the components to be u8?
Thanks for kindly reply, I'm trying to port agg to rust, the original algorithm in agg takes heavy dependency on u8 math like multiply_u8, lerp_u8, etc.
I do think it's a good time to upgrade it to f32 based color space when porting. But for the time being, I'd like to first make it compatible to the original implementation.
I see, I suppose they deemed the quality good enough for that use and prioritized speed and memory usage. It may be something to support it in the longer run, with some more specific traits. Maybe a Scale trait for what multiplication usually does, for example. That could avoid requiring specialization and wrapper types. Although the plan is to move the math traits out of the main crate, so it's not necessarily as simple in the future. 🤔