Crate dithereens

Crate dithereens 

Source
Expand description

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().
  • Image support: Both 1D methods (processing as flat array) and 2D methods (using coordinates).
  • 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 and images as flat arrays)

  • Hash (default): Fast hash-based dithering, good general-purpose quality.
  • R2: Low-discrepancy sequence using the R2 sequence.
  • GoldenRatio: Golden ratio-based sequence.

1D methods have been used successfully for image dithering for years by processing images as flat arrays. They work well when you don’t need spatial correlation between pixels.

§2D Methods (for images using spatial coordinates)

  • 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.

2D methods use pixel coordinates to create spatially-aware dithering patterns, which can produce more visually pleasing results for images.

§Using Custom Methods

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

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(value, 255.0, 0, &hash_method);
let dithered_r2 = simple_dither_with(value, 255.0, 0, &r2_method);
let dithered_golden = simple_dither_with(value, 255.0, 0, &golden_method);

§Image Dithering with 1D Methods

1D methods work great for images when processed as flat arrays:

use dithereens::{Hash, simple_dither_slice};

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

// Process entire image as flat array with 1D dithering.
simple_dither_slice(&mut pixels, 255.0, 42);

// pixels now contains dithered values.

§2D Dithering for Images

2D methods use spatial coordinates for better visual results:

use dithereens::{InterleavedGradientNoise, simple_dither_slice_2d};

// 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:

§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.

This increases binary size by ~5M!

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

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);

§Float-to-Float Dithering

Dither when converting between floating-point types of different precisions to reduce quantization artifacts like banding in smooth gradients.

§Supported Conversions

  • f64 → f32: Always available.
  • f32 → f16: Requires nightly_f16 feature and nightly Rust.
  • f64 → f16: Requires nightly_f16 feature and nightly Rust.

§Use Cases

Float-to-float dithering is particularly useful for:

  • Converting HDR sky gradients from f32 to f16.
  • Reducing banding in smooth color transitions.
  • Maintaining visual quality when downsampling precision.
  • Processing high-precision data for display or storage.

§Example: HDR Gradient Conversion

use dithereens::dither_float_slice;

// Smooth gradient in f64.
let gradient: Vec<f64> = (0..100).map(|i| 1.0 + i as f64 * 0.001).collect();

// Convert to f32 with dithering to preserve smoothness.
let dithered: Vec<f32> = dither_float_slice(&gradient, 42);

// Without dithering (simple cast) would show more banding.

§Example: Image Conversion with 2D Methods

use dithereens::{InterleavedGradientNoise, dither_float_slice_2d};

let width = 256;
let image_f32: Vec<f32> = vec![1.5; width * width];

// Use 2D dithering for spatially-aware noise patterns.
let method = InterleavedGradientNoise::new(42);
let image_f16: Vec<f16> = dither_float_slice_2d(&image_f32, width, &method);

§Available Functions

Single values:

Slices:

Iterators:

Trait methods: All LinearRng and SpatialRng implementations provide dither_float* methods.

See examples/float_precision_dither.rs for complete examples.

Modules§

rng
Position-based random number generation using spatial RNG methods.

Structs§

BlueNoiseApprox
Blue noise approximation using multiple octaves.
GoldenRatio
Golden ratio sequence for 1D low-discrepancy sampling.
Hash
Hash-based dithering (default method).
InterleavedGradientNoise
Interleaved Gradient Noise for 2D dithering.
R2
R2 low-discrepancy sequence for improved distribution.
SpatialHash
Spatial hash for 2D blue noise-like properties.

Traits§

DitherFloat
Minimal trait requirements for dithering.
DitherFloatConversion
Trait for dithered float-to-float precision conversions.
DitherIteratorExt
Iterator adapter trait for dithering operations.
DitherParallelIteratorExt
Parallel iterator adapter trait for dithering operations.
LinearRng
Trait for linear (1D) random number generators.
SpatialRng
Trait for spatial random number generators.

Functions§

dither
Dither a value using the default hash method (backward compatible).
dither_2d
Dither a value using 2D coordinates.
dither_float
Dither a float value when converting to lower precision using default hash method.
dither_float_2d
Dither a float value when converting to lower precision using 2D spatial RNG method.
dither_float_iter
dither_float_iter_with
dither_float_slice
dither_float_slice_2d
dither_float_slice_with
dither_float_with
Dither a float value when converting to lower precision using a specific linear RNG method.
dither_iter
dither_iter_with
dither_slice
dither_slice_2d
dither_slice_with
dither_with
Dither a value using a specific method.
simple_dither
Simple dither with default hash method (backward compatible).
simple_dither_2d
Simple dither with 2D coordinates.
simple_dither_iter
simple_dither_iter_with
simple_dither_slice
simple_dither_slice_2d
simple_dither_slice_with
simple_dither_with
Simple dither with specific method.