use std::collections::HashMap;
use std::io::{Cursor, Read, Write};
use super::manifest::SaveBundle;
const MANIFEST_PATH: &str = "manifest.json";
const COMPOSITE_PATH: &str = "composite.png";
pub fn assemble_zip(bundle: &SaveBundle) -> Vec<u8> {
let buf = Vec::new();
let cursor = Cursor::new(buf);
let mut zip = zip::ZipWriter::new(cursor);
let options =
zip::write::SimpleFileOptions::default().compression_method(zip::CompressionMethod::Stored);
zip.start_file(MANIFEST_PATH, options).unwrap();
zip.write_all(&bundle.manifest_json).unwrap();
let composite_png = encode_rgba_as_png(
&bundle.composite_rgba,
bundle.composite_width,
bundle.composite_height,
);
zip.start_file(COMPOSITE_PATH, options).unwrap();
zip.write_all(&composite_png).unwrap();
for blob in &bundle.blobs {
zip.start_file(&blob.path, options).unwrap();
zip.write_all(&blob.bytes).unwrap();
}
let cursor = zip.finish().unwrap();
cursor.into_inner()
}
pub struct ZipEntries {
pub entries: HashMap<String, Vec<u8>>,
}
impl ZipEntries {
pub fn get(&self, path: &str) -> Option<&[u8]> {
self.entries.get(path).map(Vec::as_slice)
}
}
pub fn extract_zip(bytes: &[u8]) -> ZipEntries {
let cursor = Cursor::new(bytes);
let mut archive = zip::ZipArchive::new(cursor).unwrap();
let mut entries = HashMap::with_capacity(archive.len());
for i in 0..archive.len() {
let mut entry = archive.by_index(i).unwrap();
let path = entry.name().to_string();
let mut bytes = Vec::with_capacity(entry.size() as usize);
entry.read_to_end(&mut bytes).unwrap();
entries.insert(path, bytes);
}
ZipEntries { entries }
}
fn encode_rgba_as_png(rgba: &[u8], width: u32, height: u32) -> Vec<u8> {
let mut out = Vec::new();
let cursor = Cursor::new(&mut out);
use image::ImageEncoder;
image::codecs::png::PngEncoder::new(cursor)
.write_image(rgba, width, height, image::ExtendedColorType::Rgba8)
.unwrap();
out
}