This version of the manual refers to an earlier version of the software.


The watermarking feature overlays an image "watermark" on top of an output image. This can be useful for applying branding, attribution, copyright notices, and so on.

Modes of Operation

The watermarking system offers two "strategies," or modes of operation: a basic strategy, where watermark properties are hard-coded in the configuration file and applied to all requests; and a script strategy, where the decision whether or not to apply a watermark depends on the return value of a delegate script method. The watermark.strategy configuration key is used to set the strategy.


With BasicStrategy, the watermark.BasicStrategy.* keys in the configuration file are used to set a watermark image, position, inset, and minimum size cutoff. This strategy is easy to configure and works well when you intend for the same watermark to be applied to all images.


Perhaps you only want to apply a watermark to some of your images, and to others, you want to apply a different watermark, or no watermark. Perhaps you want to control watermarking based on the client's IP address, or user agent, or whether it possesses a certain cookie. Or, perhaps you only want to apply watermarks to JPEG output images, and not GIFs. Or, perhaps you don't want to apply a watermark to images that have been rotated. All of this is possible by writing just a few lines of code.

With the Cantaloupe::watermark delegate script method, you can tell the image server whether or not to apply a watermark in response to a particular request, in what position to apply it, and what image to apply. An example of how this can be accomplished appears below:

module Cantaloupe
  # See the argument & return value documentation in delegates.rb.sample.
  def self.watermark(identifier, operations, resulting_size, output_format,
                     request_uri, request_headers, client_ip, cookies)
    # If the resulting image is less than this many pixels on a side, don't
    # apply the watermark.
    min_size_cutoff = 300
    return false if resulting_size['width'] < min_size_cutoff or
        resulting_size['height'] < min_size_cutoff

    # Don't render a watermark to clients on localhost.
    return false if %w( ::1/128).include?(client_ip)

    # Don't render a watermark on GIF images.
    return false if output_format['media_type'] == 'image/gif'

    # Don't render a watermark on images of cantaloupes.
    return false if identifier.downcase.include?('cantaloupe')

    # Render a different watermark for iOS clients.
    if request_headers.
        select{ |k,v| k.downcase == 'user-agent' and v.include?('iOS') }.any?
      return {
        'pathname' => '/path/to/ios-watermark.png',
        'position' => 'bottom right',
        'inset' => 0

    # Render the default watermark for all other clients.
      'pathname' => '/path/to/default-watermark.png',
      'position' => 'bottom right',
      'inset' => 10


The watermark must be a 24-bit PNG image, either RGB or RGBA. It will be blended pixel-for-pixel into the output image, respecting its alpha channel.

Sample watermark (PNG)


Position and inset are configurable. Below, all availble positions are pictured with insets of zero:

top left
top center
top right
left center
right center
bottom left
bottom center
bottom right

Processor Support

Not all processors support watermarking; see the table of processor-supported features.



Watermark application should have minimal impact on response times, adding perhaps a few milliseconds for a typical-sized watermark. One thing to note, though, is that normally, requests for source images with no modification are streamed through with no processing. When watermarking is enabled, this will no longer be the case.

Zooming Image Viewers

Zooming image viewers display a mosaic of cropped image tiles. When watermarking is enabled, each tile will have a watermark, which may look more or less strange depending on the size of the watermark and the tile size used by the viewer. The image server has no control over this.

One way of getting around this might be to set the watermark.BasicStrategy.output_width_threshold and watermark.BasicStrategy.output_height_threshold configuration options to values that are slightly larger than the tile size used by the zooming image viewer. This will disable watermarking for zooming image viewer tiles, but enable for it for anything larger. Unfortunately, the tile size used by the viewer may differ depending on the source image, as the recommended tile sizes in information responses will vary on a per-image basis.


Watermark parameters (filename, position, inset, etc.) are encoded in cached-image identifiers. When watermark settings change, cached watermarked images will be re-generated automatically, and images with different watermark settings (when using ScriptStrategy) will be cached separately.