Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Combining multiple images in ImageMagick with relative (not absolute) offsets

I'm looking for the most efficient way to stitch multiple images together in ImageMagick, on top of a background image, such that the spacing / padding between the overlaid images is consistent?

I've investigated use of +append, convert -composite, and convert with -page and -layers merge.

The following command (convert -composite) works, but requires precalculation of image dimensions in order to specify absolute offsets. Really, I want a 10 pixel gap between the end of the FIRST layered image and the start of the second layered image, but the only way I can see to achieve that is by specifying the absolute offset from the top-left corner of the canvas.

convert \
  background.jpg \
  first.jpg -gravity Northwest -geometry  +10+10 -composite \
  second.jpg                   -geometry +300+10 -composite \
  third.jpg                    -geometry +590+10 -composite \
  output.jpg

I am looking for some sort of operator so that the horizontal offset can be interpreted relative to the "last" image in the layering, so instead of specifying +300+10 for the second image and +590+10 for the third, I can somehow specify a +10+10 offset.

I thought gravity would allow me to achieve that (-gravity Northwest), in the same way that float: left; works in CSS positioning, but that is not the case.

I have also had some success with the following:

convert \
  -page  +10+10 first.jpg  \
  -page +300+10 second.jpg \
  -page +590+10 third.jpg  \
  -background transparent  \
  -layers merge \
   layered.png

convert background.jpg layered.png -gravity Center -composite output.jpg

Both the techniques described require pre-calculation of absolute offsets, which is a bit of a pain. Is there a better way to do this?

like image 586
Przemek Kujonewicz Avatar asked Sep 05 '12 01:09

Przemek Kujonewicz


2 Answers

You've overlooked the montage command.

The most simple command to add the wanted spacing with it would be to set a -frame 5 option with -mattecolor none. This works with images of different width values and spaces them all apart with a distance of 10 pixels:

montage             \
  -alpha on         \
  -background none  \
  -mode concatenate \
  -tile x1          \
  -frame 5          \
  -mattecolor none  \
   *.jpg            \
   output1.png

You'll easily notice however, that the resulting image's border is only 5 pixels wide on top, right, bottom and left. To remove these 5 pixels all around use:

convert  output1.png  -shave 5  output2.png

To overlay this result on your background.jpg, use:

convert             \
  background.jpg    \
  output2.png       \
 -gravity Northwest \
 -geometry +10+10   \
 -composite         \
  final.jpg
like image 109
Kurt Pfeifle Avatar answered Nov 01 '22 11:11

Kurt Pfeifle


You can also use Kurt's transparent frame trick with append. Using append instead of montage has the advantage that you can use gravity settings to align your images top (north) bottom (south) or center.

Here's an example of how to append images horizontally with a 10 pixel gap between them, and with the images top aligned:

convert \
  -frame 5 \
  -mattecolor none \
  -background none \
  -gravity north \
  first.jpg second.jpg third.jpg \
  +append \
  png:- | convert - -shave 5
  output.png

To append images vertically use -append instead of +append. I've used a pipe | to shave off the outside frame in the same command.

like image 23
toby-one Avatar answered Nov 01 '22 11:11

toby-one