diff --git a/Cargo.lock b/Cargo.lock index 1eface9..f473f81 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -192,7 +192,7 @@ dependencies = [ [[package]] name = "gd-icon-renderer" -version = "1.1.0" +version = "1.2.0" dependencies = [ "image", "imageproc", diff --git a/Cargo.toml b/Cargo.toml index da116fb..d9e8b7f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "gd-icon-renderer" description = "A tool to render Geometry Dash icons." -version = "1.1.0" +version = "1.2.0" edition = "2021" license-file = "LICENSE" repository = "https://git.reidlab.online/reidlab/gd-icon-renderer" diff --git a/readme.md b/readme.md index 621708d..1ed271c 100644 --- a/readme.md +++ b/readme.md @@ -42,5 +42,4 @@ Provide your `GJ_GameSheet02-uhd`, `GJ_GameSheetGlow-uhd`, `Robot_AnimDesc2`, an ## Todo - Add examples to the repo. -- Trim extra alpha space on the final result. - I think theres some weird shifting and offsets going on, please investigate 🥺. Really big on `spider_16` for some reason?? Related issue on the inspired project [here](https://github.com/oatmealine/gd-icon-renderer/issues/2). \ No newline at end of file diff --git a/src/renderer.rs b/src/renderer.rs index bc0421f..2127d15 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -123,6 +123,31 @@ fn is_black(c: [f32; 3]) -> bool { c == [0.0, 0.0, 0.0] } +fn crop_whitespace(img: DynamicImage) -> DynamicImage { + let (width, height) = img.dimensions(); + + let mut left = width; + let mut right = 0; + let mut top = height; + let mut bottom = 0; + + for x in 0..width { + for y in 0..height { + let pixel = img.get_pixel(x, y); + if pixel[3] != 0 { + left = left.min(x); + right = right.max(x); + top = top.min(y); + bottom = bottom.max(y); + } + } + } + + let cropped_image = img.clone().crop(left, top, right - left, bottom - top); + + return cropped_image +} + /// Renders out a non-robot/spider icon. You may be looking for `render_icon`. pub fn render_normal(basename: String, col1: [f32; 3], col2: [f32; 3], glow: bool, game_sheet_02: LoadedSpritesheet, game_sheet_glow: LoadedSpritesheet) -> DynamicImage { let glow_col = if is_black(col2) { if is_black(col1) { [1.0, 1.0, 1.0] } else { col1 } } else { col2 }; @@ -147,7 +172,7 @@ pub fn render_normal(basename: String, col1: [f32; 3], col2: [f32; 3], glow: boo None ]; - return render_layered( + let layered_images = render_layered( layers.iter() .filter_map(|s| s.as_ref().map(|(img, _spr)| img.to_owned())) .collect(), @@ -161,6 +186,8 @@ pub fn render_normal(basename: String, col1: [f32; 3], col2: [f32; 3], glow: boo vec![None, None, None, None, None], vec![None, None, None, None, None] ); + + return crop_whitespace(layered_images); } fn flip(scale: (f32, f32), flipped: (bool, bool)) -> (f32, f32) { @@ -221,13 +248,15 @@ pub fn render_zany(basename: String, col1: [f32; 3], col2: [f32; 3], glow: bool, .filter_map(|(opt_sprite, pos, scale, rot, glow, color)| opt_sprite.clone().map(|sprite| ((sprite.0, sprite.1), *pos, *scale, *rot, *glow, *color))) .collect::)>>(); - return render_layered( + let layered_images = render_layered( layers_r.iter().map(|t| t.0.0.clone()).collect(), layers_r.iter().map(|t| Some((t.0.1.offset.0 + t.1.0 * 4.0, t.0.1.offset.1 * -1.0 + t.1.1 * -4.0))).collect(), layers_r.iter().map(|t| t.5).collect(), layers_r.iter().map(|t| Some(t.2)).collect(), layers_r.iter().map(|t| Some(t.3 as f32)).collect() - ) + ); + + return crop_whitespace(layered_images); } /// The main entrypoint for icon rendering; this should be all you need to render out an icon.