image
| Language | Rust |
|---|---|
| License | MIT or Apache 2.0 |
| Repository | github.com/image-rs/image |
| Documentation | image::codecs::ico on docs.rs |
| Depends on | pure Rust (png crate for PNG entries); the ico feature is on by default |
| Read / write | yes (largest entry only) / yes, PNG entries, several frames |
The image crate treats ICO as one more format: image::open("app.ico") returns a DynamicImage of the best entry (largest area, then highest bit depth). It decodes BMP and PNG entries. You can’t pick another entry through the crate; use the ico crate for that.
For writing, IcoEncoder::encode_images takes a list of IcoFrames, so you can resize one image to several sizes with image’s own resize functions and write a multi-size icon in a few lines. Frames are PNG-encoded (or you pass pre-encoded PNG/BMP bytes), and each must be 1 to 256 pixels wide and high.
Installation#
Shell
cargo add image
Basic usage: convert ICO to PNG#
Rust
fn main() -> Result<(), image::ImageError> {
let img = image::open("app.ico")?; // largest entry
println!("{} x {}", img.width(), img.height());
img.save("app.png")?;
Ok(())
}
How to create a multi-size favicon.ico from one image#
Rust
use image::codecs::ico::{IcoEncoder, IcoFrame};
use image::imageops::FilterType;
use image::ExtendedColorType;
use std::fs::File;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let logo = image::open("logo.png")?;
let mut frames = Vec::new();
for size in [256u32, 48, 32, 16] {
let rgba = logo.resize_exact(size, size, FilterType::Lanczos3).to_rgba8();
frames.push(IcoFrame::as_png(rgba.as_raw(), size, size, ExtendedColorType::Rgba8)?);
}
IcoEncoder::new(File::create("favicon.ico")?).encode_images(&frames)?;
Ok(())
}
How to save a single-size ICO#
save picks the encoder from the extension and writes one entry. The image must be 256x256 or smaller:
Rust
let img = image::open("logo.png")?;
img.resize(256, 256, image::imageops::FilterType::Lanczos3).save("app.ico")?;
How to get the icon size without decoding#
Rust
let (w, h) = image::image_dimensions("app.ico")?; // size of the largest entry
Tips#
IcoFrame::with_encodedtakes already encoded PNG or BMP data, for BMP entries or PNGs from your own optimizer.- The decoder ignores the CUR hotspot; a
.curfile decodes like an icon when you load it withImageFormat::Ico.