I want to have a background image with another image composited over top to the bottom edge. The final image will have maximum width (say, 1000px, but may be less). The composited image can shrink in width but always needs to be at the bottom. I can't seem to find a way get this all done in one command with imagemagick.
Here is some dummy images as an example.
Image to composite over the background:
Here are two examples of end products I want:
This one is 960px wide, but yet the composited image is flush bottom and left/right edge.
This one is quite narrow, but the composited image has shrunk to make it flush bottom/left/right.
Since the images may vary in size and aspect ratio, I'd rather not have to do some sort of external calculation to scale and position the composited image. I feel like this should be possible within imagemagick, right?
It would be easiest to identify the width of background image beforehand.
#!/bin/bash
# Get background width
WIDTH=`convert background.jpg -format "%w" info:`
# Apply composite
convert background.jpg \
\( arrows.png -resize "${WIDTH}x" \) \
-alpha set \
-gravity South \
-compose ATop \
-composite output.png
The \( arrows.png -resize "${WIDTH}x" \) is a subprocess for matching widths, and -gravity South will keep the arrows anchored to the bottom.
Related
I have an image, 5120 × 4352 that I crop into 2048x2048 tiles. I want to name my cropped tiles like
tile_0_0.png
tile_0_1.png
tile_0_2.png
tile_1_0.png
tile_1_1.png
tile_1_2.png
...
But this command:
convert image.png -crop 2048x2048 -gravity northwest \
-extent 2048x2048 -transparent white \
-set 'filename:tile' '%[fx:page.x/2048]_%[fx:page.y/2048]' \
+repage +adjoin 'tile_%[filename:tile].png'
Gives me this result:
tile_0_0.png
tile_0_1.png
tile_0_16.png
tile_1_0.png
tile_1_1.png
tile_1_16.png
tile_4_0.png
tile_4_1.png
tile_4_16.png
I suspect it has do with the tiles on the last row and column aren't fully 2048x2048, but the extent command makes the end result still 2048, but how can I use this with tiles and file names?
My current workaround is to first resize the original image like this, and then run the above command:
convert image.png -gravity northwest \
-extent 2048x2048 -transparent white bigger.png
But it would be nice to do it in one swoop :)
Using ImageMagick you could set a viewport that is just enough larger than the input image so it divides evenly by 2048. Then a no-op distort will enlarge the viewport to that size. That way the "-crop 2048x2048" will create pieces that are already 2048 square.
Here's a sample command I worked up in Windows, and I'm pretty sure I translated it to work correctly as a *nix command.
convert image.png \
-set option:distort:viewport '%[fx:w-(w%2048)+2048]x%[fx:h-(h%2048)+2048]' \
-virtual-pixel none -distort SRT 0 +repage -crop 2048x2048 \
-set 'filename:tile' '%[fx:page.x/2048]_%[fx:page.y/2048]' \
+repage +adjoin 'tile_%[filename:tile].png'
The "-distort SRT" operation does nothing except expand the viewport to dimensions that divide evenly by 2048, with a result just like doing an "-extent" before the crop. And "-virtual-pixel none" will leave a transparent background in the overflow areas.
Edited to add: The formula for extending the viewport in the above command will incorrectly add another 2048 pixels even if the dimension is already divisible by 2048. It also gives an incorrect result if the dimension is less than 2048. Consider using a formula like this for setting the viewport to handle those conditions...
'%[fx:w+(w%2048?2048-w%2048:0)]x%[fx:h+(h%2048?2048-h%2048:0)]'
I am trying to place a rotated image onto a blank canvas.
This is the command i am using:
convert "(" -size 1000x1000 xc:transparent ")" "(" "img.jpg" -virtual-pixel white -rotate -10.75 ")" -geometry +136+148 -composite "overlay.png" -geometry +0+0 -composite out.png
I would expect the image to appear at +136+148 rotated around its center. However, it appears to be rotated around its upper right corner instead.
I confirmed this in Photoshop:
This is the resulting image (using slightly different size but same parameters as my example command given here):
The 4 lines are the guides that mark the coordinates that define where the image sits. As you can see, the image is rotated -10.75 degrees. And the rotation center is the upper right corner.
Here i select the box at the correct coordinates in Photoshop:
And here i rotate it after setting the rotation point to the top right:
As you can see, the selection now matches the image as it was calculated by my convert command.
I have tried dealing with this for many hours. I tried switching to +distort and -distort and what not, but there i simply get either a cropped image or another wrongly positioned bounding box.
I don't know how to address this problem. What am i doing wrong? How can i tell -rotate to rotate my image around its center, not around the top right corner (why top right anyway?).
Thank you for your help!
The default gravity for offsetting is the northwest corner or top-left corner. The geometry offset you are using moves the top left corner of the padded rotated image after its background has been added and not the top left corner of the where the Input gets rotated. So I think that may be why you are not getting the expected result. ImageMagick -rotate does rotate about its center, but it fills the background out to make a complete rectangular image that is the bounding rectangle about the rotated image.
In ImageMagick, a better approach to what you did would be to use -gravity center and align the center of the rotated input image with the center of the transparent region in the overlay image.
Alternately, measure the 4 corners of your transparent region in the overlay and 4 corners of the input image and do a perspective or affine distortion to align the two.
Here is how to do it in bash unix syntax.
over1="122,186"
over2="466,118"
over3="510,345"
over4="166,411"
WxH=`convert -ping "Image.jpg" -format "%wx%h" info:`
ww=`echo "$WxH" | cut -dx -f1`
hh=`echo "$WxH" | cut -dx -f2`
ww=$((ww-1))
hh=$((hh-1))
in1="0,0"
in2="$ww,0"
in3="$ww,$hh"
in4="0,$hh"
convert overlay.png \
\( Image.jpg -virtual-pixel none +distort Perspective \
"$in1 $over1 $in2 $over2 $in3 $over3 $in4 $over4" \) \
-layers merge +repage \
out.png
See https://imagemagick.org/Usage/distorts/#perspective
Try using the offset geometry that aligns with the outer edges of your target area. That would be more along the red lines I've added here, not along the cyan lines in your example image.
Edited to add: For a method of finding the proper offset information to fill the hole and placing the image under the hole, see my other answer in this thread.
You can find the location of the cutout in your overlay image, then use that information to properly place your under image with a command like this...
convert overlay.png -background none \
\( +clone -alpha extract -trim \
-set option:offset +%[fx:page.x]+%[fx:page.y] +delete \) \
\( image.jpg -rotate -10.7 -set page %[offset] \) \
-set page %[fx:u.w]x%[fx:u.h] +swap -layers merge result.png
This makes use of the fact that the bounding box dimensions of the rotated input image are the same as the bounding box dimensions of the cutout of the transparent region in the overlay image.
That reads in the overlay, and inside parentheses it makes a clone of it, extracts the alpha channel, and trims the result to find the offset of the cutout. It saves the offset to a variable named "offset".
Then inside another set of parentheses it reads in the under image, rotates it the known -10.7 degrees, and uses that variable "offset" to set the paging offset on the rotated "image.jpg".
Then outside the parentheses it uses the width and height of the overlay to set the paging dimensions for the under image.
It finishes by swapping the order of the images to put the overlay on top, then merging the two layers to create the output.
Here is an alternate to GeeMack's excellent ImageMagick solution. This computes the center of the original input.jpg, and the center of the transparent region in the Overlay.png. Then it uses +distort SRT to translate and rotate the image before finally compositing with -layers merge.
convert Overlay.png \
\( +clone -alpha extract -trim -set option:center "%[fx:page.x+w/2],%[fx:page.y+h/2]" +delete \) \
\( Image.jpg -virtual-pixel none +distort SRT "%[fx:w/2],%[fx:h/2] 1 -10.7 %[center]" \) \
+swap -layers merge +repage result2.png
The second line is much line GeeMack's, but it computes the center of the transparent region's bounding box and saves that in the "center" argument and then deletes the trimmed image.
The third line computes the center of the Input.jpg image (before rotation). It then uses +distort SRT to translate from the input center, (scale=1) and rotate -10.7 and translate to the center of the transparent region's bounding box.
See https://imagemagick.org/Usage/distorts/#srt
I have an image of 4500x5400, I want to resize it for the height 4200 keeping the width ratio, however the width of the image needs to be 4050, leaving the sides transparent.
I have this ImageMagick command:
convert file.png -resize 4500x5400 -gravity center -background transparent -extent 4050x4200 out.png
However it's cutting the top and the bottom, while it needs to appear.
Do you guys have any idea of how I can make it work?
Appreciate your time!
Try this...
convert input.png -resize 4050x4200 -background none -gravity center -extent 4050x4200 output.png
The "-resize" fits your input image within a container of that size. The "-extent" makes sure the total canvas is that size. The "-background" and "-gravity" make sure extra space is filled with transparent and that the input image is located in the center of the output canvas.
I have used the following imagemagick command for the image below:
convert img.png -define morphology:compose=darken -morphology Thinning Rectangle:17x1+0+0\< tmp.png
This removes ALL lines from the image, but I just want to remove the small horizontal and vertical lines on the right and bottom of the number in top left corner of each block. I want to preserve the main column and row lines. Can anyone tell me how to do it?
This is what I get (notice the long lines dividing the image content into columns and rows are also gone. I want those line to stay):
I notice the script is finer/thinner and less regular than the lines so it is more susceptible to eroding techniques. With that in mind we can ditch the text like this:
convert vcards.png -colorspace gray -threshold 50% -morphology erode disk:1.5 +repage z1.png
That's a good start, but if we use that as a mask, we will lose the long horizontal lines in your original image. So, we can find all those by projecting all the rows into a single-pixel wide tall column and thresholding all the rows that are more than 80% white. Then widen the image back out to its original width.
convert z1.png -colorspace gray -resize 1x\! +repage -threshold 80% -scale 810x1518\! +repage z2.png
Now combine the two masks so they only do the lower and right sides of your little title box things.
convert z1.png \( z2.png -negate \) -compose darken -composite z3.png
Finally, fatten that mask up a bit because it may have shifted around during previous processing, and apply it to your original image.
convert vcards.png \( z3.png -morphology dilate disk:2 -negate \) -compose darken -composite result.png
It could all be combined into a single command, but I won't do that, because some aspects may not work for all your images and while they are all individually implemented and documented, they are simpler to improve or correct individually.
you can use the followin code for horizontal an change it slightly for vertical lines
magick 21.gif -monochrome ( +clone -negate -statistic median 219x1 ) -compose lighten -composite q1.png
I have an overlay image, which is like a watermark/logo, which needs to be overlayed on top of the source image (while preserving alpha channel, etc)
When overlay is the same or smaller dimension as the source image - things are easy:
composite.exe -alpha on -gravity center logo.png in_image.jpg out_image.jpg
However, when logo.png is larger than in_image.jpg - above call truncates the logo, and out_image.jpg has the same dimensions as in_image.jpg
I would like the resulting image to be the largest of either the logo.png or in_image.jpg so I can do things like artistic frames around the photos.
Below image demonstrates the end result I want to be able to get this:
Desired Result
Note, here, the png with skulls has larger dims than the kiddo's image. The alpha channel needs to be preserved.
Edit: more clarity through examples
Here is another desired result
Here, the png file is opaque on the sides, has a clear window in the middle, and half-translucent bubbles. the JPG file is just a regular JPG from a camera.
Would love to add original and logo files that result in it, but lack reputation to add more than 2 links (or to add images)
Updated Answer
If you have v7 of ImageMagick, you can get it to do the maths for you all in one line using -fx to determine the dimensions of the larger of the two images:
magick background.jpg overlay.png -background none -gravity center -extent '%[fx:u.w>v.w?u.w:v.w]x%[fx:u.h>v.h?u.h:v.h]' -composite result.png
That basically says... "Extend the two images as follows. If the width of the first image (u.w) is greater than that of the second image (v.w), then use the width of the first, else use that of the second. Same for height.".
Original Answer
I believe you want this. Get width of whatever is wider of background and overlay. Get height of whatever is taller of background and overlay. Extend both background and overlay with transparent pixels to new dimensions. Overlay.
So, if we start with this as background (300x50):
And this as overlay (122x242) - which is a tall blue rectangle surrounded with transparency then that is bordered in black to show the extent of it:
You would run this, which is actually very simple but it is full of comments and debug output so you can see what is going on:
#!/bin/bash
# Get background width and height
read wb hb < <(convert background.jpg -format "%w %h" info: )
echo "Background: " $wb $hb
# Get overlay width and height
read wo ho < <(convert overlay.png -format "%w %h" info: )
echo "Overlay: " $wo $ho
# Get wider of the two
w=$wb
[ $wo -gt $w ] && w=$wo
# Get taller of the two
h=$hb
[ $ho -gt $h ] && h=$ho
echo "New dimensions: " $w $h
convert background.jpg overlay.png -background none -gravity center -extent ${w}x${h} -composite result.png
Here is how it looks running:
Background: 300 50
Overlay: 122 242
New dimensions: 300 242
Presumably, when you have done your overlay, you would add -trim as the final part of the command line to remove any extraneous stuff that has been added.
Try using convert rather than composite. It is more flexible than composite.
convert logo.png in_image.jpg -gravity center -compose over -composite out_image.jpg
But if you insist on using composite, then
composite in_image.jpg logo.png -gravity center -compose src_over out_image.jpg
Note sure exactly what you mean by preserving the alpha channel, since jpg does not support transparency. Perhaps you can post a pair of inputs and your desired output, if what I have posted does not do what you want.