tiny-skia icon indicating copy to clipboard operation
tiny-skia copied to clipboard

Add dithering support

Open RazrFalcon opened this issue 5 years ago • 4 comments
trafficstars

Makes gradients nicer, afaiu.

RazrFalcon avatar Nov 07 '20 21:11 RazrFalcon

It's enough to add 0.5 * random([0..1]) to the value before rounding it. This is from an unpublished crate with color utilities I'm working on atm:

use clamped::Clamp;
use core::ops::Mul;
use num_traits::{float::Float, identities::Zero};
use oorandom;

pub fn quantize<T>(
    value: T,
    one: T,
    min: T,
    max: T,
    dither_amplitude: T,
    rng: &mut oorandom::Rand32,
) -> T
where
    T: Float + Mul<f32, Output = T>,
{
    (one * value + dither_amplitude * rng.rand_float())
        .round()
        .clamped(min, max)
}

To go from 0..1 to 0..255 with dithering:

let quantized_value = quantize::<f32>(value, 255.0, 0.0, 255.0, 0.5) as u8;

min/max are for conversion of HDR with headroom and you may not need this. For example, going to 15 bit with one bit of headroom:

let quantized_value = quantize::<f32>(value, 32767.0, 0.0, 65535.0, 0.5) as u16;

If deterministic results are not needed, the rng can be initialized inside the function ofc.

virtualritz avatar Dec 07 '20 19:12 virtualritz

I plan to use Skia's implementation.

RazrFalcon avatar Dec 07 '20 19:12 RazrFalcon

Yes, that one will work for many cases. Not sure if those bitshift ops will end up being faster than a rng lookup though.

However, after you add #12 and someone wanted to use tiny-skia for creating art exported e.g. as OpenEXR and which is color-graded afterwards, they don't want the dither pattern to show up. I.e. for generative art etc. (check e.g. valora).

I'd suggest making the dither algo pluggable somehow – if that's not too much work (closure, maybe?).

virtualritz avatar Dec 07 '20 19:12 virtualritz

I'd suggest making the dither algo pluggable somehow

Not possible. The rendering pipeline is very low-level and vectorized.

RazrFalcon avatar Dec 07 '20 20:12 RazrFalcon