Playing with images: Rmagick, Ruby on Rails, large coffee

|
After a few minutes of messing around I found it was actually rather simple to perform basic manipulation of images with Rmagick and Ruby. At work, we'd been looking for a simple way of allowing folk to upload an image, pop it into a BLOB in postgres and generate a small thumbnail. So here's a brief rundown of what I did (btw: i'm assuming your modifying an existing model to store the image):

Install Rmagick
(i'm currently running Vista (not for long) and this is the best for windows as you'll struggle to find win32 binaries for the other ruby image mungers). Have a look here for the latest Rmagick.

Prepare your Database.
Do a migration to allow you to store some meta-data and the actual image data. I did something like this:


class AddImageData < ActiveRecord::Migration
def self.up
add_column :foo, :image_content_type, :string
add_column :foo, :image_filename, :string
add_column :foo, :image_binary_data, :binary
add_column :foo, :image_thumb_binary_data, :binary
end

def self.down
remove_column :foo, :image_content_type
remove_column :foo, :image_filename
remove_column :foo, :image_binary_data
remove_column :foo, :image_thumb_binary_data, :binary
end
end


Run a rake db:migrate to prepare your database.

Write some tests to validate your model class is actually going to do something with the image data. I wrote a couple of simple tests to prove our accessor method below "uploaded_picture=" gets hit when i create a new "Foo", and that the image_data fields are read into the model correctly.

Fix up, Look sharp.
Now fix up your model to do something with the new image. I did this (not much code for what you get!):


def uploaded_picture= image_data
if image_data
img_orig = Magick::Image.from_blob image_data.read
thumb = img_orig.first.scale(200, 200)

self.image_filename = base_part_of(image_data.original_filename)
self.image_content_type = image_data.content_type.chomp
self.image_binary_data = img_orig.first.to_blob
self.image_thumb_binary_data = thumb.to_blob
end
end

def base_part_of(file_name)
File.basename(file_name).gsub(/[^\w._-]/,'')
end


The code has eyes
Now modify your view to accept a file upload.
Note that you need to set :html => {:multipart => true} for the tag or you're in for a long and fruitless evening.

Add this to your form where "f" is the form in scope.

<%= f.file_field :uploaded_picture, :label => "Image" %>


And you're done. Hope this saves you some time! PS - sorry about the screwy CSS. I'm using a crufty wordpress theme. Will fix when i have some time.

0 comments: