dithereens 0.3.0

Functions & traits for quantizing values with error-diffusion
Documentation

dithereens

Before/after dithering Before (top) and after (bottom) dithering a gradient (uses simple_dither(), i.e. defaults).

Functions and traits for quantizing values with deterministic hash-based error-diffusion.

Quantizing from f64/f32/f16 to u32/u16/u8 without dithering creates banding. This crate provides deterministic hash-based dithering to reduce quantization artifacts.

Overview

  • Deterministic: Same input with same seed always produces same output.
  • Multiple dithering methods: Hash, R2, GoldenRatio for 1D; IGN, SpatialHash, BlueNoise for 2D.
  • Single values: [dither()], [simple_dither()].
  • Iterator processing: [dither_iter()], [simple_dither_iter()].
  • In-place operations: [dither_slice()], [simple_dither_slice()].
  • 2D dithering: [dither_slice_2d()], [simple_dither_slice_2d()] for images.
  • Custom methods: Use specific dithering algorithms via [*_with_method()] functions.
  • no_std support: Works in embedded environments.
  • Generic types: f32, f64, f16 (with nightly_f16 feature), or any type implementing [DitherFloat].
  • Blue noise: High-quality blue noise dithering (with blue_noise feature).

Quick Start

use dithereens::simple_dither;

let value: f32 = 0.5;

// Dither `value` to `127u8` or `128u8` deterministically.
// The same index and seed will always produce the same result.
let dithered_value: u8 =
    simple_dither(value, 255.0, 0, 42).clamp(0.0, 255.0) as u8;

assert!(dithered_value == 127 || 128 == dithered_value);

Dithering Methods

1D Methods (for sequential data)

  • Hash (default): Fast hash-based dithering
  • R2: Low-discrepancy sequence using the R2 sequence
  • GoldenRatio: Golden ratio-based sequence

2D Methods (for images)

  • InterleavedGradientNoise (IGN): Fast, good quality for real-time graphics
  • SpatialHash: Spatial hash function for blue noise-like properties
  • BlueNoiseApprox: Approximation combining IGN and SpatialHash
  • BlueNoise (requires blue_noise feature): True blue noise from precomputed tables

Using Custom Methods

use dithereens::{simple_dither_with_method, Hash, R2, GoldenRatio};

let value = 0.5f32;
let seed = 42;

// Use different dithering methods
let hash_method = Hash::new(seed);
let r2_method = R2::new(seed);
let golden_method = GoldenRatio::new(seed);

let dithered_hash = simple_dither_with_method(value, 255.0, 0, &hash_method);
let dithered_r2 = simple_dither_with_method(value, 255.0, 0, &r2_method);
let dithered_golden = simple_dither_with_method(value, 255.0, 0, &golden_method);

2D Dithering for Images

use dithereens::{simple_dither_slice_2d, InterleavedGradientNoise};

// Example: dither a grayscale image
let width = 256;
let height = 256;
let mut pixels: Vec<f32> = vec![0.5; width * height];

// Use IGN for 2D dithering
let method = InterleavedGradientNoise::new(42);
simple_dither_slice_2d(&mut pixels, width, 255.0, &method);

// pixels now contains dithered values

Performance Guide

Benchmarks with 10,000 values:

  • Single values: [dither()], [simple_dither()].
  • In-place slice operations: [dither_slice()], [simple_dither_slice()] (~5.6x faster than iterator methods)
  • Iterator chains: [dither_iter()], [simple_dither_iter()], or [DitherIteratorExt] adapters (allocation overhead)

Parallel Processing

Via rayon (enabled by default). With rayon enabled, _iter and _slice functions use parallel processing automatically for better performance on large datasets.

no_std Support

This crate supports no_std environments. The libm crate provides a native round() implementation. Without libm, a manual implementation is used.

[dependencies]
# `no_std`
dithereens = { version = "0.3", default-features = false }
[dependencies]
# Optional: uses `libm`'s `round()` function instead of a manual
# implementation for `no_std`.
dithereens = {
   version = "0.3",
   default-features = false,
   features = ["libm"]
}

Native f16 Support

Enable the nightly_f16 feature to use native f16 types (requires nightly Rust):

[dependencies]
dithereens = { version = "0.3", features = ["nightly_f16"] }

Blue Noise Support

Enable the blue_noise feature for high-quality blue noise dithering:

[dependencies]
dithereens = { version = "0.3", features = ["blue_noise"] }

This adds the BlueNoise struct which provides true blue noise dithering using a precomputed 256×256×4 table. Note: This increases binary size by ~5MB.

#[cfg(feature = "blue_noise")]
use dithereens::{simple_dither_slice_2d, BlueNoise};

let width = 256;
let mut pixels: Vec<f32> = vec![0.5; width * width];

let blue_noise = BlueNoise::new(42);
simple_dither_slice_2d(&mut pixels, width, 255.0, &blue_noise);

License

Apache-2.0 OR BSD-3-Clause OR MIT OR Zlib at your discretion.