49 lines
1.9 KiB
Rust
49 lines
1.9 KiB
Rust
//! Original executable ICO encoder: DIB images and transparency masks.
|
|
use super::app_icon;
|
|
|
|
pub fn encode() -> Result<Vec<u8>, Box<dyn std::error::Error>> {
|
|
let sizes = [16usize, 24, 32, 48, 64, 128, 256];
|
|
let mut images = Vec::new();
|
|
for size in sizes {
|
|
let rgba = app_icon::rgba(size)?;
|
|
// ICO DIB: bottom-up BGRA plus a padded one-bit transparency mask.
|
|
let mask_stride = size.div_ceil(32) * 4;
|
|
let mut dib = Vec::new();
|
|
dib.extend_from_slice(&40u32.to_le_bytes());
|
|
dib.extend_from_slice(&(size as i32).to_le_bytes());
|
|
dib.extend_from_slice(&((size * 2) as i32).to_le_bytes());
|
|
dib.extend_from_slice(&1u16.to_le_bytes());
|
|
dib.extend_from_slice(&32u16.to_le_bytes());
|
|
dib.extend_from_slice(&[0; 24]);
|
|
for row in rgba.chunks_exact(size * 4).rev() {
|
|
for p in row.as_chunks::<4>().0.iter() {
|
|
dib.extend_from_slice(&[p[2], p[1], p[0], p[3]]);
|
|
}
|
|
}
|
|
for row in rgba.chunks_exact(size * 4).rev() {
|
|
let mut mask = vec![0u8; mask_stride];
|
|
for (x, p) in row.as_chunks::<4>().0.iter().enumerate() {
|
|
if p[3] == 0 {
|
|
mask[x / 8] |= 0x80 >> (x % 8);
|
|
}
|
|
}
|
|
dib.extend_from_slice(&mask);
|
|
}
|
|
images.push((size, dib));
|
|
}
|
|
let mut ico = vec![0, 0, 1, 0];
|
|
ico.extend_from_slice(&(images.len() as u16).to_le_bytes());
|
|
let mut offset = 6 + 16 * images.len();
|
|
for (size, data) in &images {
|
|
let dim = if *size == 256 { 0 } else { *size as u8 };
|
|
ico.extend_from_slice(&[dim, dim, 0, 0, 1, 0, 32, 0]);
|
|
ico.extend_from_slice(&(data.len() as u32).to_le_bytes());
|
|
ico.extend_from_slice(&(offset as u32).to_le_bytes());
|
|
offset += data.len();
|
|
}
|
|
for (_, data) in images {
|
|
ico.extend_from_slice(&data);
|
|
}
|
|
Ok(ico)
|
|
}
|