I want to scale the sprite 8x with padding between pixels - imagemagick

There is a small sprite:
# mario sprite in base64 writing to file:
magick 'inline:data:image/png;base64,
iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAA7EAAAO
xAGVKw4bAAAA00lEQVQ4ja1UwRGDMAyTe7zLJmWUzMoodBO6gHmkhsRWcukVvYID
kiKbiKoqbsTjTjIAmLq7IvXzwGHahJ5sUKBJKKhf3rcVAPB8pZ5BTihyEcxLomuD
Fxhqyryk06WtDZ93LSB+bMqYvBtPBsQYA2FP3YPl2XUIAIpcsCZ5eRM18slvALyL
CoFAu5EApCn7tsbx+hY0U55llmkYG7NefuhzKAVFUv1Mm8L+EgKWa5zDQbIWqiNn
riuvID8g1r4c2Hi6Ghvg6sg/mqEIDv+9v2+/sQ8vtmAvY/Wf0QAAAABJRU5ErkJg
gg==' mario.png
I want to scale it 8x:
convert -scale 800% -quality 100 mario.png mario-big.png
But scale with padding between pixels. To have an indent of 1 pixel between four adjacent eight times larger pixels. Or overlay a grid over the enlarged image.
How can I do this, please tell me?
Example:

As an alternative approach, how about using -fx to make a grid? For example:
convert -size 64x64 canvas: -fx "i % 9 == 0 | j % 9 == 0" x.png
Will set a pixel white when either the column (that's i) or row number (that's j) is on a multiple of 9. I see:
Now using Mark's suggestion, just expand your sprite by 9 with nearest neighbor, then use a ternary operator to pick either the image (image pixels are u) or white (1.0):
convert mario.png \
-scale 900% \
-fx "(i % 9 == 0 | j % 9 == 0) ? 1.0 : u" \
result.png
With this test image:
I see:
It'll work for any size image, though it'll be pretty slow if the image is large.

Updated Answer
I'm not sure how to change the 2px spacing to 1px in my original answer. Here's another method which we can probably speed up and improve if it gets the results you want. I'm using my image below as it's a an easier size to see, but you can adjust the numbers to match your own image. I am also using the "wrong" colours so you can see where each one ends up, but again, you can change my mad colours to white:
Chop into rows, each row being 50px tall
Iterate over rows, chopping each into 50px wide chunks and recombining with 1px yellow spacing
Smush the new rows together vertically with 1px cyan spacing
The code looks like this:
#!/bin/bash
# Chop into rows, each row being 50px tall
magick artistic-swirl.jpg -crop x50 row-%02d.png
# Iterate over rows, chopping each into 50px wide chunks and recombining with 1px spacing
for f in row-*png ; do
echo $f
magick "$f" -crop 50x -background yellow +smush 1 "$f"
done
# Smush the new rows together vertically with 1px spacing
magick row-*png -background cyan -smush 1 result.png
Note that +smush N joins images side-by-side with N px spacing in the background colour, but that -smush N joins images above-and-below with N px spacing.
Here's what I get applying that to your image:
#!/bin/bash
# Chop into rows, each row being 50px tall
magick mario.png -scale 800% -crop x8 row-%02d.png
# Iterate over rows, chopping each into 50px wide chunks and recombining with 1px spacing
for f in row-*png ; do
echo $f
magick "$f" -crop 8x -background yellow +smush 1 "$f"
done
# Smush the new rows together vertically with 1px spacing
magick row-*png -background cyan -smush 1 -bordercolor blue -border 1 result.png
Original Answer
Not at a computer to test, but if you scale your image up to the correct size as you are currently doing, you should then be able to crop the image into tens/hundreds of individual 8x8 images and pipe them to a montage command to lay them out on a white background with a 1px spacing between all the individual 8x8 blocks.
Something like:
magick 'inline:data:...' -scale 800% -crop 8x8 miff:- | magick montage -background white -geometry +1+1 -tile Nx miff:- result.png
where N is the number of 8x8 blocks you want in each row.
Note that miff:- is an ImageMagick internal lossless transmission format.
Back at a computer, I'll do something similar with this image:
magick artistic-swirl.jpg -scale 500x500 -crop 50x50 miff:- | magick montage -background yellow -geometry +5+5 -tile 10x miff:- result.png

Related

ImageMagick count how many identical or almost identical color pixels are vertically by x coordinate

I have this image:
I need to count how many red pixels there are vertically on x 60 which would be the red line on the right containing 4 pixels.
I tried this:
img.png -alpha off -fuzz 2% -fill white -opaque "#FF0000" -fill black +opaque white -gravity west -crop 61x+0+0 -format "%[fx:round(mean*w*h)]\n" info:
but it also counts all the red pixels left to x 60
Try:
magick ... -crop 1x+61+0 ...
to crop a full-height, 1px wide column starting at 61,0.

ImageMagick count how many identical or almost identical color pixels are on the edges left and right of image

This is an example PNG image:
it's 50x40 but enlarged here to see it better.
The hex of bottom left and bottom right pixels is F9E4B7
I need to know how many pixels there are on vertical edges from the bottom left and right with almost this color, like 1% fuzz because they are not all exactly F9E4B7 but some are very slightly different.
In this case it would be 20px of each side:
I'll mark the areas which need to be counted just to make it perfectly clear:
I also need to be able to count how many pixels are exactly F9E4B7, which in this case would be 15 left and 20 right, I'll mark the slightly different areas so it's clear where the counter needs to stop:
The way to do that in Imagemagick is to use fuzz to change all your pixels close to that color to white and the rest black. The crop the first or last column and use -fx to get the count from mean*width*height. So for example for the left full column of the whole image, one has
Unix Imagemagick 6 syntax:
convert tan.png -alpha off \
-fuzz 1% -fill white -opaque "#F9E4B7" -fill black +opaque white \
-gravity west -crop 1x+0+0 -format "%[fx:round(mean*w*h)]\n" info:
Windows Imagemagick Syntax:
convert tan.png -alpha off ^
-fuzz 1% -fill white -opaque "#F9E4B7" -fill black +opaque white ^
-gravity west -crop 1x+0+0 -format "%[fx:round(mean*w*h)]\n" info:
Result:
108
To get the right side, use -gravity east.
For exact count, use -fuzz 0
For Imagemagick 7, change convert to magick

Relative imagemagick transforms: Relative Crop?

I'm trying to execute the following set of transformations without knowing the absolute width or height of the target image:
1. Crop image A by 10px on every size :: A1
2. Create duplicate of A1 translating image by 1270px on the y-axis :: A2
3. Create montage of A1 && A2 :: A3
4. Translate A3 by 385px on the y-axis :: A4
5. Crop A4 at 100% width, and 1270px tall (box from 0,0 to WIDTH,1270) :: A5
My issue is how do I do steps 1 and 5 with relative coordinates? Below are my steps that I've come up with:
1. convert A.jpg -shave 10x10 A1.jpg
2. convert A1.jpg -page +0-1270 -background none -flatten A2.jpg
3. montage A1.jpg A2.jpg -geometry +0+0 A3.jpg
4. convert A3.jpg -page +0-385 -background none -flatten A4.jpg
5. convert A4.jpg ????? A5.jpg
Updated Answer
Ok, I think I understand what you want a bit better now. Here's how I would do it:
convert start.jpg -crop +0+383 +repage \
\( -clone 0 -crop x1270+0+0 \) \
\( -clone 0 -crop x1270+0+1270 \) \
-delete 0 +append result.jpg
The first line says..."Take the starting image and crop off the top 383 pixels and reset all the sizes to match what is left. Call that the first image from now onwards."
The second line says..."To one side (because of the parentheses), clone the first image and crop out the full width and 1270 pixels in height from the top. Hold onto that till later - i.e. keep it in the image list.".
The third line says..."To one side (because of the parentheses), clone the first image, and crop out a piece the full width and 1270 pixels in height, but start 1270 pixels from the top. Hold onto that till later - i.e. keep it in the image list."
The last line says..."Delete the initial image, and then take the two slices in the image list and append them side-by-side, Save as result.jpg".
Original Answer
I think we will need to work together on this one, but it can be done. Let's start with a concrete image that is a 400x250 gradient with a 15px black border:
convert -size 250x400 gradient:red-cyan -rotate 90 -bordercolor black -border 15 A.png
So, step 1.
convert A.png -shave 10x10 A1.png
Step 2&3. I don't get the point of these! You appear to be trying to add transparent space to a JPEG which doesn't support transparency. Also, I can't tell what you are montaging where. Please try and express what you want with these two steps in plain English, like "add a transparent area N pixels wide/tall above/below, left/right of A2", or maybe "add a transparent area such that the new dimensions are X,Y and the original A2 image is at the bottom-right of the new canvas."
If I have a stab at steps 2&3, I'll guess this (and add a purple border so you can see it on StackOverflow's white background). I am appending a transparent area 1270 pixels tall below the image.
convert A.png -background none -shave 10x10 xc:none[1x1270\!] -append b.png
Step 4&5. As above.
Or maybe you mean this:
convert A.png -background magenta -shave 10x10 -gravity southeast -extent 1270x385 result.png
I think we can get you down to a single command, with no intermediate files, if we understand your needs.

Cleaning the left side of an image

Using imagemagick, I want to clean the left side of an image, i.e. make white without cropping. For example cleaning the left-most vertical strip of 25 pixels wide. I figured out how to crop to a given geometry, but I couldn't figure out how to clean without cropping.
Here is my start image, made like this:
convert -size 256x256 gradient:cyan-yellow image.png
Method 1
One way to do it would be to use -fx and set all pixels where the x-coordinate is less than 25 to 1.0 (i.e. white) and leave all other pixels as they are:
convert image.png -fx "i<25?1:u" result.png
Method 2
Another, faster way to do it might be to clone the original image, and scale it down to 25 pixels wide, fill it with white and composite that over the original image:
convert image.png \
\( +clone -scale 25x! -fill white -colorize 100 \) \
-composite result.png
The result is the same.
Method 3
A third way to do it might be to crop the image 25 pixels in from the left side, then splice 25 white pixels back on the left side:
convert image.png -crop +25+0 -background white -gravity west -splice 25x result.png
Method 4
Bit of a kludge, but nearer to what you asked. Here, I guess that your image height doesn't exceed 10,000 pixels and draw a rectangle:
convert image.png -fill white -draw "rectangle 0,0 24,9999" result.png
I guess the proper way to do this is to get the height first then use it:
#!/bin/bash
h=$(convert image.png -format "%[fx:h-1]" info:)
convert image.png -fill white -draw "rectangle 0,0 24,$h" result.png

Imagemagick montage 3x3 spacing 1px

I want to merge 9 images using imagemagicks convert into 3x3 tiles with a 1px spacing between the tiles.
In my other, bigger version of the resulting image I have a spacing of 2px. To achieve this I've added a border of 1px to every image, and after the image has been created I'm using crop to strip the outer border.
Is there an easy way to get just 1px spacing between the tiles, unfortunately a border of 0.5px doesn't work.
The best.
Your method is similar to that used by the montage program, which has the same limitation that you found. In order to get 1px spacing between tiles, you will need a little bit more involved of a convert command. The method used here first builds the rows of the resulting image, then sticks them together, then cuts out border pixels that we don't want.
convert \( 0.png 1.png 2.png -splice 1x +append \) \
\( 3.png 4.png 5.png -splice 1x +append \) \
\( 6.png 7.png 8.png -splice 1x +append \) \
-splice x1 -append -chop 1x1 \
out.png
In more detail:
Each parenthesized subgroup says to add a column of width 1 to the left side of each image in the subgroup. The first image in the subgroup gets a column added, too, so we will clean this up at the end. We then append the images of our row horizontally, and then do the same for the second and third row.
After building our rows, we use splice to add a 1 pixel row to the top of our three rows, and append vertically.
At this point, we almost have the image we want, but we have a 1 pixel border on the left and on the top that we need to get rid of, so that is what that final -chop is for.
Hope this helps.

Resources