This commit is contained in:
mehbark 2026-02-04 01:00:53 -05:00
commit f452a6e869
4 changed files with 1132 additions and 0 deletions

4
.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
/target
.devenv
*.jpg
*.png

1076
Cargo.lock generated Normal file

File diff suppressed because it is too large Load diff

7
Cargo.toml Normal file
View file

@ -0,0 +1,7 @@
[package]
name = "floyd-steinberg"
version = "0.1.0"
edition = "2024"
[dependencies]
image = "0.25.6"

45
src/main.rs Normal file
View file

@ -0,0 +1,45 @@
use std::{env, error::Error};
use image::{DynamicImage, ImageReader, Luma};
#[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)]
fn main() -> Result<(), Box<dyn Error>> {
let kernel: &[(i64, i64, f32)] = &[
(1, 0, 7. / 16.),
(-1, 1, 3. / 16.),
(0, 1, 5. / 16.),
(1, 1, 1. / 16.),
];
let src = env::args().nth(1).ok_or("i need a source path")?;
let out_path = env::args().nth(2).ok_or("i need an output path")?;
let mut img = ImageReader::open(&src)?.decode()?.to_luma32f();
let mut out = img.clone();
for y in 0..img.height() {
for x in 0..img.width() {
let old_pixel = img.get_pixel(x, y);
let old_luma = old_pixel.0[0];
let luma = if old_luma < 0.5 { 0. } else { 1. };
out.put_pixel(x, y, Luma([luma]));
let error = old_luma - luma;
for (dx, dy, quant) in kernel {
let x = (i64::from(x) + dx) as u32;
let y = (i64::from(y) + dy) as u32;
if x >= img.width() || y >= img.height() {
continue;
}
let error = error * quant;
let luma = img.get_pixel(x, y).0[0];
let corrected = luma + error;
img.put_pixel(x, y, Luma([corrected]));
}
}
}
DynamicImage::from(out).into_luma8().save(out_path)?;
Ok(())
}