Rick Olson’s attachment_fu is my favorite file upload plug-in because let’s you use three different image manipulation tools [rmagick, mini-magick, image science] and storage options [file system, database, amazon s3]. However it doesn’t yet support two features I use on every CMS I build, Flash/Flex file upload (images will upload but won’t be resized) and square image cropping. Here’s how to tweak it to get both features working.
First up, support for Flash/Flex upload (I should really drop the ‘Flash/’ part as I only use Flex now) , first up Flex upload… Ilya Devers posted the solution on Google groups, but I get to claim 1% credit as my blog is mentioned in his post :P
The problem is really on the Flex side of things as all uploads come through as ‘application/octet-stream’ for the mime-type. attachement_fu can upload any kind of file so it checks the mime-type before running it’s resize code, since it’s looking for an image it skips over the Flex uploaded files. Ilya’s rather ingenious solution is to override attachment_fu and use the file system to check the file type. To overide attachment_fu add the ‘uploaded_data=’ and ‘get_content_type’ methods to your upload model.
class Upload < ActiveRecord::Base
belongs_to :image
has_attachment :content_type => :image,
:storage => :file_system,
:processor => ‘MiniMagick‘,
:max_size => 2000.kilobytes,
:resize_to => ‘620×465>‘,
:thumbnails => { :thumb => [90, 90] }
def uploaded_data=(file_data)
return nil if file_data.nil? || file_data.size == 0
self.filename = file_data.original_filename if respond_to?(:filename)
if file_data.is_a?(StringIO)
file_data.rewind
self.temp_data = file_data.read
else
self.temp_path = file_data.path
end
self.content_type = get_content_type((file_data.content_type.chomp if file_data.content_type))
end
def get_content_type(fallback=nil)
begin
content_type = `file -bi “#{File.join(temp_path)}“`.chomp
content_type = fallback unless $?.success?
content_type.gsub!(/;.+$/,““) if content_type
content_type
rescue
fallback
end
end
end
Next is cropping square images with mini-magick. Currently if you request a square image attachment_fu will stretch rather than crop the image, this time I’ll ‘borrow’ the solution from Craig Ambrose. This time you have to dig deeper down into the depths of the rails plugins directory to edit ‘vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu/processors/mini_magick_processor.rb’ and replace the resize_image method with the following.
def resize_image(img, size)
size = size.first if size.is_a?(Array) && size.length == 1
if size.is_a?(Fixnum) || (size.is_a?(Array) && size.first.is_a?(Fixnum))
if size.is_a?(Fixnum)
resize_and_crop(img, size)
else
size[0] == size[1] ? resize_and_crop(img, size[0]) : img.resize(size.join(‘x‘))
end
else
img.resize(size.to_s)
end
self.temp_path = img
end
def resize_and_crop(image, square_size)
if image[:width] < image[:height]
shave_off = ((image[:height] - image[:width])/2).round
image.shave(“0x#{shave_off}“)
elsif image[:width] > image[:height]
shave_off = ((image[:width] - image[:height])/2).round
image.shave(“#{shave_off}x0“)
end
image.resize(“#{square_size}x#{square_size}“)
return image
end
To crop an image you use ‘:thumb => [90, 90]‘ as in the Model code above. That’s it!