Last active
June 15, 2025 04:58
-
-
Save randrews/6fedcf0968e40b87aec7bba9ce09aca1 to your computer and use it in GitHub Desktop.
Floyd-Steinberg dithering in Rust
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[package] | |
name = "dither" | |
version = "0.1.0" | |
edition = "2024" | |
[dependencies] | |
image = "0.25.6" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
fn main() { | |
let input = image::load_from_memory(include_bytes!("lena.png")).unwrap(); | |
let (width, height) = (input.width(), input.height()); | |
let pixels = input.into_luma16(); | |
let mut out_image = image::GrayImage::new(width, height); | |
let mut curr_row_errors = vec![0.0; width as usize]; | |
let mut next_row_errors = vec![0.0; width as usize]; | |
for (x, y, p) in pixels.enumerate_pixels(){ | |
let xu = x as usize; | |
// We're at the start of a new row, so we need to swap the error buffers around: | |
if x == 0 && y > 0 { | |
(curr_row_errors, next_row_errors) = (next_row_errors, curr_row_errors); | |
next_row_errors.fill(0.0); | |
} | |
let val = (p.0[0] as f32 / 65535.0) + curr_row_errors[xu]; | |
// Get the 16-bit value for calculating everything else: | |
let new_val = if val < 0.5 { | |
0.0 | |
} else { | |
1.0 | |
}; | |
// Write the 8-bit value to output | |
out_image.put_pixel(x, y, [new_val as u8 * 255].into()); | |
let error = val - new_val; | |
if x < width - 1 { | |
curr_row_errors[xu + 1] += error * (7.0 / 16.0); | |
next_row_errors[xu + 1] += error * (1.0 / 16.0); | |
} | |
if x > 0 { | |
next_row_errors[xu - 1] += error * (3.0 / 16.0); | |
} | |
next_row_errors[xu] += error * (5.0 / 16.0); | |
} | |
out_image.save_with_format("lena-dithered.png", image::ImageFormat::Png).unwrap() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment