Search code examples
imagemagick

Crop the result of a tile?


I'm dumping images from an old game, and for whatever reason they come divided in chunks of 64x64. I tile them to make up the 640x512 picture, fix the alpha, and then I need to crop off some dummy pixel rows from the bottom so that it is 640x480.

Thing is, I can't seem to make the crop work correctly. How do I make the crop apply over the result of this, and have it all be in a single command?

magick montage -tile 10x8 -geometry +0+0 -alpha off *.png out.png

I'm on 7.1.0 on W11.


Solution

  • Let's make 4 circular gradients for illustration:

    magick -size 100x100 radial-gradient:magenta-black -duplicate 3 %d.png
    

    Here they are:

    -rw-r--r--     1 mark  staff     20307 12 Mar 08:28 0.png
    -rw-r--r--     1 mark  staff     20307 12 Mar 08:28 1.png
    -rw-r--r--     1 mark  staff     20307 12 Mar 08:28 2.png
    -rw-r--r--     1 mark  staff     20307 12 Mar 08:28 3.png
    

    And they all look the same:

    enter image description here


    If you do this:

    magick montage -geometry +0+0 ?.png result.png 
    

    You get:

    enter image description here


    If you do this:

    magick montage -geometry +0+0 ?.png -crop 50x50+0+0 result.png
    

    You get the following and you can see it did the cropping prior to montaging:

    enter image description here


    But if you montage the images together and send the result in a MIFF "Magick Image File Format" (which can contain any number of layers and any number of bit-depths) to a further instance of magick and crop it there:

    magick montage -geometry +0+0 ?.png MIFF:- | magick MIFF:- -crop 200x125+0+0 result.png
    

    You get:

    enter image description here

    Note that you can, in this instance, replace MIFF:- with PNG:- if you don't understand the need for it - it would come into its own with a 64-bit TIFF for example, where an intermediate 16-bit PNG would be unable to retain all information between the two stages.


    I'm hoping you asked for a single command because you don't want to write to disk, although you didn't say why, and if so, this solution achieves that. If the reason was different, please explain and I will provide a different solution.


    If you really, really only want to use a single process for some reason, you can use a "magick script" like this.

    First put all the commands you want in a script file, and name it say croppedMontage.mgk:

    ( 0.png 1.png +append )     # append 0.png and 1.png across page to make a row
    ( 2.png 3.png +append )     # append 2.png and 3.png across page to make a row
    -append                     # vertically stack all previously created rows down the page
    -crop 200x125+0+0           # crop result of stacking all rows
    -write result.png
    

    Then invoke it with:

    magick -script croppedMontage.mgk
    

    enter image description here

    Note that you could do the above on the command-line without a script, but I didn't do that because the number of files you have is a bit unwieldy and the quoting is ugly. It would look like this though:

    magick \
       \( 0.png 1.png +append \) \
       \( 2.png 3.png +append \) \
       -append -crop 200x125+0+0 result.png
    

    Note that quoting is different in Windows where you want:

    magick ^
       ( 0.png 1.png +append ) ^
       ( 2.png 3.png +append ) ^
       -append -crop 200x125+0+0 result.png
    

    So that's maybe yet another reason to prefer the script approach.