about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.toml3
-rw-r--r--slugs/Cargo.toml14
-rw-r--r--slugs/readme.md9
-rw-r--r--slugs/src/main.rs94
4 files changed, 119 insertions, 1 deletions
diff --git a/Cargo.toml b/Cargo.toml
index f186b67..f45abd6 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -2,5 +2,6 @@
 members = [
 	"gifed",
 	"gifprobe",
-	"gaudio"
+	"gaudio",
+	"slugs"
 ]
\ No newline at end of file
diff --git a/slugs/Cargo.toml b/slugs/Cargo.toml
new file mode 100644
index 0000000..ba4dac2
--- /dev/null
+++ b/slugs/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "slugs"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+camino = "1.1.2"
+gifed = { path = "../gifed" }
+png = "0.17.7"
+tepimg = { git = "https://github.com/gennyble/tep" }
+thiserror = "1.0.38"
+colorsquash = { path = "../../colorsquash" }
\ No newline at end of file
diff --git a/slugs/readme.md b/slugs/readme.md
index f5dbe6b..72a47ca 100644
--- a/slugs/readme.md
+++ b/slugs/readme.md
@@ -22,4 +22,13 @@ Frame frame1.tep
 Frame frame2.tep
 	Delay 2
 Frame frame3.tep
+```
+
+```kdl
+gif width=16 height=16 delay=4 {
+	palette "palette"
+	image "frame1.tep"
+	image "frame2.tep" delay=2
+	image "frame3.tep"
+}
 ```
\ No newline at end of file
diff --git a/slugs/src/main.rs b/slugs/src/main.rs
new file mode 100644
index 0000000..bdf936e
--- /dev/null
+++ b/slugs/src/main.rs
@@ -0,0 +1,94 @@
+use std::fs::File;
+
+use camino::{Utf8Path, Utf8PathBuf};
+use colorsquash::{ColorCollector, Squasher};
+use gifed::{
+	block::{extension::DisposalMethod, Palette},
+	writer::{ImageBuilder, Writer},
+	Color,
+};
+
+fn main() {
+	let base = Utf8PathBuf::from("/Users/gen/microglass-transfer/transcube");
+	let mut collector = ColorCollector::new();
+
+	let mut imgs = vec![];
+	for idx in 1..=120 {
+		let img = load_and_rgb(base.join(format!("{idx:04}.png")));
+		collector.add(&img.b);
+		imgs.push(img);
+	}
+
+	let squash: Squasher<u8> = collector.as_squasher(255);
+	let pal = squash.palette();
+	let trans_idx = pal
+		.iter()
+		.enumerate()
+		.find(|(_idx, rgb)| rgb[0] == 0 && rgb[1] == 0 && rgb[2] == 0)
+		.unwrap()
+		.0;
+
+	let mut palette = Palette::new();
+	for c in pal {
+		palette.push(Color::new(c[0], c[1], c[2]));
+	}
+	println!("{}", palette.len());
+
+	let f = File::create(base.join("transcube.gif")).unwrap();
+	let mut write = Writer::new(f, imgs[0].w as u16, imgs[1].h as u16, Some(palette)).unwrap();
+
+	for img in imgs {
+		let mut buf = vec![0; img.w as usize * img.h as usize];
+		squash.map_unsafe(&img.b, &mut buf);
+		let img = ImageBuilder::new(img.w as u16, img.h as u16)
+			.transparent_index(Some(trans_idx as u8))
+			.delay(3)
+			.disposal_method(DisposalMethod::RestoreBackground)
+			.build(buf)
+			.unwrap();
+
+		write.image(img).unwrap();
+	}
+
+	write.repeat(gifed::block::LoopCount::Forever).unwrap();
+	write.done().unwrap();
+}
+
+pub fn load_and_rgb<P: AsRef<Utf8Path>>(path: P) -> Img {
+	let decoder = png::Decoder::new(File::open(path.as_ref()).unwrap());
+	let mut reader = decoder.read_info().unwrap();
+	let mut b = vec![0; reader.output_buffer_size()];
+	let info = reader.next_frame(&mut b).unwrap();
+
+	let b = (&b[..info.buffer_size()]).to_owned();
+
+	Img {
+		b: rgba_replace_a(b, (0, 0, 0), 128),
+		w: info.width,
+		h: info.height,
+	}
+}
+
+pub fn rgba_replace_a(buf: Vec<u8>, repl: (u8, u8, u8), tol: u8) -> Vec<u8> {
+	let mut r = vec![0; (buf.len() / 4) * 3];
+
+	for (idx, px) in buf.chunks(4).enumerate() {
+		if px[3] >= tol {
+			r[idx * 3] = px[0];
+			r[idx * 3 + 1] = px[1];
+			r[idx * 3 + 2] = px[2];
+		} else {
+			r[idx * 3] = repl.0;
+			r[idx * 3 + 1] = repl.1;
+			r[idx * 3 + 2] = repl.2;
+		}
+	}
+
+	r
+}
+
+pub struct Img {
+	b: Vec<u8>,
+	w: u32,
+	h: u32,
+}