| Crates.io | blue-noise |
| lib.rs | blue-noise |
| version | 0.2.1 |
| created_at | 2021-01-19 03:20:32.766164+00 |
| updated_at | 2025-11-05 09:13:59.012318+00 |
| description | High-quality blue noise generation and dithering using the void-and-cluster algorithm |
| homepage | |
| repository | https://github.com/mblode/blue-noise/ |
| max_upload_size | |
| id | 343777 |
| size | 1,032,489 |
A comprehensive Rust implementation of Robert Ulichney's void-and-cluster algorithm for generating blue noise textures and applying high-quality dithering to images. Blue noise produces evenly distributed, visually pleasing dithered images without the clustering artifacts of white noise or the repetitive patterns of Bayer dithering.
cargo install blue-noise
git clone https://github.com/mblode/blue-noise.git
cd blue-noise
cargo build --release
The binary will be in target/release/blue-noise.
# Generate a 128x128 blue noise texture
blue-noise generate --size 128 --output blue-noise.png
# Generate with custom sigma and seed for reproducibility
blue-noise generate --size 64 --sigma 1.9 --seed 42 --verbose
# Quick 64x64 texture (2-5 seconds)
blue-noise generate -s 64 -o noise-64.png
# Larger 256x256 texture (several minutes)
blue-noise generate -s 256 -o noise-256.png --verbose
Options:
-s, --size <SIZE> - Texture size (8-512, default: 128)-o, --output <PATH> - Output file path (default: blue-noise.png)--sigma <SIGMA> - Gaussian sigma (1.0-3.0, default: 1.9)--seed <SEED> - Random seed for reproducibility-v, --verbose - Show detailed progress# Basic dithering
blue-noise dither -i input.jpg -o output.png
# Custom colors
blue-noise dither -i photo.jpg -o dithered.png \
--foreground "#000000" \
--background "#ffffff"
# Resize and adjust contrast
blue-noise dither -i image.png -o output.png \
--width 800 \
--contrast 1.2
# Use custom noise texture
blue-noise dither -i input.jpg -o output.png \
--noise custom-noise.png \
--foreground "#1a1a1a" \
--background "#f0f0f0"
Options:
-i, --input <PATH> - Input image path (required)-o, --output <PATH> - Output image path (required)-n, --noise <PATH> - Blue noise texture (default: blue-noise.png)-f, --foreground <HEX> - Foreground color (default: #000000)-b, --background <HEX> - Background color (default: #ffffff)-w, --width <PIXELS> - Output width (maintains aspect ratio)--height <PIXELS> - Output height (maintains aspect ratio)-c, --contrast <FLOAT> - Contrast adjustment (1.0 = normal)Add to your Cargo.toml:
[dependencies]
blue-noise = "0.2"
use blue_noise::{BlueNoiseGenerator, BlueNoiseConfig, save_blue_noise_to_png};
// Create configuration
let config = BlueNoiseConfig {
width: 128,
height: 128,
sigma: 1.9,
seed: Some(42),
verbose: true,
..Default::default()
};
// Generate texture
let generator = BlueNoiseGenerator::new(config)?;
let result = generator.generate()?;
// Save to file
save_blue_noise_to_png(&result, "blue-noise.png")?;
use blue_noise::{
BlueNoiseTexture,
Color,
DitherOptions,
apply_dithering
};
// Load blue noise texture
let noise = BlueNoiseTexture::load("blue-noise.png")?;
// Configure dithering
let options = DitherOptions {
foreground: Color::from_hex("#000000")?,
background: Color::from_hex("#ffffff")?,
width: Some(800),
height: None,
contrast: Some(1.2),
};
// Apply dithering
apply_dithering("input.jpg", "output.png", &noise, options)?;


# Sepia tone
blue-noise dither -i photo.jpg -o sepia.png \
--foreground "#704214" --background "#f4e8d8"
# Blue on white
blue-noise dither -i image.jpg -o blue.png \
--foreground "#0066cc" --background "#ffffff"
# Green matrix style
blue-noise dither -i code.jpg -o matrix.png \
--foreground "#00ff00" --background "#000000"
This implementation uses Ulichney's void-and-cluster algorithm, which produces high-quality blue noise with evenly distributed energy at high frequencies and minimal low-frequency content.
The algorithm uses toroidal topology (wraparound edges) to ensure seamless tiling, making it perfect for dithering large images with small noise textures.
For power-of-two dimensions, Gaussian blur is performed in the frequency domain using FFT, providing ~50% performance improvement through the convolution theorem:
convolution(A, B) = IFFT(FFT(A) × FFT(B))
Generation times:
Tip: Pre-generate textures rather than generating at runtime.
Ulichney, R. (1993). "Void-and-cluster method for dither array generation" Proceedings of SPIE 1913, Human Vision, Visual Processing, and Digital Display IV https://doi.org/10.1117/12.152707
Ulichney, R. (1988). "Dithering with blue noise" Proceedings of the IEEE, 76(1), 56-79
# Build
cargo build --release
# Run tests
cargo test
# Run benchmarks
cargo bench
# Generate documentation
cargo doc --open
MIT License - see LICENSE for details
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.