Created
June 16, 2025 05:08
-
-
Save randrews/2adcdbf1b57a62becdd160e886f12572 to your computer and use it in GitHub Desktop.
Atkinson dithering in Rust (with the Shepard Fairey Obama poster palette)
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!("atkinson.png")).unwrap().into_luma16(); | |
let (width, height) = (input.width(), input.height()); | |
let mut output = image::RgbImage::new(width, height); | |
let mut error_rows = vec![vec![0.0; width as usize]; 3]; | |
let palette: Vec<image::Rgb<u8>> = vec![ | |
[0xe4, 0x2b, 0x19].into(), | |
[0, 0x40, 0x62].into(), | |
[0x82, 0xa7, 0xaf].into(), | |
[0xbe, 0xc3, 0xb6].into(), | |
[0xfb, 0xe8, 0xbb].into() | |
]; | |
for (x, y, p) in input.enumerate_pixels() { | |
let xu = x as usize; | |
// We're at the start of a new row, so we need to roll the error buffers: | |
if x == 0 && y > 0 { | |
let mut v = error_rows.remove(0); | |
v.fill(0.0); | |
error_rows.push(v); | |
} | |
let sh = palette.len() as f32 - 1.0; // number of divisions to quantize with | |
let old_val = ((p.0[0] as f32 / 65535.0) + error_rows[0][xu]).clamp(0.0, 1.0); | |
let new_val = (old_val * sh).floor() / sh; // quantize the current value + error | |
let error = old_val - new_val; | |
// Find the color in the palette and write it to output | |
let color = palette[(new_val * (palette.len() - 1) as f32) as usize]; | |
output.put_pixel(x, y, color); | |
// spread the error around | |
if x + 2 < width { | |
error_rows[0][xu + 2] += error / 8.0 | |
} | |
if x + 1 < width { | |
error_rows[0][xu + 1] += error / 8.0; | |
error_rows[1][xu + 1] += error / 8.0 | |
} | |
error_rows[1][xu] += error / 8.0; | |
error_rows[2][xu] += error / 8.0; | |
if x > 0 { | |
error_rows[1][xu - 1] += error / 8.0 | |
} | |
} | |
output.save_with_format("atkinson-dithered.png", image::ImageFormat::Png).unwrap() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment