Acts_as_attachment really kicks arse when it comes to handling files and images in your Rails application but one thing the file_column plugin has over acts_as_attachment is cropping support. Time and time again at work we have a space in the design for an image which has to be a certain size. By that I mean it must have a set width and height. But the client needs to be able to put any image they want into that space. But what if they upload a bigger image? Or, what if it’s different aspect ratio?

Example

Imagine you’ve got a client that trains dogs. They’re revising their home page and the designer has come up with a design that has space for 3 images that are exactly the same size. The designer thinks this looks great, but now you’re stuck with the problem of how can you let the client upload any image of any size or aspect ratio and have them perfectly fit into those 3 boxes.

Step one

Acts_as_attachment allows you to resize images which is useful when you can have a fixed width or height, but the other is variable. But in this case the designer wants 3 images which are all the same size, both in height and width. This is what would happen if we used acts_as_attachment to resize the images using a fixed width, but variable height.

Step two: Resizing only

Out of the box, this is actually your best option. But I’ve taken acts_as_attachment one step further and added cropping support. This will allow us to resize, then crop the image so that it’s scaled down, and then the left over bits are cropped off so that we can fit any image in these 3 boxes of fixed height and width. This is the results of using resizing and cropping:

Step Three: Resizing and Cropping

Now the client can be confident they can upload any image they like and it’s going to look nice on the site.

Patching Acts_as_Attachment to Support Cropping

Once you’ve installed the acts_as_attachment plugin, find the thumbnail_for_image method which is in /vendor/plugins/acts_as_attachment/lib/technoweenie/acts_as_attachment.rb

For me the thumbnail_for_image method begins on line 242. This might be different for you. The method should look like this:

def thumbnail_for_image(img, size)
  size = size.first if size.is_a?(Array) && size.length == 1 && !size.first.is_a?(Fixnum)
  if size.is_a?(Fixnum) || (size.is_a?(Array) && size.first.is_a?(Fixnum))
    size = [size, size] if size.is_a?(Fixnum)
    img.thumbnail(size.first, size[1])
  else
    img.change_geometry(size.to_s) { |cols, rows, image| image.resize(cols, rows) }
  end
end
To add cropping support, change it to this:
def thumbnail_for_image(img, size)
  size = size.first if size.is_a?(Array) && size.length == 1 && !size.first.is_a?(Fixnum)
  if size.is_a?(Fixnum) || (size.is_a?(Array) && size.first.is_a?(Fixnum))
    size = [size, size] if size.is_a?(Fixnum)
    img.thumbnail(size.first, size[1])
  elsif size.is_a?(String) && size =~ /^c.*$/ # Patch to enable cropping
    dimensions = size[1..size.size].split("x")
    img.crop_resized!(dimensions[0].to_i, dimensions[1].to_i)
  else
    img.change_geometry(size.to_s) { |cols, rows, image| image.resize(cols, rows) }
  end
end

Save and restart your web app and you should be up and running with cropping support!

How to Indicate you Want Cropping

In your model all you need to do is put a “c” infront of the dimensions on the thumbnail you want to resize and crop. The “c” indicates to acts_as_attachment that cropping should occur.

acts_as_attachment :storage => :file_system,
                   :file_system_path => 'public/system', # Using Capistrano conventions
                   :max_size => 4.megabytes,
                   :content_type => :image, # only allow png, gif and jpg
                   :resize_to => "1000x1000",
                   :thumbnails => {:home => "c100x80",
                                            :something_else => "500>"}
For the example above you might make a new thumbnail called “home”. We’ve put a c infront of it to make sure the cropping occurs. The result should be an image fixed at 100×80 regardless of what size or aspect ratio the client uploads.

Extending this Idea Further

If you take a look at the modifcations to acts_as_attachment to support cropping, you could easily modify it to support anything you like. Perhaps on a certain thumbnail you want a drop shadow to appear. You could make acts_as_attachment recognise “s” (for ‘shadow’) infront of the deminsions.

If you do anything cool like that please comment below and let us know!

Images used in example taken from here, here and here.