about summary refs log tree commit diff
path: root/squash/src
diff options
context:
space:
mode:
authorgennyble <gen@nyble.dev>2024-01-14 07:33:52 -0600
committergennyble <gen@nyble.dev>2024-01-14 07:33:52 -0600
commit88656a81d8e1480c3e37a3402901525aee1a596c (patch)
tree3263cc0726b8b05981c11083473e271a2f82d0c8 /squash/src
parent2b3181f3c4675d744338f497564faa00bc5d76db (diff)
downloadcolorsquash-88656a81d8e1480c3e37a3402901525aee1a596c.tar.gz
colorsquash-88656a81d8e1480c3e37a3402901525aee1a596c.zip
allow choosing selection algorithm
Diffstat (limited to 'squash/src')
-rw-r--r--squash/src/cli.rs51
-rw-r--r--squash/src/image.rs2
-rw-r--r--squash/src/main.rs24
3 files changed, 63 insertions, 14 deletions
diff --git a/squash/src/cli.rs b/squash/src/cli.rs
index dec36fa..ba1658a 100644
--- a/squash/src/cli.rs
+++ b/squash/src/cli.rs
@@ -1,6 +1,7 @@
 use std::cmp::Ordering;
 
 use camino::Utf8PathBuf;
+use colorsquash::difference::{self, DiffFn};
 
 const NAME: &str = env!("CARGO_PKG_NAME");
 const VERSION: &str = env!("CARGO_PKG_VERSION");
@@ -9,7 +10,8 @@ const AUTHORS: &str = env!("CARGO_PKG_AUTHORS");
 pub struct Cli {
 	pub color_count: u8,
 	pub tolerance: Option<f32>,
-	pub difference: DifferenceFn,
+	pub selector: Selector,
+	pub difference: &'static DiffFn,
 	pub input: Utf8PathBuf,
 	pub in_type: InType,
 	pub output: Utf8PathBuf,
@@ -23,6 +25,7 @@ struct BuildingCli {
 	pub color_count: Option<u8>,
 	pub tolerance: Option<f32>,
 	pub difference: DifferenceFn,
+	pub selector: Selector,
 }
 
 impl BuildingCli {
@@ -58,10 +61,16 @@ impl BuildingCli {
 			}
 		};
 
+		let difference = match self.difference {
+			DifferenceFn::Rgb => &difference::rgb as &DiffFn,
+			DifferenceFn::Redmean => &difference::redmean as &DiffFn,
+		};
+
 		Cli {
 			color_count: self.color_count.unwrap_or(Self::DEFAULT_COLORS),
 			tolerance: self.tolerance,
-			difference: self.difference,
+			selector: self.selector,
+			difference,
 			input,
 			in_type,
 			output,
@@ -87,6 +96,13 @@ pub enum DifferenceFn {
 	Redmean,
 }
 
+#[derive(Debug, Default)]
+pub enum Selector {
+	#[default]
+	SortSelect,
+	Kmeans,
+}
+
 pub fn build() -> Cli {
 	let mut free = vec![];
 	let mut building = BuildingCli::default();
@@ -142,7 +158,16 @@ pub fn build() -> Cli {
 					std::process::exit(1);
 				}
 			},
+			Some(("selector", sel)) | Some(("sel", sel)) => match sel {
+				"sort/select" => building.selector = Selector::SortSelect,
+				"kmeans" => building.selector = Selector::Kmeans,
+				_ => {
+					eprintln!("'{sel}' is not recognized as a selector. See help=selectors");
+					std::process::exit(1);
+				}
+			},
 			Some(("help", "algorithms")) => print_help_algorithms(),
+			Some(("help", "selectors")) => print_help_selectors(),
 			Some(("help", _)) => print_help(),
 			Some(("version", _)) => print_version(),
 			Some((key, _)) => {
@@ -174,12 +199,16 @@ fn print_help() -> ! {
 	println!("        the number of colours the final image should contain");
 	println!("        a whole number more than 0 and less than, or equal, 256");
 	println!("        [Default 256]\n");
-	println!("    difference=<algorithm> | did=<algorithm>");
+	println!("    difference=<algorithm> | dif=<algorithm>");
 	println!("        the color comparison function to use. one of: rgb, redmean");
-	println!("        for more details use help=algorithms. [Default rgb]");
+	println!("        for more details use help=algorithms. [Default rgb]\n");
+	println!("    selection=<selector> | sel=<selector>");
+	println!("        the algorithm for picking the palette. one of: means, sort/select");
+	println!("        for more details use help=selectors. [Default sort/select]");
 	println!("    tolerance=<float> | tol=<float>");
 	println!("        how different colours should be to be added to the palette");
-	println!("        a number > 0 and <= 100\n");
+	println!("        only sort/select usese this value.");
+	println!("        a number > 0 and <= 100 [Default 3]\n");
 	println!("    help= | -h | --help");
 	println!("        print this message and exit\n");
 	println!("    version= | -V | --version");
@@ -199,6 +228,18 @@ fn print_help_algorithms() -> ! {
 	std::process::exit(0)
 }
 
+fn print_help_selectors() -> ! {
+	println!("SELECTORS:");
+	println!("sort/select:");
+	println!("    the original colorsquash algorithm. sorts colors from most to least");
+	println!("    frequent and then picks the most frequent colors so long as they are");
+	println!("    sufficiently different (configurable with tolerance=)\n");
+	println!("kmeans:");
+	println!("    uses the kmeans clustering algorithm to select colours.");
+	println!("    Ignores tolerance=");
+	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 5c7b45a..ff6650f 100644
--- a/squash/src/image.rs
+++ b/squash/src/image.rs
@@ -2,7 +2,7 @@ use std::{fs::File, io::BufWriter};
 
 use anyhow::{anyhow, bail};
 use camino::{Utf8Path, Utf8PathBuf};
-use colorsquash::Squasher;
+use colorsquash::{selection::SortSelect, Squasher};
 use gifed::{writer::ImageBuilder, Gif};
 use png::{ColorType, Decoder, Encoder};
 use zune_jpeg::{zune_core::colorspace::ColorSpace, JpegDecoder};
diff --git a/squash/src/main.rs b/squash/src/main.rs
index 8e3a79b..b443f57 100644
--- a/squash/src/main.rs
+++ b/squash/src/main.rs
@@ -1,5 +1,8 @@
 use cli::DifferenceFn;
-use colorsquash::SquasherBuilder;
+use colorsquash::{
+	selection::{Kmeans, Selector, SortSelect},
+	SquasherBuilder,
+};
 
 use crate::cli::{InType, OutType};
 
@@ -16,15 +19,20 @@ fn main() -> Result<(), anyhow::Error> {
 		InType::Jpeg => image::get_jpg(cli.input)?,
 	};
 
-	let mut builder = SquasherBuilder::default().max_colors(cli.color_count);
+	let mut builder = SquasherBuilder::new()
+		.max_colors(cli.color_count)
+		.mapper_difference(cli.difference);
 
-	if let Some(tol) = cli.tolerance {
-		builder = builder.tolerance(tol);
-	}
+	match cli.selector {
+		cli::Selector::SortSelect => {
+			let mut sorsel = SortSelect::default().difference(cli.difference);
+			if let Some(tol) = cli.tolerance {
+				sorsel = sorsel.tolerance(tol)
+			}
 
-	builder = match cli.difference {
-		DifferenceFn::Rgb => builder.difference(&colorsquash::difference::rgb),
-		DifferenceFn::Redmean => builder.difference(&colorsquash::difference::redmean),
+			builder = builder.selector(sorsel);
+		}
+		cli::Selector::Kmeans => builder = builder.selector(Kmeans),
 	};
 
 	let mut squasher = builder.build(&image.data);