ico 0.5.0

A library for encoding/decoding ICO image files
Documentation
use clap::{App, Arg, SubCommand};
use std::fs;
use std::path::PathBuf;

//===========================================================================//

fn main() {
    let matches = App::new("icotool")
        .version("0.1")
        .author("Matthew D. Steele <mdsteele@alum.mit.edu>")
        .about("Manipulates ICO files")
        .subcommand(
            SubCommand::with_name("create")
                .about("Creates an ICO file from PNG files")
                .arg(
                    Arg::with_name("output")
                        .takes_value(true)
                        .value_name("PATH")
                        .short("o")
                        .long("output")
                        .help("Sets output path"),
                )
                .arg(Arg::with_name("image").multiple(true)),
        )
        .subcommand(
            SubCommand::with_name("extract")
                .about("Extracts icons from an ICO file")
                .arg(
                    Arg::with_name("output")
                        .takes_value(true)
                        .value_name("PATH")
                        .short("o")
                        .long("output")
                        .help("Sets output path"),
                )
                .arg(Arg::with_name("ico").required(true))
                .arg(Arg::with_name("index").required(true)),
        )
        .subcommand(
            SubCommand::with_name("list")
                .about("Lists icons in an ICO file")
                .arg(Arg::with_name("ico").required(true)),
        )
        .get_matches();
    if let Some(submatches) = matches.subcommand_matches("create") {
        let out_path = if let Some(path) = submatches.value_of("output") {
            PathBuf::from(path)
        } else {
            let mut path = PathBuf::from("out.ico");
            let mut index: i32 = 0;
            while path.exists() {
                index += 1;
                path = PathBuf::from(format!("out{}.ico", index));
            }
            path
        };
        let mut icondir = ico::IconDir::new(ico::ResourceType::Icon);
        if let Some(paths) = submatches.values_of("image") {
            for path in paths {
                println!("Adding {:?}", path);
                let file = fs::File::open(path).unwrap();
                let image = ico::IconImage::read_png(file).unwrap();
                icondir.add_entry(ico::IconDirEntry::encode(&image).unwrap());
            }
        }
        let out_file = fs::File::create(out_path).unwrap();
        icondir.write(out_file).unwrap();
    } else if let Some(submatches) = matches.subcommand_matches("extract") {
        let path = submatches.value_of("ico").unwrap();
        let file = fs::File::open(path).unwrap();
        let icondir = ico::IconDir::read(file).unwrap();
        let index = submatches.value_of("index").unwrap();
        let index = index.parse::<usize>().unwrap();
        let image = icondir.entries()[index].decode().unwrap();
        let out_path = if let Some(path) = submatches.value_of("output") {
            PathBuf::from(path)
        } else {
            PathBuf::from(format!("{}.{}.png", path, index))
        };
        let out_file = fs::File::create(out_path).unwrap();
        image.write_png(out_file).unwrap();
    } else if let Some(submatches) = matches.subcommand_matches("list") {
        let path = submatches.value_of("ico").unwrap();
        let file = fs::File::open(path).unwrap();
        let icondir = ico::IconDir::read(file).unwrap();
        println!("Resource type: {:?}", icondir.resource_type());
        for (index, entry) in icondir.entries().iter().enumerate() {
            let kind = if entry.is_png() { "PNG" } else { "BMP" };
            let suffix = if let Some((x, y)) = entry.cursor_hotspot() {
                format!("hotspot at ({}, {})", x, y)
            } else {
                format!("{} bpp", entry.bits_per_pixel())
            };
            println!(
                "{:5}: {}x{} {}, {}",
                index,
                entry.width(),
                entry.height(),
                kind,
                suffix
            );
        }
    }
}

//===========================================================================//