summaryrefslogtreecommitdiff
path: root/build.rs
blob: dda852e76a8bb4f5ffcdd13e5885f7a99ffdec38 (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
#![allow(clippy::expect_used, clippy::unwrap_used)]

use std::env;
use std::fs::File;
use std::io::BufWriter;
use std::path::Path;

fn main() {
    println!("cargo:rerun-if-changed=img/icon.svg");

    let out_dir = env::var("OUT_DIR").expect("OUT_DIR not set");
    let ico_path = Path::new(&out_dir).join("icon.ico");

    generate_ico(&ico_path);

    // Embed icon as a Windows resource when targeting Windows
    let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap_or_default();
    if target_os == "windows" {
        let mut res = winresource::WindowsResource::new();
        res.set_icon(ico_path.to_str().expect("Invalid ICO path"));
        if let Err(e) = res.compile() {
            println!("cargo:warning=Failed to embed Windows icon resource: {e}");
        }
    }
}

/// Render the SVG at multiple sizes and write an ICO file.
fn generate_ico(ico_path: &Path) {
    let svg_data = std::fs::read("img/icon.svg").expect("Failed to read img/icon.svg");

    let opt = resvg::usvg::Options::default();
    let tree =
        resvg::usvg::Tree::from_data(&svg_data, &opt).expect("Failed to parse img/icon.svg");

    let sizes: &[u32] = &[16, 32, 48, 256];
    let mut icon_dir = ico::IconDir::new(ico::ResourceType::Icon);

    for &size in sizes {
        let mut pixmap =
            resvg::tiny_skia::Pixmap::new(size, size).expect("Failed to create pixmap");

        let sx = size as f32 / tree.size().width();
        let sy = size as f32 / tree.size().height();
        let transform = resvg::tiny_skia::Transform::from_scale(sx, sy);

        resvg::render(&tree, transform, &mut pixmap.as_mut());

        let image = ico::IconImage::from_rgba_data(size, size, pixmap.data().to_vec());
        icon_dir.add_entry(
            ico::IconDirEntry::encode(&image).expect("Failed to encode ICO entry"),
        );
    }

    let file = File::create(ico_path).expect("Failed to create ICO file");
    let mut writer = BufWriter::new(file);
    icon_dir
        .write(&mut writer)
        .expect("Failed to write ICO file");
}