use base64::Engine;
use std::path::Path;
use tracing::warn;
pub const MAX_ICON_BYTES: u64 = 1024 * 1024;
pub fn mime_from_extension(path: &Path) -> &'static str {
match path.extension().and_then(|e| e.to_str()) {
Some("svg") => "image/svg+xml",
Some("ico") => "image/x-icon",
Some("jpg") | Some("jpeg") => "image/jpeg",
Some("webp") => "image/webp",
Some("gif") => "image/gif",
_ => "image/png",
}
}
pub fn to_data_url(mime: &str, bytes: &[u8]) -> Option<String> {
if bytes.len() as u64 > MAX_ICON_BYTES {
warn!("图标超过 {} 字节上限,忽略", MAX_ICON_BYTES);
return None;
}
Some(format!(
"data:{};base64,{}",
mime,
base64::engine::general_purpose::STANDARD.encode(bytes)
))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn mime_from_extension_covers_known_and_unknown() {
assert_eq!(
mime_from_extension(Path::new("a/b/icon.svg")),
"image/svg+xml"
);
assert_eq!(mime_from_extension(Path::new("icon.ico")), "image/x-icon");
assert_eq!(mime_from_extension(Path::new("icon.jpeg")), "image/jpeg");
assert_eq!(mime_from_extension(Path::new("icon.webp")), "image/webp");
assert_eq!(mime_from_extension(Path::new("icon.gif")), "image/gif");
assert_eq!(mime_from_extension(Path::new("icon.bmp")), "image/png");
assert_eq!(mime_from_extension(Path::new("icon")), "image/png");
}
#[test]
fn to_data_url_encodes_bytes_and_rejects_oversize() {
assert_eq!(
to_data_url("image/svg+xml", b"<svg/>").as_deref(),
Some("data:image/svg+xml;base64,PHN2Zy8+")
);
let oversize = vec![0u8; MAX_ICON_BYTES as usize + 1];
assert!(to_data_url("image/png", &oversize).is_none());
}
}