1.4 KiB · text History af1c436
//! Writing icons out as Android mipmap resources.

use std::path::{Path, PathBuf};

use crate::render;
use crate::spec::IconSpec;

/// Android adaptive icons are 108dp; these are the density buckets and the
/// pixel size each works out to.
pub const DENSITIES: &[(&str, u32)] = &[
    ("mdpi", 108),
    ("hdpi", 162),
    ("xhdpi", 216),
    ("xxhdpi", 324),
    ("xxxhdpi", 432),
];

fn write_png(pm: &tiny_skia::Pixmap, path: &Path) -> Result<(), String> {
    if let Some(dir) = path.parent() {
        std::fs::create_dir_all(dir).map_err(|e| format!("{}: {e}", dir.display()))?;
    }
    pm.save_png(path)
        .map_err(|e| format!("{}: {e}", path.display()))
}

/// Writes `ic_icon`, `ic_icon_background` and `ic_icon_foreground` into
/// `res/mipmap-*` under `root`, matching the layout the cbz apps ship.
pub fn export_mipmaps(
    spec: &IconSpec,
    root: &Path,
    base_name: &str,
) -> Result<Vec<PathBuf>, String> {
    let mut written = Vec::new();
    for (bucket, size) in DENSITIES {
        let dir = root.join(format!("mipmap-{bucket}"));
        for (suffix, pm) in [
            ("", render::render_composed(spec, *size)),
            ("_background", render::render_background(spec, *size)),
            ("_foreground", render::render_foreground(spec, *size)),
        ] {
            let p = dir.join(format!("{base_name}{suffix}.png"));
            write_png(&pm, &p)?;
            written.push(p);
        }
    }
    Ok(written)
}