Newer
Older
#[inline(always)]
fn tile_size() -> u32 {
32
}
/// Take each tile in an image and expand its borders by a given amount. Optionally fill with
/// nearby pixels instead of empty space
#[derive(Parser, Serialize, Deserialize, Clone, Debug)]
#[clap(author, version = "0.3.0")]
pub struct Extrude {
/// The path to the spritesheet file
#[serde(default)]
pub input: String,
/// The path to write the extruded spritesheet
#[serde(default)]
pub output: String,
/// The amount of horizontal space to add between each sprite in the image
#[clap(short = 'x', long, default_value_t = 0)]
/// The amount of vertical space to add between each sprite in the image
#[clap(short = 'y', long, default_value_t = 0)]
/// The amount of padding to add around the edge of the spritesheet
#[clap(short, long, default_value_t = 0)]
/// The size of each tile in the spritesheet. Assumed to be square tiles
#[clap(short, long, default_value_t = 32)]
#[serde(default = "tile_size")]
tile_size: u32,
/// Use nearby pixels for spacing
#[clap(short, long)]
#[serde(default)]
extrude: bool,
}
impl Extrude {
pub fn run(
&self,
image: &impl GenericImage<Pixel = Rgba<u8>>,
) -> anyhow::Result<RgbaOutputFormat> {
log::info!(
"Image loaded with size {} x {}",
image.width(),
image.height()
);
let columns = image.width() / self.tile_size;
let rows = image.height() / self.tile_size;
log::info!("Inferred sheet contains {} columns", columns);
log::info!("Inferred sheet contains {} rows", rows);
let mut views = Vec::with_capacity((columns * rows) as usize);
for x in 0..columns {
for y in 0..rows {
let img_x = x * self.tile_size;
let img_y = y * self.tile_size;
let payload = SpriteData {
data: image.view(img_x, img_y, self.tile_size, self.tile_size),
x: img_x,
y: img_y,
tx: x,
ty: y,
width: self.tile_size,
height: self.tile_size,
};
let new_width = (self.padding * 2 + self.space_x * columns) + image.width();
let new_height = (self.padding * 2 + self.space_y * rows) + image.height();
log::info!(
"Using new image width {} / height {}",
new_width,
new_height
);
let mut new_image = RgbaImage::from_pixel(new_width, new_height, Rgba::from([0, 0, 0, 0]));
let (width, height) = sprite.data.dimensions();
let (img_x, img_y) = sprite.data.offsets();
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)?;
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
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,
);