module Fleximage
module Operator
# Adds an overlay to the base image. It's useful for things like attaching a logo,
# watermark, or even a border to the image. It will work best with a 24-bit PNG with
# alpha channel since it will properly deal with partial transparency.
#
# image.resize(image_overlay_path, options = {})
#
# +image_overlay_path+ is the path, relative to +Rails.root+ where the image you want superimposed
# can be found.
#
# Use the following keys in the +options+ hash:
#
# * +size+: The size of the overlayed image, as '123x456' or [123, 456].
# By default the overlay is not resized before compositing.
# Use this options if you want to resize the overlay, perhaps to have a small
# logo on thumbnails and a big logo on full size images. Other than just numerical dimensions, the
# size parameter takes 2 special values :+scale_to_fit+ and :+stretch_to_fit+. :+scale_to_fit+ will
# make the overlay fit as
# much as it can inside the image without changing the aspect ratio. :+stretch_to_fit+
# will make the overlay the exact same size as the image but with a distorted aspect ratio to make
# it fit. :+stretch_to_fit+ is designed to add border to images.
#
# * +alignment+: A symbol that tells Fleximage where to put the overlay. Can be any of the following:
# :center, :top, :top_right, :right, :bottom_right, :bottom, :bottom_left, :left, :top_left.
# Default is :+center+
#
# * +offset+: the number of pixels to offset the overlay from it's :+alignment+ anchor, in
# '123x456' or [123, 456] format. Useful to give a bit a space between your logo
# and the edge of the image, for instance.
# *NOTE:* Due to some unexpected (buggy?) RMagick behaviour :+offset+ will work strangely
# if :+alignment+ is set to a non-corner value, such as :+top+ or :+center+. Using :+offset+ in
# these cases will force the overlay into a corner anyway.
#
# * +blending+: The blending mode governs how the overlay gets composited onto the image. You can
# get some funky effects with modes like :+copy_cyan+ or :+screen+. For a full list of blending
# modes checkout the RMagick documentation (http://www.simplesystems.org/RMagick/doc/constants.html#CompositeOperator).
# To use a blend mode remove the +CompositeOp+ form the name and "unserscorize" the rest. For instance,
# +MultiplyCompositeOp+ becomes :+multiply+, and +CopyBlackCompositeOp+ becomes :+copy_black+.
#
# Example:
#
# @photo.operate do |image|
# image.image_overlay('images/my_logo_with_alpha.png',
# :size => '25x25',
# :alignment => :top_right,
# :blending => :screen
# )
# end
class ImageOverlay < Operator::Base
def operate(image_overlay_path, options = {})
options = options.symbolize_keys
#load overlay
overlay = Magick::Image.read(image_overlay_path).first
#resize overlay
if options[:size]
if options[:size] == :scale_to_fit || options[:size] == :stretch_to_fit
x, y = @image.columns, @image.rows
else
x, y = size_to_xy(options[:size])
end
method = options[:size] == :stretch_to_fit ? :stretch : :scale
send(method, [x, y], overlay)
end
#prepare arguments for composite!
args = []
args << overlay #overlay image
args << symbol_to_gravity(options[:alignment] || :center) #gravity
args += size_to_xy(options[:offset]) if options[:offset] #offset
args << symbol_to_blending_mode(options[:blending] || :over) #compositing mode
#composite
@image.composite!(*args)
return @image
end
end
end
end