Create your own carrierwave processors
If you need to manage images in a rails application, I can only recommand CarrierWave.
That library will allow you to easily manage files upload. But also post processing on images, such as changing their sizes.
I use CarrierWave on this blog even though you don’t see it yet. Every category and every article has an image. That image has several different versions which have different sizes.
For one of those versions, I which to have rounded corners. You can see the result in the image at the left.
Let’s see in details how I got that.
## Post processing CarrierWave
Let’s imagine the following uploader :
We have a category uploader which will create a “thumb” version of the image. That image will have a size of 248 * 163 pixels.
You can find the processor “resize_to_fill” which will change the image’s size at lib/carrierwave/processing/rmagick.rb.
In order to create our rounded corners, we’ll create our own processor. I’ve placed it at lib/dmathieu/carrier_wave/round.rb.
unless defined? Magick begin require 'rmagick' rescue LoadError require 'RMagick' rescue LoadError puts "WARNING: Failed to require rmagick, image processing may fail!" end end module Dmathieu module CarrierWave module Round module ClassMethods def rounded_corner(radius = 10) process :rounded_corner => [radius] end end ## # Makes the image's corners round # # # === Parameters # # [radius (#to_s)] the corner radius # # === Yields # # [Magick::Image] additional manipulations to perform # def rounded_corner(radius = 10) # # See above for this method's code # end end end
Then, in your uploader, you can include that newly created processor.
You can see that, in our module, we create a method rounded_corner which will do the job of adding the rounded corners in our image. That action will be automatically called by CarrierWave when generating that version of the image.
Rounding up the corners
In order to manipulate our image, we use rmagick.
We’re gonna do the following :
- Create a new image of the same size than the previous which will contain a rectangle with rounded corners.
- Put that image above the previous one.
Quite easy no ? ;-)
def rounded_corner(radius = 10) manipulate! do |img| masq = ::Magick::Image.new(img.columns, img.rows).matte_floodfill(1, 1) ::Magick::Draw.new. fill('transparent'). stroke('black'). stroke_width(1). roundrectangle(0, 0, img.columns - 1, img.rows - 1, radius, radius). draw(masq) img.composite!(masq, 0, 0, Magick::LightenCompositeOp) img = yield(img) if block_given? img end end
We’ve just defined the rounded_corner method, which is located in the module provided earlier.
The manipulate! method is located in the rmagick.rb processor and gives us the image, allowing us to update it and to transmit it back to the next processor.
masq = ::Magick::Image.new(img.columns, img.rows).matte_floodfill(1, 1)
We create here a new image of the same size than the previous. But which contains nothing.
We draw in the image we’ve just created.
The rectangle we’ll create will have a transparent background.
That rectangle will have a black border of 1 pixel.
We create here the rectangle and add it to the previously create image.
img.composite!(masq, 0, 0, Magick::LightenCompositeOp)
Finally we add that rectangle image on top of the one which already exists, giving the effet we want.
CarrierWave’s processors are nested. Each one of them is executed one after the other. With yield, we give the image to the next processor. It’ll then just have to execute it’s own modifications.
Finally we return the image which will be saved.
As you can see, CarrierWave allows us to create generic processors so you can get your images exactly as you want them.
I’m actually quite surprise to see there’s not a lot of open source processors running wild.