From 0ec3c8d1c51ea2286e7762f3a3d1cbebd7700f50 Mon Sep 17 00:00:00 2001 From: gennyble Date: Fri, 12 Jan 2024 12:08:19 -0600 Subject: squash: fix tolerance and add algorithm selection --- squash/src/cli.rs | 37 ++++++++++++++++++++++++++++++++++++- squash/src/image.rs | 11 +++++------ squash/src/main.rs | 15 ++++++++++++--- 3 files changed, 53 insertions(+), 10 deletions(-) (limited to 'squash/src') diff --git a/squash/src/cli.rs b/squash/src/cli.rs index 2e9251f..dec36fa 100644 --- a/squash/src/cli.rs +++ b/squash/src/cli.rs @@ -9,6 +9,7 @@ const AUTHORS: &str = env!("CARGO_PKG_AUTHORS"); pub struct Cli { pub color_count: u8, pub tolerance: Option, + pub difference: DifferenceFn, pub input: Utf8PathBuf, pub in_type: InType, pub output: Utf8PathBuf, @@ -21,6 +22,7 @@ pub struct Cli { struct BuildingCli { pub color_count: Option, pub tolerance: Option, + pub difference: DifferenceFn, } impl BuildingCli { @@ -59,6 +61,7 @@ impl BuildingCli { Cli { color_count: self.color_count.unwrap_or(Self::DEFAULT_COLORS), tolerance: self.tolerance, + difference: self.difference, input, in_type, output, @@ -77,6 +80,13 @@ pub enum OutType { Gif, } +#[derive(Debug, Default)] +pub enum DifferenceFn { + #[default] + Rgb, + Redmean, +} + pub fn build() -> Cli { let mut free = vec![]; let mut building = BuildingCli::default(); @@ -124,6 +134,15 @@ pub fn build() -> Cli { building.tolerance = Some(tol); } }, + Some(("difference", algo)) | Some(("dif", algo)) => match algo { + "rgb" => building.difference = DifferenceFn::Rgb, + "redmean" => building.difference = DifferenceFn::Redmean, + _ => { + eprintln!("'{algo}' is not recognized as an algorithm. See help=algorithms"); + std::process::exit(1); + } + }, + Some(("help", "algorithms")) => print_help_algorithms(), Some(("help", _)) => print_help(), Some(("version", _)) => print_version(), Some((key, _)) => { @@ -153,7 +172,11 @@ fn print_help() -> ! { println!("ARGUMENTS:"); println!(" colors= | clrs="); println!(" the number of colours the final image should contain"); - println!(" a whole number more than 0 and less than, or equal, 256 [Default 256]\n"); + println!(" a whole number more than 0 and less than, or equal, 256"); + println!(" [Default 256]\n"); + println!(" difference= | did="); + println!(" the color comparison function to use. one of: rgb, redmean"); + println!(" for more details use help=algorithms. [Default rgb]"); println!(" tolerance= | tol="); println!(" how different colours should be to be added to the palette"); println!(" a number > 0 and <= 100\n"); @@ -164,6 +187,18 @@ fn print_help() -> ! { std::process::exit(0) } +fn print_help_algorithms() -> ! { + println!("ALGORITHMS"); + println!("rgb:"); + println!(" a straight, rather naïve, RGB comparison. It sums the channel"); + println!(" differences. This is it, really:"); + println!(" |a.red - b.red| + |a.green - b.green| + |a.blue - b.blue|\n"); + println!("redmean:"); + println!(" a slightly more intelligent algorithm that weighs the channels"); + println!(" in an attempt to more better align with human color perception."); + std::process::exit(0) +} + fn print_version() -> ! { println!("squash version {VERSION}"); println!("written by {AUTHORS}"); diff --git a/squash/src/image.rs b/squash/src/image.rs index 098e8a0..5c7b45a 100644 --- a/squash/src/image.rs +++ b/squash/src/image.rs @@ -3,7 +3,7 @@ use std::{fs::File, io::BufWriter}; use anyhow::{anyhow, bail}; use camino::{Utf8Path, Utf8PathBuf}; use colorsquash::Squasher; -use gifed::writer::{GifBuilder, ImageBuilder}; +use gifed::{writer::ImageBuilder, Gif}; use png::{ColorType, Decoder, Encoder}; use zune_jpeg::{zune_core::colorspace::ColorSpace, JpegDecoder}; @@ -94,11 +94,10 @@ pub fn save_gif( squasher: Squasher, path: Utf8PathBuf, ) -> Result<(), anyhow::Error> { - GifBuilder::new(image.width as u16, image.height as u16) - .palette(squasher.palette_bytes().as_slice().try_into().unwrap()) - .image(ImageBuilder::new(image.width as u16, image.height as u16).build(image.data)?) - .build()? - .save(path)?; + let mut gif = Gif::new(image.width as u16, image.height as u16); + gif.set_palette(Some(squasher.palette_gifed())); + gif.push(ImageBuilder::new(image.width as u16, image.height as u16).build(image.data)?); + gif.save(path)?; Ok(()) } diff --git a/squash/src/main.rs b/squash/src/main.rs index 8b77b47..5437ea1 100644 --- a/squash/src/main.rs +++ b/squash/src/main.rs @@ -1,4 +1,5 @@ -use colorsquash::Squasher; +use cli::DifferenceFn; +use colorsquash::{Squasher, SquasherBuilder}; use crate::cli::{InType, OutType}; @@ -7,6 +8,7 @@ mod image; fn main() -> Result<(), anyhow::Error> { //gen: I should use clap or at least getopt, but this is fine. + //gen: I like experimenting with the cli :) let cli = cli::build(); let mut image = match cli.in_type { @@ -14,12 +16,19 @@ fn main() -> Result<(), anyhow::Error> { InType::Jpeg => image::get_jpg(cli.input)?, }; - let mut squasher = Squasher::new(cli.color_count, &image.data); + let mut builder = SquasherBuilder::default().max_colors(cli.color_count); if let Some(tol) = cli.tolerance { - squasher.set_tolerance(tol); + builder = builder.tolerance(tol); } + builder = match cli.difference { + DifferenceFn::Rgb => builder.difference(&colorsquash::difference::rgb_difference), + DifferenceFn::Redmean => builder.difference(&colorsquash::difference::redmean_difference), + }; + + let mut squasher = builder.build(&image.data); + let size = squasher.map_over(&mut image.data); image.data.resize(size, 0); -- cgit 1.4.1-3-g733a5