#[must_use]
pub fn detect_mime_type(bytes: &[u8]) -> &'static str {
if bytes.starts_with(b"\x89PNG\r\n\x1a\n") {
return "image/png";
}
if bytes.starts_with(b"\xFF\xD8") {
return "image/jpeg";
}
if bytes.starts_with(b"GIF87a") || bytes.starts_with(b"GIF89a") {
return "image/gif";
}
if bytes.starts_with(b"BM") {
return "image/bmp";
}
if bytes.starts_with(b"RIFF") && bytes.len() >= 12 && &bytes[8..12] == b"WEBP" {
return "image/webp";
}
if bytes.starts_with(b"%PDF") {
return "application/pdf";
}
if bytes.starts_with(b"PK\x03\x04") {
if bytes.len() >= 50 {
let central_dir = &bytes[30..bytes.len().min(50)];
if central_dir.windows(6).any(|w| w == b"word/") {
return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
}
if central_dir.windows(3).any(|w| w == b"xl/") {
return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
}
if central_dir.windows(4).any(|w| w == b"ppt/") {
return "application/vnd.openxmlformats-officedocument.presentationml.presentation";
}
}
return "application/zip";
}
if bytes.starts_with(b"<?xml") {
return "application/xml";
}
if bytes.starts_with(b"<svg") || bytes.starts_with(b"<!DOCTYPE svg") {
return "image/svg+xml";
}
if bytes.starts_with(b"{") || bytes.starts_with(b"[") {
return "application/json";
}
"application/octet-stream"
}
#[must_use]
pub fn vec_to_data_uri(bytes: &[u8]) -> String {
let mime_type = detect_mime_type(bytes);
vec_to_data_uri_with_mime(bytes, mime_type)
}
#[must_use]
pub fn vec_to_data_uri_with_mime(bytes: &[u8], mime_type: &str) -> String {
let mut data_url = format!("data:{mime_type};base64,");
base64::Engine::encode_string(
&base64::engine::general_purpose::STANDARD,
bytes,
&mut data_url,
);
data_url
}
#[must_use]
pub fn vec_to_data_uri_value(bytes: &[u8]) -> serde_json::Value {
serde_json::Value::String(vec_to_data_uri(bytes))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_detect_mime_type() {
assert_eq!(detect_mime_type(&[]), "application/octet-stream");
assert_eq!(detect_mime_type(b"\x89PNG\r\n\x1a\n"), "image/png");
assert_eq!(detect_mime_type(b"\xFF\xD8\xFF\xE0"), "image/jpeg");
assert_eq!(detect_mime_type(b"GIF87a"), "image/gif");
assert_eq!(detect_mime_type(b"GIF89a"), "image/gif");
assert_eq!(detect_mime_type(b"BM\x00\x00"), "image/bmp");
assert_eq!(detect_mime_type(b"%PDF-"), "application/pdf");
assert_eq!(
detect_mime_type(b"<svg xmlns=\"http://www.w3.org/2000/svg\">"),
"image/svg+xml"
);
assert_eq!(
detect_mime_type(b"<?xml version=\"1.0\"?><root><data>test</data></root>"),
"application/xml"
);
assert_eq!(
detect_mime_type(b"{\"key\": \"value\"}"),
"application/json"
);
assert_eq!(detect_mime_type(b"PK\x03\x04"), "application/zip");
assert_eq!(
detect_mime_type(&[0x00, 0x01, 0x02, 0x03]),
"application/octet-stream"
);
}
#[test]
fn test_vec_to_data_uri() {
let result = vec_to_data_uri(&[]);
assert_eq!(result, "data:application/octet-stream;base64,");
let result = vec_to_data_uri(b"Hello World");
assert_eq!(
result,
"data:application/octet-stream;base64,SGVsbG8gV29ybGQ="
);
let binary_data = [0, 1, 2, 255, 254, 253];
let result = vec_to_data_uri(&binary_data);
assert_eq!(result, "data:application/octet-stream;base64,AAEC//79");
}
#[test]
fn test_vec_to_data_uri_with_mime() {
let result = vec_to_data_uri_with_mime(b"Hello", "text/plain");
assert_eq!(result, "data:text/plain;base64,SGVsbG8=");
let result = vec_to_data_uri_with_mime(&[255, 216, 255], "image/jpeg");
assert_eq!(result, "data:image/jpeg;base64,/9j/");
let result = vec_to_data_uri_with_mime(&[], "application/json");
assert_eq!(result, "data:application/json;base64,");
}
#[test]
fn test_vec_to_data_uri_value() {
let result = vec_to_data_uri_value(b"test");
match result {
serde_json::Value::String(s) => {
assert_eq!(s, "data:application/octet-stream;base64,dGVzdA==");
}
_ => panic!("Expected String value"),
}
}
}