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

Re: Crop sprites for minimal spritesheet size

Post by darkfrei »

GeeMack wrote: 2018-01-17T13:37:28-07:00
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 "%%".
This code

Code: Select all

magick "Input/*.png" -background rgba(0,0,0,0) ^
   ( -clone 0--1 -layers merge -set option:cropper "%%[@]" +delete ) ^
   -crop %%[cropper] Output\spritesheet_2x2.png
Pause
makes very nice result! With "+append" I get one line spritesheet.
Is it possible to merge them into spritesheet, for example, 2x2 sprites?
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:49:08-07:006. Making new spritesheet with new cropped sprites from fifth stage.
Take a look at the parts of this command...

Code: Select all

magick sprite*.png -background none ^
   ( -clone 0--1 -layers merge ^
   -set option:cropper "%[@]" +delete ) ^
   -crop %[cropper] +repage ^
   MIFF:- | magick montage MIFF:- ^
   -background none -tile 8x8 -geometry +0+0 outsprites.png
Each line number does just a few things...

1. Read in all the "sprite*.png" images, and set the background color to "none".

2. Inside the parentheses make a copy of them all, stack them, and flatten them to one layer.

3. Get the crop information from the FX expression "%[@]" which calculates the values same as if you used "-trim" to remove all the excess blank space, but it doesn't have to actually trim them. The variable "%[cropper]" will now contain something like this: "105x51+23+29". Since you don't need that cloned flattened image after this, "+delete" it.

4. Use that variable "%[cropper]" to crop all the images to the same dimensions and offsets. The "+repage" resets all their page geometries to HxW+0+0.

5. Instead of outputting an image, you output ImageMagick's special format MIFF. That way you can pipe the whole stack of cropped sprite pieces to your "montage" command. Use "magick montage MIFF:-" after the pipe to move those images into your "montage" command.

6. Set the background, tile arrangement, and geometry. Give it an output file name, and it's done.

The result should be a sprite sheet with all the images in a grid, all the same sizes and orientations, but without any unneeded transparent space surrounding them.

If you're using a command like that in a BAT script, you need to make all the percent signs "%" into 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 »

Thanks GeeMack, it works just perfect!

Code: Select all

magick "Input/*.png" -background none ^
   ( -clone 0--1 -layers merge ^
   -set option:cropper "%%[@]" +delete ) ^
   -crop %%[cropper] +repage ^
   MIFF:- | magick montage MIFF:- -background none ^
   -tile 2x2 -geometry +0+0 Output\best_spritesheet_2x2.png
One click, all done.

Is it possible to take dimensions of %[cropper] and use it as filename?
And what in this code brackets do?
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-17T14:39:30-07:00Is it possible to take dimensions of %[cropper] and use it as filename?
You can do that sort of thing with "magick", but not with the "montage" tool. There are ways to use "magick" to build your sprite sheet without using "montage". It's easiest if you know how many pieces you'll use and what the layout will be.

Let's say you have 64 sprites and you want an image with 8 columns and 8 rows. A command like this would do that...

Code: Select all

magick sprite*.png -background none ^
   ( -clone 0--1 -layers merge -set option:cropper "%[@]" +delete ) ^
   -crop %[cropper] +repage -set filename:f "mysprites_%[cropper]" ^
   +append -crop 8x1@ -append +repage "%[filename:f].png"
After cropping all the pieces to their trimmed size it sets a special variable "filename:f" to include that "%[cropper]" variable.

Next it attaches all the images horizontally with "+append". Then it crops that into 8 sections wide and 1 high with "8x1@". It attaches those 8 pieces vertically with "-append", and writes the output with a name like "mysprites_105x51+23+29.png".
And what in this code brackets do?
Square brackets "[...]" are used with percent signs "%" to hold variables and math functions and such. Parentheses "(...)" can contain operations that are isolated from the rest of the command. Instructions for using them can be found at THIS LINK.
User avatar
anthony
Posts: 8883
Joined: 2004-05-31T19:27:03-07:00
Authentication code: 8675308
Location: Brisbane, Australia

Re: Crop sprites for minimal spritesheet size

Post by anthony »

I do not know if this will be useful to this discussion, as I can't find any link to a set of example images to try it on.

Have you looked at... -layers trim-bounds This takes images with virtual offsets, and ignores the existing 'canvas' size.
It then sets all the images so they have the same sized MINIMAL virtural canvas, with and appropriate offset (relative to each other) so they still layer together properly (if flattened on top of each other), onto that minimal canvas. I made this command for exactly this situation. trimming a group of images without actually merging all the images. In fact it is exactly the same code as the '-merge' operator, but without doing the final merge!
http://www.imagemagick.org/Usage/anim_mods/#trim

After this you can use a special trick to flatten each individual frame, so as to 'pad out' the virtual canvas into a real canvas of this 'minimal size'
using -dispose Background -coalesce
See http://www.imagemagick.org/Usage/layers/#coalesce

So try this..

Code: Select all

convert  sprite*.png -layers trim-bounds -dispose  Background -coalesce +append  sprite_sheet.png
Optionally if the is wasted real canvas space in the images add a -trim to crop the real canvas in the images first.

Code: Select all

convert  sprite*.png -trim -layers trim-bounds -dispose  Background -coalesce +append  sprite_sheet.png
Or pipe the images into montage to tile it

Code: Select all

convert  sprite*.png -trim -layers trim-bounds -dispose  Background -coalesce miff:- |
   montage - -tile 8x -geometry +0+0 sprite_sheet.png
Anthony Thyssen -- Webmaster for ImageMagick Example Pages
https://imagemagick.org/Usage/
Post Reply