use std::io::{Cursor, Write};
use crate::svg::{SvgParser, SvgRasterizer};
use super::png_writer::to_png;
pub const DEFAULT_SIZES: [u32; 6] = [16, 32, 48, 64, 128, 256];
pub fn to_zip(svg: &str, sizes: &[u32]) -> Vec<u8> {
let sizes = if sizes.is_empty() { &DEFAULT_SIZES } else { sizes };
let doc = SvgParser::parse(svg);
let mut buf = Vec::new();
{
let cursor = Cursor::new(&mut buf);
let mut zip = zip::ZipWriter::new(cursor);
let options = zip::write::SimpleFileOptions::default()
.compression_method(zip::CompressionMethod::Deflated);
for size in sizes {
let pixmap = SvgRasterizer::rasterize(&doc, *size).expect("favicon PNG 光栅化失败");
let png = to_png(&pixmap);
zip.start_file(format!("avatar-{}.png", size), options)
.expect("zip 条目创建失败");
zip.write_all(&png).expect("zip 写入失败");
}
zip.finish().expect("zip 收尾失败");
}
buf
}
pub fn to_ico(svg: &str, sizes: &[u32]) -> Vec<u8> {
let sizes = if sizes.is_empty() { &DEFAULT_SIZES } else { sizes };
let doc = SvgParser::parse(svg);
let pngs: Vec<Vec<u8>> = sizes
.iter()
.map(|size| {
let pixmap = SvgRasterizer::rasterize(&doc, *size).expect("ICO PNG 光栅化失败");
to_png(&pixmap)
})
.collect();
let mut offset: u32 = 6 + 16 * sizes.len() as u32; let mut bos = Vec::with_capacity(offset as usize + 64 * 1024);
write_le16(&mut bos, 0);
write_le16(&mut bos, 1);
write_le16(&mut bos, sizes.len() as u16);
for (i, size) in sizes.iter().enumerate() {
let s = *size;
bos.push(if s >= 256 { 0 } else { s as u8 }); bos.push(if s >= 256 { 0 } else { s as u8 }); bos.push(0); bos.push(0); write_le16(&mut bos, 1); write_le16(&mut bos, 32); write_le32(&mut bos, pngs[i].len() as u32); write_le32(&mut bos, offset); offset += pngs[i].len() as u32;
}
for png in &pngs {
bos.extend_from_slice(png);
}
bos
}
fn write_le16(out: &mut Vec<u8>, v: u16) {
out.push((v & 0xFF) as u8);
out.push((v >> 8) as u8);
}
fn write_le32(out: &mut Vec<u8>, v: u32) {
out.push((v & 0xFF) as u8);
out.push((v >> 8) as u8);
out.push((v >> 16) as u8);
out.push((v >> 24) as u8);
}