Mirror Images with CarrierWave

This post was originally published on the Elabs blog, before Elabs and Varvet joined forces.

Inspired by this post on how to create mirror images with Paperclip, I decided to write up how to do the same thing with CarrierWave. It’s a nice example of how CarrierWave’s Uploader class makes manipulating files very easy.

This assumes you’ve already generated an uploader and probably mounted it on a model somewhere. If this doesn’t make sense to you, check out the CarrierWave documentation.

Add this method to you uploader:

def add_mirror_effect(mirror_length)
  manipulate! do |img|
    mirror_rows = img.rows * mirror_length

    gradient = Magick::GradientFill.new(0, 0, mirror_rows, 0, "#888", "#000")
    gradient = Magick::Image.new(img.columns, mirror_rows, gradient)
    gradient.matte = false

    flipped = img.flip
    flipped.matte = true
    flipped.composite!(gradient, 0, 0, Magick::CopyOpacityCompositeOp)

    new_frame = Magick::Image.new(img.columns, img.rows + mirror_rows)
    new_frame.composite!(img, 0, 0, Magick::OverCompositeOp)
    new_frame.composite!(flipped, 0, img.rows, Magick::OverCompositeOp)
    new_frame
  end
end

This will first create a gradient. It will then flip the image and use that gradient as the alpha channel for the flipped image. Finally it will create a new image, putting the original, and the faded out mirror image together.

Next, add a version to your Uploader, which calls the new add_mirror_effect method:

version :with_mirror do
  process :add_mirror_effect => 0.2
end

That’s it! The end result should look something like this:

class AvatarUploader < CarrierWave::Uploader::Base
  include CarrierWave::RMagick

  version :with_mirror do
    process :resize_to_fill => [200, 200]
    process :add_mirror_effect => 0.2
  end

private

  def add_mirror_effect(mirror_length)
    manipulate! do |img|
      mirror_rows = img.rows * mirror_length

      gradient = Magick::GradientFill.new(0, 0, mirror_rows, 0, "#888", "#000")
      gradient = Magick::Image.new(img.columns, mirror_rows, gradient)
      gradient.matte = false

      flipped = img.flip
      flipped.matte = true
      flipped.composite!(gradient, 0, 0, Magick::CopyOpacityCompositeOp)

      new_frame = Magick::Image.new(img.columns, img.rows + mirror_rows)
      new_frame.composite!(img, 0, 0, Magick::OverCompositeOp)
      new_frame.composite!(flipped, 0, img.rows, Magick::OverCompositeOp)
    end
  end

end

For extra props, put the add_mirror_effect method in a module and include it in your Uploader.