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

Overlays

The overlay feature overlays an image or text string on top of a derivative (output) image. This can be useful for description, branding, attribution, copyright notices, and so on.

Image with image overlay applied.
Image overlay.
Image with string overlay applied.
String overlay.

With both types of overlays, the position, inset, and output width/height threshold (below which the overlay won't be displayed) are configurable.

Not all processors support overlays; see the table of supported features.


Image Overlays

An image overlay must be a 24-bit PNG image, either RGB or RGBA. It will be blended pixel-for-pixel into the output image.

Overlay images can be located on the filesystem, and also, since version 3.3, on a web server. Regardless, they are cached in memory after being loaded the first time, so there is no performance penalty for using web-hosted overlay images.

Note: when using multiple image overlays, their filenames must all be different, regardless of where they reside.

Sample overlay image (PNG)


String Overlays

String overlays are dynamically rendered onto an image using Java 2D. The font family, size, weight, color, stroke color, background color and opacity, etc., are configurable.

Line breaks within the string (\n) are respected, enabling multi-line strings. Each line is auto-aligned to the edge of the image according to the overlay position.

Strings are guaranteed to never overflow outside of the image. When a string doesn't fit entirely inside at its specified font size, the image server will try to use the largest font size that fits, down to the configurable minimum allowed size. If none fit, the string won't be drawn.


Modes of Operation

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

BasicStrategy

With BasicStrategy, the overlays.BasicStrategy.* keys in the configuration file are used to set an overlay type (image or string), position, inset, and others. This strategy is easy to configure and is all that is needed when it is intended for the same overlay to be applied to all images.

ScriptStrategy

Perhaps you want to apply an image overlay to some of your images, and to others, you want to apply a string overlay, or no overlay. Perhaps you want to control overlays based on the client's IP address or user agent. Or, perhaps you only want to apply overlays to JPEG output images, and not GIFs. Or, perhaps you don't want to apply an overlay to images that have been rotated. All of this is possible by writing just a few lines of code.

With the overlay() delegate method, you can tell the image server whether to apply an overlay in response to a particular request, and what its properties should be. As an example:

module Cantaloupe
  ##
  # See the argument & return value documentation in delegates.rb.sample.
  #
  def self.overlay(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 an overlay.
    min_size_cutoff = 300
    return false if resulting_size['width'] < min_size_cutoff or
        resulting_size['height'] < min_size_cutoff

    # Don't render an overlay for clients on localhost.
    return false if %w(127.0.0.1 ::1/128).include?(client_ip)

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

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

    # Render an image overlay for iOS clients.
    if request_headers.
        select{ |k,v| k.downcase == 'user-agent' and v.include?('iOS') }.any?
      return {
        'image' => '/path/to/ios-overlay.png',
        'position' => 'bottom right',
        'inset' => 5
      }
    end

    # Render a string overlay for all other clients.
    {
      'string' => "This string\nhas multiple lines",
      'position' => 'bottom left',
      'inset' => 5,
      'font' => 'Helvetica',
      'font_size' => 20,
      'font_min_size' => 18,
      'font_weight' => 1.0,
      'color' => 'white',
      'background_color' => 'rgba(0, 0, 0, 0.6)'
      'glyph_spacing' => 0,
      'stroke_color' => 'black',
      'stroke_width' => 1
    }
  end
end

Positioning

Position and inset are configurable. Supported positions are:

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

Implications for Zooming Viewers

Zooming image viewers display a mosaic of cropped image tiles. When overlays are enabled, each tile will have one, which is bound to look strange. A couple of ways to work around this are:

  • Set the overlays.BasicStrategy.output_width_threshold and overlays.BasicStrategy.output_height_threshold configuration options to values that are slightly larger than the tile size used by the image viewer. This will disable overlays for images the size of image viewer tiles, and enable them for anything larger. Bear in mind, though, that 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.
  • Have the zooming viewer supply a URI query argument, and check for it in the overlay() delegate method. Of course, a user could figure this out and supply the same argument in other image requests to bypass overlays arbitrarily.