about summary refs log tree commit diff
diff options
context:
space:
mode:
authorgennyble <gen@nyble.dev>2023-10-09 01:27:19 -0500
committergennyble <gen@nyble.dev>2023-10-09 01:27:19 -0500
commite52599e25372827fd3cef1433773c5a1b181fd3e (patch)
treedefb472fdf74b3d6c163c0983f52e3454b5d0898
parent1575e5fd1a358a3c997288998d7b25f87472905d (diff)
downloadcolorsquash-e52599e25372827fd3cef1433773c5a1b181fd3e.tar.gz
colorsquash-e52599e25372827fd3cef1433773c5a1b181fd3e.zip
squash
-rw-r--r--Cargo.lock11
-rw-r--r--README.md4
-rw-r--r--squash/Cargo.toml7
-rw-r--r--squash/src/.rustfmt.toml (renamed from .rustfmt.toml)0
-rw-r--r--squash/src/main.rs88
-rw-r--r--src/lib.rs3
6 files changed, 107 insertions, 6 deletions
diff --git a/Cargo.lock b/Cargo.lock
index f80a769..d04e722 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -9,6 +9,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
 
 [[package]]
+name = "anyhow"
+version = "1.0.75"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
+
+[[package]]
 name = "bitflags"
 version = "1.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -80,8 +86,7 @@ dependencies = [
 [[package]]
 name = "png"
 version = "0.17.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd75bf2d8dd3702b9707cdbc56a5b9ef42cec752eb8b3bafc01234558442aa64"
+source = "git+https://github.com/image-rs/image-png.git?rev=f10238a1e886b228e7da5301e5c0f5011316f2d6#f10238a1e886b228e7da5301e5c0f5011316f2d6"
 dependencies = [
  "bitflags",
  "crc32fast",
@@ -109,6 +114,8 @@ checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
 name = "squash"
 version = "0.1.0"
 dependencies = [
+ "anyhow",
  "camino",
+ "colorsquash",
  "png",
 ]
diff --git a/README.md b/README.md
index 0db61d0..da8832f 100644
--- a/README.md
+++ b/README.md
@@ -11,4 +11,6 @@ until it selects the necessary amount of colours.
 [^1] (wikipedia: color quantization)[https://en.wikipedia.org/wiki/Color_quantization]
 
 ### squash
-A CLI tool to quantize colours. Accepts a path to a PNG; exports an indexed PNG.
\ No newline at end of file
+A CLI tool to quantize colours :D
+
+Currently only takes PNG in the RGB colorspace and outputs indexed PNG.
\ No newline at end of file
diff --git a/squash/Cargo.toml b/squash/Cargo.toml
index 18f2be3..16c450a 100644
--- a/squash/Cargo.toml
+++ b/squash/Cargo.toml
@@ -6,5 +6,10 @@ edition = "2021"
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
+colorsquash = { path = "..", version = "0.1.0" }
+anyhow = "1.0.75"
 camino = "1.1.6"
-png = "0.17.10"
+# time of writing:
+# png has a change to ignore extra iCCP blocks my test image needed. it hasn't
+# been released yet, so we're using the git here. the commit we require is e4b4811
+png = { git = "https://github.com/image-rs/image-png.git", rev = "f10238a1e886b228e7da5301e5c0f5011316f2d6" }
diff --git a/.rustfmt.toml b/squash/src/.rustfmt.toml
index 218e203..218e203 100644
--- a/.rustfmt.toml
+++ b/squash/src/.rustfmt.toml
diff --git a/squash/src/main.rs b/squash/src/main.rs
index f328e4d..b6eb699 100644
--- a/squash/src/main.rs
+++ b/squash/src/main.rs
@@ -1 +1,87 @@
-fn main() {}
+use std::{fs::File, io::BufWriter};
+
+use anyhow::bail;
+use camino::{Utf8Path, Utf8PathBuf};
+use colorsquash::Squasher;
+use png::{ColorType, Decoder, Encoder};
+
+fn main() -> Result<(), anyhow::Error> {
+	// I should use clap or at least getopt, but this is fine. It's 20LOC.
+	let usage = || -> ! {
+		println!("usage: squash <color count> <input> <output>");
+		std::process::exit(0);
+	};
+	let mut argv = std::env::args().skip(1);
+
+	let color_count: u8 = if let Some(Ok(count)) = argv.next().map(|r| r.parse()) {
+		count
+	} else {
+		usage()
+	};
+
+	let input_path: Utf8PathBuf = if let Some(path) = argv.next() {
+		path.into()
+	} else {
+		usage();
+	};
+
+	let output_path: Utf8PathBuf = if let Some(path) = argv.next() {
+		path.into()
+	} else {
+		usage();
+	};
+
+	let mut image = get_png(input_path)?;
+
+	let squasher = Squasher::new(color_count, &image.data);
+	let size = squasher.map_over(&mut image.data);
+	image.data.resize(size, 0);
+
+	// PNG Output
+	let file = File::create(output_path)?;
+	let bufw = BufWriter::new(file);
+
+	let mut enc = Encoder::new(bufw, image.width as u32, image.height as u32);
+	enc.set_color(ColorType::Indexed);
+	enc.set_depth(png::BitDepth::Eight);
+	enc.set_palette(squasher.palette_bytes());
+	enc.write_header()?.write_image_data(&image.data)?;
+
+	Ok(())
+}
+
+fn get_png<P: AsRef<Utf8Path>>(path: P) -> Result<Image, anyhow::Error> {
+	let decoder = Decoder::new(File::open(path.as_ref())?);
+	let mut reader = decoder.read_info()?;
+
+	let mut buf = vec![0; reader.output_buffer_size()];
+	let info = reader.next_frame(&mut buf)?;
+	let data = &buf[..info.buffer_size()];
+
+	println!(
+		"{}x{} * 3 = {} | out={}, bs={}",
+		info.width,
+		info.height,
+		info.width as usize * info.height as usize * 3,
+		buf.len(),
+		info.buffer_size()
+	);
+
+	let colors = info.color_type;
+	match colors {
+		ColorType::Grayscale | ColorType::GrayscaleAlpha | ColorType::Indexed | ColorType::Rgba => {
+			bail!("colortype {colors:?} not supported")
+		}
+		ColorType::Rgb => Ok(Image {
+			width: info.width as usize,
+			height: info.height as usize,
+			data: data.to_vec(),
+		}),
+	}
+}
+
+struct Image {
+	width: usize,
+	height: usize,
+	data: Vec<u8>,
+}
diff --git a/src/lib.rs b/src/lib.rs
index a404f38..0757a03 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -174,10 +174,11 @@ impl Squasher<u8> {
     /// # Returns
     /// The new size of the image
     pub fn map_over(&self, image: &mut [u8]) -> usize {
-        for idx in 0..image.len() {
+        for idx in 0..(image.len() / 3) {
             let rgb_idx = idx * 3;
             let color = RGB8::new(image[rgb_idx], image[rgb_idx + 1], image[rgb_idx + 2]);
             let color_index = self.map[color_index(&color)];
+
             image[idx] = color_index;
         }