about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock45
-rw-r--r--Cargo.toml1
-rw-r--r--squash/Cargo.toml4
-rw-r--r--squash/README.md3
-rw-r--r--squash/src/cli.rs37
-rw-r--r--squash/src/image.rs11
-rw-r--r--squash/src/main.rs15
-rw-r--r--src/lib.rs7
8 files changed, 109 insertions, 14 deletions
diff --git a/Cargo.lock b/Cargo.lock
index fc918c1..4e9b559 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -27,6 +27,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
 
 [[package]]
+name = "bitvec"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
+dependencies = [
+ "funty",
+ "radium",
+ "tap",
+ "wyz",
+]
+
+[[package]]
 name = "bytemuck"
 version = "1.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -48,6 +60,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 name = "colorsquash"
 version = "0.1.0"
 dependencies = [
+ "gifed",
  "rgb",
 ]
 
@@ -80,9 +93,16 @@ dependencies = [
 ]
 
 [[package]]
+name = "funty"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
+
+[[package]]
 name = "gifed"
-version = "0.2.0"
+version = "0.3.0"
 dependencies = [
+ "bitvec",
  "weezl",
 ]
 
@@ -115,6 +135,12 @@ dependencies = [
 ]
 
 [[package]]
+name = "radium"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
+
+[[package]]
 name = "rgb"
 version = "0.8.36"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -131,7 +157,7 @@ checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
 
 [[package]]
 name = "squash"
-version = "0.1.0"
+version = "0.2.0"
 dependencies = [
  "anyhow",
  "camino",
@@ -142,12 +168,27 @@ dependencies = [
 ]
 
 [[package]]
+name = "tap"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
+
+[[package]]
 name = "weezl"
 version = "0.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb"
 
 [[package]]
+name = "wyz"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
+dependencies = [
+ "tap",
+]
+
+[[package]]
 name = "zune-core"
 version = "0.2.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index a4f7347..c5bb6a7 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -11,6 +11,7 @@ repository = "https://github.com/gennyble/colorsquash"
 
 [dependencies]
 rgb = "0.8.36"
+gifed = { path = "../gifed/gifed", optional = true }
 
 [workspace]
 members = ["squash"]
diff --git a/squash/Cargo.toml b/squash/Cargo.toml
index 68fe712..760dcaf 100644
--- a/squash/Cargo.toml
+++ b/squash/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "squash"
-version = "0.1.0"
+version = "0.2.0"
 authors = ["gennyble <gen@nyble.dev>"]
 edition = "2021"
 license = "ISC"
@@ -11,7 +11,7 @@ repository = "https://github.com/gennyble/colorsquash/tree/main/squash"
 
 [dependencies]
 # the meat 'o the thing! the meaning behind it all
-colorsquash = { path = "..", version = "0.1.0" }
+colorsquash = { path = "..", version = "0.1.0", features = ["gifed"] }
 
 # just useful tools for writing binaries
 anyhow = "1.0.75"
diff --git a/squash/README.md b/squash/README.md
new file mode 100644
index 0000000..6dd691c
--- /dev/null
+++ b/squash/README.md
@@ -0,0 +1,3 @@
+# squash
+A command line color quantization program. Accepts most JPEG/PNG as input
+and outputs indexed PNG/GIF
\ No newline at end of file
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<f32>,
+	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<u8>,
 	pub tolerance: Option<f32>,
+	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=<int> | clrs=<int>");
 	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=<algorithm> | did=<algorithm>");
+	println!("        the color comparison function to use. one of: rgb, redmean");
+	println!("        for more details use help=algorithms. [Default rgb]");
 	println!("    tolerance=<float> | tol=<float>");
 	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<u8>,
 	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);
 
diff --git a/src/lib.rs b/src/lib.rs
index 8d94c8e..213adfc 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -144,6 +144,13 @@ impl<T: Count> Squasher<T> {
 		}
 	}
 
+	#[cfg(feature = "gifed")]
+	pub fn palette_gifed(&self) -> gifed::block::Palette {
+		use rgb::ComponentBytes;
+
+		self.palette.as_slice().as_bytes().try_into().unwrap()
+	}
+
 	/// Retrieve the palette this squasher is working from
 	pub fn palette(&self) -> &[RGB8] {
 		&self.palette