= FlexImage
By Alex Wayne < rubyonrails AT beautifulpixel DOT com >
--
***NOTE: This document will be much more readable if viewed through the rdoc
run "rake rdoc" from inside vendor/plugins/flex_image to generate the html
documention
++
FlexImage is a plugin that allows you to put image data in your database or
file sysytem and retrieve at any size, quality or cropping you like. It evens
supports some interesting effects with overlays, borders, shadows, and more.
Combine this with page caching and you have a fast and easy way to manage
large numbers of uploaded images that are always just the right size for your
needs.
== Prerequisites
*RMagick* must be installed
http://rmagick.rubyforge.org
== Size declarations!
Any reference to a size is defined with a special format, similar to the rails
+image_tag+ helper. It is a string of format "100x200" where 100 is width and 200 is height.
You can omit the "x", or use a single number, to denote a square. For instance "150"
is identical in function to "150x150"
See process! in FlexImage::Model for options explanation.
== Setup
=== Installation
SVN: http://beautifulpixel.com/svn/plugins/flex_image/
Install via the plugin script into your rails application
ruby script/plugin install http://beautifulpixel.com/svn/plugins/flex_image/
use install -x instead of install if your project is
already under subversion. Then the plugin will update itself everytime you do a
+svn up+.
=== Model and Migration
First, you must create the table model and table used by FlexImage. At
a command prompt in the root of your rails app:
ruby script/generate flex_image ProductImage
rake migrate
This will create a model +ProductImage+ and a migration for a table called +product_images+,
just like script/generate model ProductImage. Except with some added functionality.
If you want to add FlexImage to an exsiting model, simply make it inherit from FlexImage::Model
instead of ActiveRecord::Base and add a +MEDIUMBLOB+ field to your table for that model.
Remember that your FlexImage class inherits from ActiveRecord and works just like every other
model in Rails. It simply has some added functionality.
*NOTE*: if you want to store the images in the file system rather than the db, simply remove
lines that create the binary column form the migration file, and add the following to your
model object:
self.file_store = 'path/to/images'
==== Image Pre-Processing
Use the +pre_process_image+ method on your model to transform the images as they are uploaded.
Simply pass any of the rendering options. The following will make all uploaded images be no
larger than 1000x1000.
class ProductImage < FlexImage::Model
pre_process_image :size => '1000x1000'
end
See process! in FlexImage::Model for options explanation.
=== Controller
In order to see the image, you use the +flex_image+ method to add an action to
a controller. The +action+ and +class+ parameters are required. The +action+
parameter is the name of the controller action that shows the image and the
+class+ is the model class that will be searched for images. The actual class
object or just it's name as a string can be used.
class ProductImagesController < ApplicationController
flex_image :action => 'show',
:class => ProductImage
end
You can also pass in any of the previously mentioned rendering options to set the defaults
for image rendering. For example:
flex_image :action => 'show', :class => ProductImage, :size => '100x50', :crop => true
Or even have a different action for two sizes of image:
flex_image :action => 'show', :class => ProductImage, :size => '640x480'
flex_image :action => 'thumb', :class => ProductImage, :size => '100x75'
*NOTE*: you can create your own action for rendering images instead of using the +flex_image+
macro. For more info see FlexImage::Controller.
Now you could go to /product_images/show/1 to see an image, but you haven't
created any yet. Luckily, this isn't hard. So let's create a quick little view for
creating +ProductImage+ objects. Use this simple form:
#app/views/product_images/new.rhtml
<%= form_tag({:action => 'create'}, {:multipart => true})%>
<%= file_field 'image', 'data' %>
<%= submit_tag %>
<%= end_form_tag %>
*IMPORTANT* :multipart => true must be present on any form with a file upload or
the browser will not send the binary with the request.
We will also add a +create+ method to process an uploaded file, creating a new database
row for the image.
class ProductImagesController < ApplicationController
flex_image :action => 'show', :class => ProductImage
def create
img = ProductImage.create(:data => params[:image][:data])
redirect_to :action => 'show', :id => img
end
end
Now find an image on your hard drive and upload via the form at /product_images/new.
You should be redirected to your image, displayed in the browser.
Try adding ?size=100x50 to the url, and watch the image size alter. Or add options
to the +flex_image+ method call to affect the image without changing the URL.
=== View Usage
To include an image tag in your view, simply call +url_for+ as the image location and point
it to your image action.
<%= image_tag url_for(:controller => 'product_images',
:action => 'show',
:id => 123) %>
You can add any of the rendering options to this hash to override the defaults in the controller.
Although the above works, it's not entirely compatible with page caching since the parameters are not
actually part of the filename. To remedy this make a custom route for your images.
map.product_image 'product_images/show/:id/:size/image.jpg',
:controller => 'product_images',
:action => 'show'
Here in routes as well, you can use the rendering options.
Now when page caching is active, the size is baked into the filename. This means when the webserver
fetches the same image of a different size the proper cache is used or generated.
== Configuration Examples
=== Adding a border
Lets say we want the thumbnails in our app to have a border, to help them better blend into the layout.
Assume that we have an image with an alpha channel that gives it a hole in the middle. We can add
this image as a border using the :size => :stretch_to_fit option in the overlay options.
flex_image :action => 'thumbnail',
:class => MyImage,
:size => '100x100',
:overlay => {
:file => 'public/images/border.png',
:size => :stretch_to_fit
}
=== Adding a logo in the corner
Stamp your sites logo on all the big images
flex_image :action => 'show',
:class => MyImage,
:size => '640x480',
:overlay => {
:file => 'public/images/logo.png',
:alignment => :bottom_left,
:offset => 10
}