Crop sprites for minimal spritesheet size

Questions and postings pertaining to the usage of ImageMagick regardless of the interface. This includes the command-line utilities, as well as the C and C++ APIs. Usage questions are like "How do I use ImageMagick to create drop shadows?".
darkfrei
Posts: 15
Joined: 2018-01-16T11:47:26-07:00
Authentication code: 1152

Crop sprites for minimal spritesheet size

Post by darkfrei »

Hi all!

I have some sprites, for example 128x128 (or 256x256) pixels.
Image

If I have 8 sprites, I can make this spritesheet with only one command:

Code: Select all

montage "Input_Folder/*.png" -geometry +0+0 -tile 8x -background rgba(0,0,0,0) -quality 100% Output_Folder\spritesheet_8x_128.png
Image

As you can see, here is too much borders with alpha = 100%.
Image

Is it possible to make the mask and crop all alpha borders from this sprites?

If I put all sprites together,

Code: Select all

convert "Input/*.png" -background none -flatten musk.png
then it looks like (added white):
Image

In this case I get image 207x97 (complete without alpha borders) and here was top left pixel {49, 61}. (added white)

Code: Select all

convert musk.png -trim musk_trim.png
Image

Then cut all sprites with this musk. Save it, then montage with the command above.
And result looks like:
Image

With white background:
Image

For this 8 images I need about 15 minutes. But I have every spritesheet with 128 or 256 sprites and I want make it automatically.

Version: ImageMagick-7.0.5-4-portable-Q16-x64
Last edited by darkfrei on 2018-01-16T15:24:55-07:00, edited 5 times in total.
darkfrei
Posts: 15
Joined: 2018-01-16T11:47:26-07:00
Authentication code: 1152

Re: Crop sprites for minimal spritesheet size

Post by darkfrei »

As you can see, dimension of the cropped spritesheet is much less.
Image and Image
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Crop sprites for minimal spritesheet size

Post by fmw42 »

Sorry, I do not understand the question. How are you getting an image that is too large? What was your command?

If I take your one sprite and duplicated two more times and run

Code: Select all

magick montage "test/*.png" -geometry +0+0 -tile 3x -background none spritesheet_3x_128.png
I get a resulting image that is 384 x 128 pixels. Just the correct size it should be.

If then add -trim +repage, I get

Code: Select all

magick montage "test/*.png" -trim +repage -geometry +0+0 -tile 3x -background none spritesheet_3x_128b.png
which is 312 x 46 pixels.

This is done using IM 7.0.7.21 Q16 Mac OSX Sierra.

Is that what you want?
darkfrei
Posts: 15
Joined: 2018-01-16T11:47:26-07:00
Authentication code: 1152

Re: Crop sprites for minimal spritesheet size

Post by darkfrei »

If I put all my sprites together, it looks like:
Image

As you see, here is a lot free space, while all sprites have same dimension: 256x256 pixels. So, if I make only one spritesheet, it will be 4096x4096. It's too much.
I want to cut (or crop) all sprites so, that they have so less as you can, but with same center and with same size.
Image
Image

That means, that I need one sum of this pictures, find alpha borders and crop same borders from all sprites before. And than I can make spritesheet like before with montage.
darkfrei
Posts: 15
Joined: 2018-01-16T11:47:26-07:00
Authentication code: 1152

Re: Crop sprites for minimal spritesheet size

Post by darkfrei »

This code

Code: Select all

montage "Input/*.png" -trim +repage -geometry +0+0 -tile 8x -background none spritesheet_8x_128b.png
makes not-same-dimension-spritesheet:
Image

So must it be:
Image
User avatar
GeeMack
Posts: 718
Joined: 2015-12-01T22:09:46-07:00
Authentication code: 1151
Location: Central Illinois, USA

Re: Crop sprites for minimal spritesheet size

Post by GeeMack »

darkfrei wrote: 2018-01-16T13:40:59-07:00Is it possible to make the mask and crop all alpha borders from this sprites?
You can layer all the individual pieces onto a transparent background and find the common trim geometry with "%[@]". Then you can crop all the pieces to that geometry and attach them together with "+append". A command like this might get you started in the right direction...

Code: Select all

magick "Input_Folder/*.png" -background rgba(0,0,0,0) ^
   ( -clone 0--1 -layers merge -set option:cropper "%[@]" +delete ) ^
   -crop %[cropper] +append Output_Folder\spritesheet_8x_128.png
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Crop sprites for minimal spritesheet size

Post by fmw42 »

I still do not understand your issue. Do you want the montage to be 8x8 without specifying other than 8x. This works fine for me in IM 7.0.7.21 Q16 Mac OSX. Perhaps you need to upgrade IM.

Code: Select all

magick montage "test/sprite1.png" -duplicate 63 -trim +repage -geometry +0+0 -tile 8x -background none spritesheet_8x.png
Image


Be sure to use "magick montage" in IM 7 rather than just "montage", which is an IM 6 command
darkfrei
Posts: 15
Joined: 2018-01-16T11:47:26-07:00
Authentication code: 1152

Re: Crop sprites for minimal spritesheet size

Post by darkfrei »

You are making nice spritesheet with perfect grid with same sprites. It's not a problem for me too.

I'm using ImageMagick-7.0.5-4-portable-Q16-x64 (it's portable version) and all commands without "magick" are working great.

I have another example. I have a spritesheet 2x2 with sprites 256x256:
Image

I crop it with a command

Code: Select all

convert spritesheet.png -crop 256x256  +repage  +adjoin  sprite_n.png
I'm making sprites, then a mask from this sprites:

Code: Select all

convert "sprite_n*.png" -background none -flatten mask.png
Image

Then I want to crop all sprites with this mask, all sprites after cropping must have same sizes and same center. Output image looks like:
Image

As you can see, here is nice grid without gravity correction, it's very easy to use it for any animation.
Output sprites are all 168x119 (same size like mask without alpha border),
Image
Image

Output spritesheet is exact 336x238: two times wider and two times higher than mask after cropping.
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Crop sprites for minimal spritesheet size

Post by fmw42 »

Your numbers do not make sense to me. The output sprites are 256x256. When you flatten them, they are still 256x256. You say the bounding box is 168x119 and then you say the output is 335x238. I do not understand these numbers.

Which output do you want? The 4x4 grid of sprites or an animated image of the flattened sprites.

Please clarify.

Try

Code: Select all

convert spritesheet.png -crop 256x256 +repage \
-gravity center -crop 168x168+0+0 +repage miff:- | \
montage - -tile 2x2 -geometry +0+0 -background none \
spritesheet2.png
Image

If I try the above with the second crop at 168x119, then it cuts off part of the sprites. Also if I trim and extent to 336x238 it also crops off part of the image.
User avatar
GeeMack
Posts: 718
Joined: 2015-12-01T22:09:46-07:00
Authentication code: 1151
Location: Central Illinois, USA

Re: Crop sprites for minimal spritesheet size

Post by GeeMack »

darkfrei wrote: 2018-01-17T10:58:18-07:00Output spritesheet is exact 336x238: two times wider and two times higher than mask after cropping.
What problems did you encounter when you tried my suggestion above?
darkfrei
Posts: 15
Joined: 2018-01-16T11:47:26-07:00
Authentication code: 1152

Re: Crop sprites for minimal spritesheet size

Post by darkfrei »

I want to get just one script. This script takes sprites and makes a mask, from this mask we can get how big alpha borders we have.
This alpha borders are marked here as red:
Image
If we have this alpha borders, it will be very easy to crop all previous sprites with the same size.

Your script has line:

Code: Select all

-gravity center -crop 168x168+0+0 +repage miff:- | \
The problem that we don't know what size are we need before. We are need to get this "168x168" (in this case 168x119, see bounding rectangle size of selected part of mask) automatically.

I can all basics, but here are we need functions:
1. We have sprites.
2. Making mask from this sprites. This mask is a picture with the same size as all sprites.
3. Get alpha borders from this mask: We are need left and top pixels, that we are using by crop function.
4. Get mask size: We can get wight and high of mask, where alpha is less than 100%.
5. Crop all sprites from first stage. Just call crop function with parameters wightxhigh+left+top.
6. Making new spritesheet with new cropped sprites from fifth stage.
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Crop sprites for minimal spritesheet size

Post by fmw42 »

Your red image is 256x256. Is that correct for what you want? How do you know where to put the trimmed flattened images (in white) inside the red larger 256x256 box? How would this help you crop the original image from the mask. You do not know the relative positions of the mask in relation to your original grid of sprites? I am still confused. I still do not understand your size requirements for the mask and for the final grid of sprites.

What are the command you have tried for your steps 1-6? Perhaps that will help us understand what you are trying to do.
darkfrei
Posts: 15
Joined: 2018-01-16T11:47:26-07:00
Authentication code: 1152

Re: Crop sprites for minimal spritesheet size

Post by darkfrei »

GeeMack wrote: 2018-01-17T12:57:02-07:00
darkfrei wrote: 2018-01-17T10:58:18-07:00Output spritesheet is exact 336x238: two times wider and two times higher than mask after cropping.
What problems did you encounter when you tried my suggestion above?
ImageMagick>magick convert "Input\*.png" -background rgba(0,0,0,0) ( -clone 0--1 -layers merge -set option:cropper "[@]" +delete ) -crop [cropper] +append Output\cropped_GeeMack.png
convert: invalid argument for option '-crop': [cropper] @ error/convert.c/ConvertImageCommand/1206.
User avatar
GeeMack
Posts: 718
Joined: 2015-12-01T22:09:46-07:00
Authentication code: 1151
Location: Central Illinois, USA

Re: Crop sprites for minimal spritesheet size

Post by GeeMack »

darkfrei wrote: 2018-01-17T13:17:33-07:00ImageMagick>magick convert "Input\*.png" -background rgba(0,0,0,0) ( -clone 0--1 -layers merge -set option:cropper "[@]" +delete ) -crop [cropper] +append Output\cropped_GeeMack.png
convert: invalid argument for option '-crop': [cropper] @ error/convert.c/ConvertImageCommand/1206.
If you're using that command in a BAT script you need to make every percent sign "%" into a double percent sign "%%".
darkfrei
Posts: 15
Joined: 2018-01-16T11:47:26-07:00
Authentication code: 1152

Re: Crop sprites for minimal spritesheet size

Post by darkfrei »

fmw42 wrote: 2018-01-17T13:08:16-07:00 Your red image is 256x256. Is that correct for what you want?
My red image is a mask, where all alpha borders are marked as red, but it's 0,0,0,255. You cant see alpha channel and I'm just marked it.
fmw42 wrote: 2018-01-17T13:08:16-07:00 How do you know where to put the trimmed flattened images (in white) inside the red larger 256x256 box? How would this help you crop the original image from the mask. You do not know the relative positions of the mask in relation to your original grid of sprites? I am still confused. I still do not understand your size requirements for the mask and for the final grid of sprites.

What are the command you have tried for your steps 1-6? Perhaps that will help us understand what you are trying to do.
I'm making mask just with one command:

Code: Select all

convert "sprite_n*.png" -background none -flatten mask.png
As you can see, this mask is just all sprites that we have. I don't want to trim this mask, but I want to take all properties from this trim function (new size and position of the image where it was before) and crop all sprites with this properties (-crop _wight_x_high_+_left_+_top_.).

1. We have sprites.
This sprites I get after rendering in blender 3D. They are always same, but I don't see shadows before I render it.


2. Making mask from this sprites. This mask is a picture with the same size as all sprites.

Code: Select all

convert "sprite_n*.png" -background none -flatten mask.png

3. Get alpha borders from this mask: We are need left and top pixels, that we are using by crop function.

Code: Select all

magick identify mask.png
pause
mask.png PNG 256x256 256x256+0+0 8-bit Grayscale Gray 5.48KB 0.000u 0:00.000


4. Get mask size: We can get wight and high of mask, where alpha is less than 100%.

Code: Select all

convert  mask.png -trim  info:-
pause
mask.png PNG 168x119 256x256+44+89 8-bit Gray 0.000u 0:00.006


5. Crop all sprites from first stage. Just call crop function with parameters wightxhigh+left+top.
-- I don't know how to get 168x119 and 44+89 from it.

Code: Select all

convert sprite_n*.png -crop 168x119+44+89  +repage  +adjoin  sprite_crop.png
-- here 168x119+44+89 must be taked from step 4, I don't know how


6. Making new spritesheet with new cropped sprites from fifth stage.

Code: Select all

montage "sprite_crop*.png" -geometry +0+0 -tile 2x2 -background rgba(0,0,0,0) -quality 100% Output\spritesheet_2x2.png
Post Reply