Skip to content

Commit

Permalink
Improves DMI saving (smaller files, better formatting) (#15)
Browse files Browse the repository at this point in the history
  • Loading branch information
LemonInTheDark committed Nov 25, 2023
1 parent 90c205c commit 3374dbe
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 16 deletions.
25 changes: 20 additions & 5 deletions src/icon.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use crate::{error, ztxt, RawDmi};
use image::codecs::png;
use image::imageops;
use image::GenericImageView;
use image::ImageEncoder;
use std::collections::HashMap;
use std::io::prelude::*;
use std::io::Cursor;
Expand Down Expand Up @@ -335,23 +337,36 @@ impl Icon {

signature.push_str("# END DMI\n");

let max_index = (sprites.len() as f64).sqrt().ceil() as u32;
// We try to make a square png as output
let states_rooted = (sprites.len() as f64).sqrt().ceil();
// Then if it turns out we would have empty rows, we remove them
let cell_width = states_rooted as u32;
let cell_height = ((sprites.len() as f64) / states_rooted).ceil() as u32;
let mut new_png =
image::DynamicImage::new_rgba8(max_index * self.width, max_index * self.height);
image::DynamicImage::new_rgba8(cell_width * self.width, cell_height * self.height);

for image in sprites.iter().enumerate() {
let index = image.0 as u32;
let image = image.1;
imageops::replace(
&mut new_png,
*image,
(self.width * (index % max_index)).into(),
(self.height * (index / max_index)).into(),
(self.width * (index % cell_width)).into(),
(self.height * (index / cell_width)).into(),
);
}

let mut dmi_data = Cursor::new(vec![]);
new_png.write_to(&mut dmi_data, image::ImageOutputFormat::Png)?;
// We're futzing around with pngs directly here so we can use the best possible compression
let bytes = new_png.as_bytes();
let (width, height) = new_png.dimensions();
let color = new_png.color();
let encoder = png::PngEncoder::new_with_quality(
&mut dmi_data,
png::CompressionType::Default,
png::FilterType::Adaptive,
);
encoder.write_image(bytes, width, height, color)?;
let mut new_dmi = RawDmi::load(&dmi_data.into_inner()[..])?;

let new_ztxt = ztxt::create_ztxt_chunk(signature.as_bytes())?;
Expand Down
18 changes: 18 additions & 0 deletions tests/dmi_ops.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use dmi::icon::Icon;
use std::fs::File;
use std::path::PathBuf;

#[test]
fn load_and_save_dmi() {
let mut load_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
load_path.push("tests/resources/load_test.dmi");
let load_file =
File::open(load_path.as_path()).unwrap_or_else(|_| panic!("No lights dmi: {load_path:?}"));
let lights_icon = Icon::load(&load_file).expect("Unable to load lights dmi");
let mut write_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
write_path.push("tests/resources/save_test.dmi");
let mut write_file = File::create(write_path.as_path()).expect("Failed to create dmi file");
let _written_dmi = lights_icon
.save(&mut write_file)
.expect("Failed to save lights dmi");
}
11 changes: 0 additions & 11 deletions tests/load_dmi.rs

This file was deleted.

Binary file added tests/resources/save_test.dmi
Binary file not shown.

0 comments on commit 3374dbe

Please sign in to comment.