diff --git a/src/main.rs b/src/main.rs index af48a55..8c945b7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,8 +20,13 @@ fn main() { let image = image.resize(w / 8, h / 8, FilterType::CatmullRom); image.save("scaled.png").unwrap(); println!("resized"); - // let image = quantize_image(image, 6); - let image = dither(image, 12); + + const COLOR_COUNT: usize = 6; + + let quantized_image = quantize_image(image.clone(), COLOR_COUNT); + quantized_image.save("q.png").unwrap(); + + let image = dither(image, COLOR_COUNT); image.save("out.png").unwrap(); println!("saved"); } @@ -34,10 +39,15 @@ fn generate_palette(image: &DynamicImage, count: usize) -> Vec> { .map(|(_x, _y, a)| a.to_rgb()) // .collect()]; + struct Spread { + range: u8, + channel: usize, + mid_point: u8, + } // divide buckets count-1 times for _i in 0..(count - 1) { // spread amount and channel for each bucket - let mut spreads: Vec<(u8, usize)> = Vec::new(); + let mut spreads: Vec = Vec::new(); // calculate where each bucket would do its division if it's chosen // todo: only calculate this when the bucket is created/modified for bucket in &buckets { @@ -54,23 +64,30 @@ fn generate_palette(image: &DynamicImage, count: usize) -> Vec> { let range_b = max[2] - min[2]; let mut widest_channel = 0; let mut widest_amount = range_r; + let mut widest_middle = min[0] + range_r / 2; if range_g > widest_amount { widest_amount = range_g; widest_channel = 1; + widest_middle = min[1] + range_g / 2; } if range_b > widest_amount { widest_amount = range_b; widest_channel = 2; + widest_middle = min[2] + range_b / 2; } - spreads.push((widest_amount, widest_channel)) + spreads.push(Spread { + range: widest_amount, + channel: widest_channel, + mid_point: widest_middle, + }); } let mut most_spread_bucket = 0; let mut highest_spread = 0; - for (i, &(spread, _channel)) in spreads.iter().enumerate() { - if spread > highest_spread { + for (i, spread) in spreads.iter().enumerate() { + if spread.range > highest_spread { most_spread_bucket = i; - highest_spread = spread; + highest_spread = spread.range; } } @@ -80,11 +97,21 @@ fn generate_palette(image: &DynamicImage, count: usize) -> Vec> { continue; } - let channel = spreads[most_spread_bucket].1; + let channel = spreads[most_spread_bucket].channel; bucket.sort_unstable_by_key(|pixel| pixel.0[channel]); - let halfway = bucket.len() / 2; - let new_bucket = bucket[halfway..].to_owned(); - bucket.truncate(halfway); + let mid_value = spreads[most_spread_bucket].mid_point; + let pop_split = bucket.len() / 2; + let pos_split = bucket + .iter() + .position(|c| c.0[channel] >= mid_value) + .unwrap(); + let split_index = if spreads[most_spread_bucket].range > 150 { + pos_split + } else { + pop_split + }; + let new_bucket = bucket[split_index..].to_owned(); + bucket.truncate(split_index); buckets.push(new_bucket); } let mut colors = Vec::new(); @@ -168,7 +195,7 @@ fn dither(input: DynamicImage, count: usize) -> DynamicImage { let by = y as usize % 4; let bayer = bayer_f(bx, by); - let ratio = ratio + bayer * 1.5; + let ratio = ratio + bayer; let out_col = if ratio > 0. { best_col } else { second_col }; out.put_pixel(x, y, out_col.to_rgba());