| Module | ActionController::Macros::ImageMagick::ClassMethods |
| In: |
actionpack/lib/action_controller/macros/image_magick.rb
|
This macro can be used to add ImageMagick functionality to a controller. You can use it to access ImageMagick commands with a simple template tag. ImageMagick is a set of image processing tools, that can do nearly everything you’d ever want to do with an image. Resize, rotate, crop and much more.
This needs the RMagick library (and ImageMagick, of course) to work.
The simplest way to use this extension, is by adding the behaviour to a directory. For example:
# Controller
class Photo < ApplicationController
imagemagick_for_directory '/var/lib/photos'
end
# View
<%= imagemagick_tag 'presentation.jpg', 'resize(100x50)+flop' %>
This example generates an <img> tag in the view, which points to the imagemagick action of the Photo controller. All you need to do to generate this controller, is adding the imagemagick_for_directory method to your controller class. The imagemagick action opens the image, sends the commands to RMagick for processing and then sends the result to the browser.
This example shows you the image presentation.jpg from the /var/lib/photos directory. It is processed with the commands resize(100x50), which means that ImageMagick will shrink it to fit it in an area of 100x50 pixels, and flop, which means that left and right are reversed.
Or perhaps you have stored your images not in a directory, but in a database or somewhere else. Even then you can use the ImageMagick extension. This works by adding the ImageMagick processing as an after_filter for the action that retrieves and sends the original image. For example:
# Controller
class Photo < ApplicationController
imagemagick_filter_for :display_photo
def display_photo
# do some work to retrieve and send the photo (that's your job)
end
end
# View
<%= imagemagick_tag :action=>'display_photo', :commands=>'resize(100)', ... other parameters for display_photo ... %>
The action display_photo gets the image from the database or where you’ve stored it and renders it normally. Then after that, the imagemagick filter is executed. It reads the output from your action, processes it using the commands from @params[‘commands’] and finally sends the resulting image to the browser (or to another filter, if there is one).
The <img> tag for this rendered image is generated by imagemagick_tag: you give it the url_for options hash that your action needs to find and display the image, plus the additional :commands parameter that is to be used by ImageMagick.
If you used imagemagick_for_directory, the extension expects to find all images in a directory, the name of which is specified with the imagemagick_for_directory method. In this directory, you can simply place the image files. The names and extensions are not really important, ImageMagick is smart enough to determine the file type from the contents of the file.
In the image directory, you can have subdirectories. Just give the name of the subdirectory to imagemagick_tag. For example, if in our directory /var/lib/photos there is a subdirectory called rails, we can refer to an image in that subdirectory like this:
# View <%= imagemagick_tag 'rails/presentation.jpg' %>
You can use the ImageMagick extension in multiple controllers, but you might want to specify a different image directory for each of them. (But even that is not required.)
The filter expects your action to put the image in @response.body. If you use render(:file) or render(:text) to render the image, it should work right. You can’t use the streaming methods send_file and send_data.
If you don’t take any precautions, the rendered image will not be saved, and it has to be rendered from scratch for every new request. This can make it a little slow. This extension therefore provides a caching mechanism, which caches the processed images. For the requests that follow after the first rendering, it simply sends the cached image, instead of re-rendering it.
To enable caching, you need a cache directory that is writable by the webserver. If you have that directory, all you have to do is specify it with the cache option of the imagemagick_for method.
# Controller
class Photo < ApplicationController
imagemagick_for_directory '/var/lib/photos', :cache=>'/var/lib/photo-cache'
end
You can use the same cache directory for multiple controllers. Caching is also possible if you use imagemagick_filter_for.
By default, the commands are transferred in the URL of the image, and are executed when the user requests the image. This is reasonably safe, but it does allow your visitors to specify any ImageMagick command they want by simply changing the URL. If you think this is a problem, you can enable the pre-rendering function.
Pre-rendering means that the image is rendered earlier in the process: when the imagemagick_tag is displayed by the view. The image is rendered and cached, and the name of that cached image is sent to the browser, which then uses it to request the image. This means that the user does not have the possibility to influence the rendering of the image, as rendering is done from the view. It also means that the initial delay of the rendering of the image is on the web page, instead of on the loading of the images.
The pre-rendered images are stored by the caching system, so you’ll need to enable caching if you want to use pre-rendering.
# Controller
class Photo < ApplicationController
imagemagick_for_directory '/var/lib/photos', :cache=>'/var/lib/photo-cache', :prerender=>true
end
Prerendering is only possible if you’re using the imagemagick_for_directory action, prerendering does not work with imagemagick_filter_for.
It is possible to define your own commands, or ‘recipes’, for use with imagemagick_tag. See the documentation for ActionController::Macros::ImageMagick::RecipeSet for more information.
If you have your own set of recipes, you can restrict the commands that can be executed to the recipes in this set. See the :max_recipe_level option of imagemagick_for.
imagemagick_for works without any additional routes. It uses urls like:
/photo/imagemagick/presentation.jpg?command=resize(100x100)
If you’d like to get rid of the ?command=, you can add the following routes to your routes.rb:
map.connect ':controller/imagemagick/:id', :action=>'imagemagick', :commands=>''
map.connect ':controller/imagemagick/:commands/:id', :action=>'imagemagick'
The above url will now be rendered as:
/photo/imagemagick/resize(100x100)/presentation.jpg
Enables the ImageMagick extension as an after_filter for action_name. The response of the action will be processed as an image, with the commands found in @params["command"].
For a description of the options, see the documentation for imagemagick_for.
Enables the ImageMagick extension for this controller. If image_source is a String, the extension will be enabled for the directory with that name. If image_source is a Symbol, the extension will be enabled as a after_filter that does its work on the result of the action with that name.
This method is also available as imagemagick_for_directory and imagemagick_filter_for.
The following options can be specified:
To change the system-wide defaults, see the ActionController::Macros::ImageMagick::DEFAULT_OPTIONS
Enables the ImageMagick extension for the given image_path. For a description of the options, see the documentation for imagemagick_for.