diff --git a/CHANGELOG.md b/CHANGELOG.md index 348a34dba88bbfffeaf72d9fc4d0d0d2cdcc856b..00207cd44e88572c410f69316dca85f122dcdb9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added +- Support for `--extrude` param in `extrude` command + +## [0.5.0] - 2023-02-22 +### Added +- `split` command for taking a sprite sheet and converting it into individual tiles + ### Changed - Moved all arguments into subcommands, for a less confusing end user experience diff --git a/src/commands/extrude.rs b/src/commands/extrude.rs index fdff8c9969d9c6d38cd1d263de04b11e08a746e4..1bbff08b098e26424883bf8ce4a51b1ce0e00048 100644 --- a/src/commands/extrude.rs +++ b/src/commands/extrude.rs @@ -1,8 +1,11 @@ use crate::utils::{RgbaOutputFormat, SpriteData}; use clap::Parser; -use image::{GenericImage, GenericImageView, Pixel, Rgba, RgbaImage}; +use image::flat::View; +use image::math::Rect; +use image::{DynamicImage, GenericImage, GenericImageView, Pixel, Rgba, RgbaImage}; use num_traits::cast::ToPrimitive; use serde::{Deserialize, Serialize}; +use std::ops::Deref; #[inline(always)] fn tile_size() -> u32 { @@ -44,7 +47,10 @@ pub struct Extrude { } impl Extrude { - pub fn run(&self, image: &impl GenericImage) -> anyhow::Result<RgbaOutputFormat> { + pub fn run( + &self, + image: &impl GenericImage<Pixel = Rgba<u8>>, + ) -> anyhow::Result<RgbaOutputFormat> { log::info!( "Image loaded with size {} x {}", image.width(), @@ -84,32 +90,59 @@ impl Extrude { new_width, new_height ); - let mut new_image = RgbaImage::new(new_width, new_height); - let (new_image_x, new_image_y, new_image_width, new_image_height) = new_image.bounds(); - for x in new_image_x..new_image_width { - for y in new_image_y..new_image_height { - new_image.put_pixel(x, y, Rgba::from([0, 0, 0, 0])); - } - } - + let mut new_image = RgbaImage::from_pixel(new_width, new_height, Rgba::from([0, 0, 0, 0])); for sprite in views.iter() { let (img_x, img_y, width, height) = sprite.data.bounds(); - for x in 0..width { - for y in 0..height { - let pix = sprite.data.get_pixel(x, y).to_rgba(); - let p = Rgba::from([ - pix.0[0].to_u8().unwrap(), - pix.0[1].to_u8().unwrap(), - pix.0[2].to_u8().unwrap(), - pix.0[3].to_u8().unwrap(), - ]); + let target_x = self.padding + img_x + (sprite.tx * self.space_x); + let target_y = self.padding + img_y + (sprite.ty * self.space_y); + + new_image.copy_from(sprite.data.deref(), target_x, target_y)?; - new_image.put_pixel( - self.padding + (sprite.tx * self.space_x) + img_x + x, - self.padding + (sprite.ty * self.space_y) + img_y + y, - p, - ); - } + if self.extrude { + // Left Side + new_image.copy_within( + Rect { + x: target_x, + y: target_y, + width: 1, + height, + }, + target_x.saturating_sub(1), + target_y, + ); + // Right Side + new_image.copy_within( + Rect { + x: target_x + width - 1, + y: target_y, + width: 1, + height, + }, + target_x + width, + target_y, + ); + // Top Side + new_image.copy_within( + Rect { + x: target_x, + y: target_y, + width, + height: 1, + }, + target_x, + target_y.saturating_sub(1), + ); + // Bottom Side + new_image.copy_within( + Rect { + x: target_x, + y: target_y + height - 1, + width, + height: 1, + }, + target_x, + target_y + height, + ); } } diff --git a/src/utils.rs b/src/utils.rs index edef97e1567ef32d88100ffda3625a586c67bb42..eb21cbe93e57279b23bdf0cc5b357e96bb352325 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -10,10 +10,14 @@ use lab::Lab; pub struct SpriteData<'a, T: GenericImage> { pub data: SubImage<&'a T>, #[allow(dead_code)] + /// Horizontal pixel coordinate of this sprite within the parent image pub x: u32, #[allow(dead_code)] + /// Vertical pixel coordinate of this sprite within the parent image pub y: u32, + /// "Tile X" - The horizontal grid position of this Sprite within a Spritesheet pub tx: u32, + /// "Tile Y" - The vertical grid position of this Sprite within a Spritesheet pub ty: u32, #[allow(dead_code)] pub width: u32,