123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110 |
- use failure::Error;
- use image;
- use serde_json;
- use std::io::{Read, Write, Seek};
- use zip::{ZipArchive, ZipWriter};
- /// This value represents both the current document in-memory as well
- /// as the entirety of the values that we will want to both save and
- /// restore.
- pub struct Document {
- pub tilesheet: image::DynamicImage,
- pub metadata: Metadata,
- pub rules: (),
- }
- /// This should be renamed probably, but it's the configuration-level
- /// info about a document (e.g. the tile size)
- #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
- pub struct Metadata {
- pub tile_width: u16,
- pub tile_height: u16,
- pub config_loop_forever: bool,
- }
- impl Document {
- /// Attempt to read a `Document` from anything which implements
- /// `Read` and `Seek`. The file format for Palladio files is
- /// documented externally.
- pub fn open_from_file<R: Read + Seek>(r: &mut R) -> Result<Document, Error> {
- let mut archive = ZipArchive::new(r)?;
- let tilesheet = {
- let mut buf = Vec::new();
- archive.by_name("tilesheet.png")?.read_to_end(&mut buf)?;
- image::load_from_memory(&buf)?
- };
- let metadata = {
- let file = archive.by_name("metadata.json")?;
- serde_json::from_reader(file)?
- };
- let rules = {
- let file = archive.by_name("rules.json")?;
- serde_json::from_reader(file)?
- };
- Ok(Document{ tilesheet, metadata, rules })
- }
- /// Attempt to write a `Document` from anything which implements
- /// `Write` and `Seek`. The file format for Palladio files is
- /// documented externally.
- pub fn save_to_file<W: Write + Seek>(&self, w: &mut W) -> Result<(), Error> {
- use zip::write::FileOptions;
- let mut zip = ZipWriter::new(w);
- zip.start_file("tilesheet.png", FileOptions::default())?;
- self.tilesheet.write_to(&mut zip, image::ImageOutputFormat::PNG)?;
- zip.start_file("metadata.json", FileOptions::default())?;
- serde_json::to_writer(&mut zip, &self.metadata)?;
- zip.start_file("rules.json", FileOptions::default())?;
- serde_json::to_writer(&mut zip, &self.rules)?;
- zip.start_file("info.txt", FileOptions::default())?;
- writeln!(
- &mut zip,
- "Created by {} v{}",
- ::constants::PROGRAM_NAME,
- ::constants::PROGRAM_VERSION,
- )?;
- zip.finish()?;
- Ok(())
- }
- /// Create a new fresh document with an empty 32x32 image, a
- /// configured tile size of 16x16, and no rules
- pub fn default() -> Document {
- Document {
- tilesheet: image::DynamicImage::new_rgb8(32, 32),
- metadata: Metadata {
- tile_width: 16,
- tile_height: 16,
- config_loop_forever: false,
- },
- rules: (),
- }
- }
- }
- #[cfg(test)]
- mod tests {
- use super::Document;
- use std::io::{BufReader, Cursor};
- #[test]
- fn round_trip() {
- // First, save our dummy `Document` to an in-memory buffer
- let mut buf = Cursor::new(Vec::new());
- let doc1 = Document::default();
- doc1.save_to_file(&mut buf).unwrap();
- // then take that buffer back, and reparse it
- let buf = buf.into_inner();
- let doc2 = Document::open_from_file(&mut BufReader::new(Cursor::new(buf))).unwrap();
- // we can't assert equality over the image itself, so let's
- // just assert that the other parts are equal
- assert!(doc1.metadata == doc2.metadata);
- assert!(doc1.rules == doc2.rules);
- }
- }
|