49 lines
1.6 KiB
Rust
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(())
|
|
}
|