HOWTO: Watermarking Images with ImageMagick and attachment_fu14 January 2010

While working on a project for the State Hermitage Museum last year, I had to implement some image watermarking. The basic requirement was that for a certain type of uploaded image, its largest thumbnail should have the museum's logo tiled across it. I was using attachment_fu to handle the image upload, and ImageMagick/RMagick to process the thumbnails.

After some cursory Googling, I found the ImageMagick Annotating guide, which had this sample watermark command:

 $ convert overlay.png  -fill grey50 -colorize 40  miff:- |\
    composite -dissolve 15 -tile  -  original.jpg watermarked_image.jpg

The dissection of the command:

overlay.png: The source image to overlay

-fill grey50 -colorize 40: Alter the colors of the watermark file

composite: command to overlay the watermark

-dissolve 15 -tile: "dissolve" the overlay at 15%, for good transparency, and tile (repeat) the watermark over the source image.

That's simple enough, and with these source files:

and dearest Rufus:

rufus.jpg

 $ convert overlay.png -fill grey50 -colorize 40 miff:- |\
    composite -dissolve 15 -tile - rufus.jpg result-15.jpg
Produces:
convert overlay.png -fill grey50 -colorize 40 miff:- |\
  composite -dissolve 50 -tile - rufus.jpg result-50.jpg

Unfortunately, RMagick's watermark method doesn't support tiling. To work around, I had to call the composite_tiled! method on a colorized image. This code is in my Thumbnail model, which includes attachment_fu:

class Thumbnail < ActiveRecord::Base
  has_attachment  :content_type => :image,
   # some settings omitted
   :watermark_overlay => File.join(RAILS_ROOT, '/public/images/watermark-overlay-image.png'),
   :watermarkable_size => "1500>" 

  after_attachment_saved do |record|
    if record.respond_to?(:parent_id) and record.parent_id.nil? # the original image, not the smaller thumbnails
      with_image record.full_filename do |img|
        img.composite_tiled!(
          Magick::ImageList.new(attachment_options[:watermark_overlay]).first.colorize(0.4, 0.4, 0.4, 'grey'),
          Magick::SoftLightCompositeOp)
        img.write record.full_filename  # save image
      end
    end
  end
end

Now every Thumbnail record will automatically have a watermarked large image.

Want to talk about this a bit more? Send a tweet to @cgansen or email me at cgansen@gmail.com.