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.
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.
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:
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:
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])
else
img.change_geometry(size.to_s) { |cols, rows, image| image.resize(cols, rows) }
end
end
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.
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.
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>"}
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!