sg-sprite 0.3.2

Application for restoring Mages engine sprites (Steins;Gate, Steins;Gate 0, Chaos;Child)
Documentation
use super::*;
use image::{
    self, imageops, DynamicImage, GenericImage, GenericImageView, ImageBuffer, Pixels, Rgba,
    RgbaImage,
};
use std::format as fmt;
use std::fs::File;
use std::io::{BufReader, Read};
use std::path::Path;

pub const BLOCK_W: u32 = 32;
pub const BLOCK_H: u32 = 32;
pub const CANVAS_PAD_W: u32 = 0;
pub const CANVAS_PAD_H: u32 = 0;

pub struct DrawPrep {
    img: DynamicImage,
}

pub fn draw_prep(img: &Path) -> Result<DrawPrep, SgSpriteErr> {
    eprint!("draw: decode");
    Ok(DrawPrep { img: image::open(img)? })
}

pub fn draw_sprites(
    src: &mut DrawPrep,
    png_out: impl AsRef<Path>,
    sprites: &[&Sprite],
    pass: usize,
    lay: &ParsedLay,
) -> Result<(), SgSpriteErr> {
    macro_rules! status { ($($e:tt)*) => {
    eprint!("\rdraw {:02}: {}", pass, format_args!($($e)*));
  }}
    status!("");

    let (x_mid, y_mid) = lay.sprite_xy_min;
    let x_mid = x_mid.abs();
    let y_mid = y_mid.abs();

    status!("canvas");
    let mut canvas = ImageBuffer::from_pixel(
        lay.sprite_w + CANVAS_PAD_W,
        lay.sprite_h + CANVAS_PAD_H,
        Rgba([0, 0, 0, 0]),
    );

    let mut chunk_count = 0usize;

    for s in sprites.iter().rev() {
        let chunks = &lay.chunks[s.chunk_offset..][..s.chunk_count];

        for c in chunks.iter() {
            status!("{} chunks", chunk_count + 1);

            let (cx, cy) = ((x_mid + c.img_x) as u32, (y_mid + c.img_y) as u32);
            let (sx, sy) = (c.chunk_x as u32 - 1, c.chunk_y as u32 - 1);
            let mut dst_chunk = imageops::crop(&mut canvas, cx, cy, BLOCK_W, BLOCK_H);
            let src_chunk = imageops::crop(&mut src.img, sx, sy, BLOCK_W, BLOCK_H);

            imageops::replace(&mut dst_chunk, &src_chunk, 0, 0);
            chunk_count += 1;
        }
    }

    eprint!(", encoding: ");
    canvas.save(png_out)?;

    eprintln!("done");
    Ok(())
}