Files

49 lines
1.6 KiB
Rust

//! Regenerate the PNG and multi-resolution Windows ICO from the editable SVG.
use image::codecs::ico::{IcoEncoder, IcoFrame};
use std::{error::Error, fs::File};
fn main() -> Result<(), Box<dyn Error>> {
let tree = resvg::usvg::Tree::from_data(
include_bytes!("../assets/icon.svg"),
&resvg::usvg::Options::default(),
)?;
let mut frames = Vec::new();
for size in [16, 24, 32, 48, 64, 128, 256, 512] {
let mut pixmap = resvg::tiny_skia::Pixmap::new(size, size).ok_or("invalid size")?;
resvg::render(
&tree,
resvg::tiny_skia::Transform::from_scale(size as f32 / 512.0, size as f32 / 512.0),
&mut pixmap.as_mut(),
);
// tiny-skia stores premultiplied pixels; PNG and ICO need straight alpha.
let mut rgba = pixmap.take();
for pixel in rgba.as_chunks_mut::<4>().0 {
let alpha = pixel[3] as u32;
for channel in &mut pixel[..3] {
*channel = (*channel as u32 * 255 + alpha / 2)
.checked_div(alpha)
.unwrap_or(0)
.min(255) as u8;
}
}
if size == 512 {
image::save_buffer(
"assets/icon.png",
&rgba,
size,
size,
image::ColorType::Rgba8,
)?;
} else {
frames.push(IcoFrame::as_png(
&rgba,
size,
size,
image::ExtendedColorType::Rgba8,
)?);
}
}
IcoEncoder::new(File::create("assets/icon.ico")?).encode_images(&frames)?;
Ok(())
}