I use imagemagick to add a watermark to my photos. The command line is the following:

composite -tile -gravity center watermark.png somefile.jpg somefile.jpg

But the watermark isn’t centered vertically. It looks like this:

Image with watermark

I’d like it to start from the center. How can I do it?


First, get the dimensions of the base and watermark images:

basew=`identify -format '%w' "$infile"`
baseh=`identify -format '%h' "$infile"`
wmw=`identify -format '%w' "$wmfile"`
wmh=`identify -format '%h' "$wmfile"`

Then, calculate how many complete tiles we can fit over the base image:

tilew=$(($basew / $wmw * $wmw))
tileh=$(($baseh / $wmh * $wmh))

This uses integer arithmetic, so the multiply operation doesn't counteract the divide. Let's take an example. If the base image is 100x100 and the tile image 34x34, this will yield 68x68, since you can't quite fit a third tile in on either axis.

Note that we're using a Bash feature here to do arithmetic within the shell script proper. If you have to do this in another shell, you can call out to bc or dc to do the calculation externally.

Now that we know how large we can make it, create a tiled temporary version of the watermark image, centered within a frame equal to the size of the base image:

wmtemp=`mktemp /tmp/wm-XXXXXX.png`
convert -background 'rgba(0,0,0,0)' -size "$tilew"x"$tileh" \
    tile:"$wmfile" -gravity center -extent "$basew"x"$baseh" \

Notice that this forces the watermark image to RGBA format if it wasn't already. Also, it's important that the -background 'rgba(0,0,0,0)' directive be before the input image, so it doesn't do the tiling operation over the default white background.

The real trick here, though, is that we're using different values for the -size and -extent directives. We're building up a potentially smaller tiled image, then padding it out if needed to match the size of the base image. If the tile image size divides evenly into the base image size, that's fine, it simply won't have to add any extra padding to center the tile set.

Finally, lay the temporary tiled watermark over the original image:

composite "$wmtemp" "$infile" "$outfile"
rm "$wmtemp"
  • Thanks. I wanted to incorporate it into a loop – it works but the output consists only of one watermark – the watermark is not tiled: link
    – wryrych
    Aug 17 '12 at 11:36
  • Hm, maybe I didn’t make it clear. The watermark you can see in the photo consists of only one writing: ‘sparrowbike.co.uk’. I then tile it. Does it make sense?
    – wryrych
    Aug 17 '12 at 15:34
  • I’m googling but without a success. It seems that you can’t? set a starting point for tiles – and I want tiles to start from the centre and then spread across photo. It seems that -tile always start from the top left corner. :(
    – wryrych
    Aug 17 '12 at 16:06
  • I've extended the script to add the even tiling capability. Aug 17 '12 at 17:13
  • Truly awesome! Do you think that it makes sense to extend it so that the whole photo is covered with watermark? I was playing with it a little and did the following: get the ceiling of tilew/tileh so that the newly created image with watermark is larger than the base image. Then crop it (and add offsets) and merge. But having 800×600 photo and 250×250 watermark I ended up with watermark that didn’t seem to be visually centered, though it was perfectly before cropping. So I think that you solution takes this into account because otherwise you should have a watermark that fits perfectly a photo.
    – wryrych
    Aug 18 '12 at 7:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.