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
|
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>,
}
|