about summary refs log tree commit diff
path: root/slugs/src/main.rs
blob: bdf936e39f6009f2156acd3e626c5d252de23626 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
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,
}