NAME
Catalyst::Controller::Imager - generate scaled or mangled images
VERSION
version 0.06
SYNOPSIS
# use the helper to create your Controller
script/myapp_create.pl controller Image Imager
# DONE. READY FOR USE.
# Just use it in your template:
# will deliver a 200 pixel wide version of some_image.png as jpg
<img src="/image/w-200/some_image.png.jpg" />
# will deliver a 210 by 300 pixel sized image without conversion
# (empty areas will be white)
<img src="/image/w-210-h-300/other_image.jpg" />
# will deliver a 80 by 80 pixel sized image
# (empty areas will be white)
<img src="/image/thumbnail/other_image.jpg" />
# define a modifier of your own
<img src="/image/blur-9/some_image.png.jpg" />
# your modifier plus a predefined one
<img src="/image/thumbnail-blur-9/some_image.png.jpg" />
# same thing as above
<img src="/image/blur-9-thumbnail/some_image.png.jpg" />
# in your Controller you then need:
sub want_blur :Action :Args(1) {
### do something to get a blurred image
}
DESCRIPTION
A Catalyst Controller that generates image files in any size you request and optionally converts the image format. Images are taken from a cache directory if possible and desired or generated on the fly. The Cache-directory has a structure that is very similar to the URI scheme, so a redirect rule in your webserver's setup would do this job also.
The URI of an image consists of always the same parts:
- the action namespace
-
If your Controller is named
MyApp::Controller::Image
, this first part will beimage
. - modifier(s)
-
Here a series of modifiers and arguments separated with single dashes ('-') are used.
h-100 # will request an image's height w-200 # will request an image's width h-80-w-20 # both, height and width will apply thumbnail # a configurable square (defaults to 80)
- image path
-
This is the relative path to the image that should get rendered
- extension (optional)
-
If an additional option like
.gif
is added immediately after the image path, this format is requested for delivery.
A Controller that is derived from Catalyst::Controller::Imager
may define its own modifier functions. See EXTENDING below.
Possible initially defined options are:
- w-n
-
specifies the width of the image to generate. The height is adjusted to maintain the same ratio as the original image. The maximum size is controlled by a configuration parameter
max_size
that defaults to 1000.Can be used in conjunction with h-n. However, if both options are given, the image will scale to fill the given area either by width or by height, get centered inside the area and additional spaces will get filled with white.
- h-n
-
specifies the height of the image to generate. The width is adjusted to maintain the same ratio as the original image. The maximum size is controlled by a configuration parameter
max_size
that defaults to 1000.Can be used in conjunction with w-n. However, if both options are given, the image will scale to fill the given area either by width or by height, get centered inside the area and additional spaces will get filled with white.
- thumbnail
-
requests the generation of a thumbnail image. Defaults to a maximum size of
thumbnail_size
. The size can get changed by a simple configuration parameter.
Configuration
A simple configuration of your Controller could look like this:
__PACKAGE__->config(
# the directory to look for files (inside root)
# defaults to 'static/images'
root_dir => 'static/images',
# specify a cache dir if caching is wanted
# defaults to no caching (more expensive)
cache_dir => undef,
# specify a format that will get delivered if
# not guessable from the file extension
# defaults to 'jpg'
default_format => 'jpg'
# specify a maximum value for width and height of images
# defaults to 1000 pixels
max_size => 1000,
# specify the size of thumbnails (always square)
# defaults to 80 pixels
thumbnail_size => 80,
# set jpeg quality
# defaults to 95
jpeg_quality => 95,
);
Caching
If caching is enabled (by setting the cache_dir
configuration parameter), every image rendered will get saved into the cache directory if it exists and the directory is writable.
The path of a cached image inside the cache directory is identical to the URI part after the action namespace. Thus, a properly configured webserver might take over the responsibility to deliver static images from cache removing the burden from your Catalyst Controller.
INTERNALS
This base class defines a Chained dispatch chain consisting of the following Action methods. Each method is responsible for eating up a defined part of the URI. The URI always consists of 3 parts: The namespace, a format and size modifier and a relative path to the image in question optionally with another file extension added for format conversion.
Action Chain
To allow easy modification the URI dispatching is left to Catalyst. The following :Chained
actions each work on a stage of the image construction. The final image will get delivered by the end
action.
- base
-
consumes the namespace of the controller inheriting this one.
- scale
-
consumes a single URI part. If the part is a concatenation of several things joined with a dash '-', then these things are regarded as either arguments to an action or further actions with their arguments.
If a modifier is named 'blur' and needs a single parameter, you may define a method like:
sub blur :Action :Args(1) { # do something to blur }
During this stage, the only thing that happens is recording every modification into a series of stash-variables.
- image
-
The final stage consumes the image path and tries to find the image in question.
After the image is found, a forward to 'generate_image' is issued which does the conversion we want.
Stash Variables
All action methods communicate with each other by setting or retrieving stash variables.
- image_path
-
relative path to original image
- image
-
Imager Object as soon as image is loaded
- image_data
-
binary image data after conversion or from cache
- cache_path
-
relative path to cached image
- format
-
format for conversion
- scale
-
{ w => n, h => n, mode => min/max/fit/fill }
- before_scale
-
list of Actions executed before scaling ### FIXME: action or subref???
- after_scale
-
list of Actions executed after scaling ### FIXME: action or subref???
EXTENDING
The magic behind all the conversions is the existence of specially named action methods (their name starts with 'want_' or 'scale_').
- want_
-
Actions starting with 'want_' get triggered if the URI part after the package namespace contains a word that matches the remainder of the action's name. The
:Arg()
attribute specifies how many additional parts this action will need for its operation. - scale_
-
One part of the scaling hash inside stash is a scaling mode. Depending on the name of the scaling mode, an action named 'scale_mode' is used to process the scaling.
If you plan to offer URIs like:
/image/small/image.jpg
/image/size-200-300/image.jpg
/image/watermark/image.jpg
# or a combination of them:
/image/size-200-300-watermark/image.jpg
# but not invalid things:
/image/size-200/image.jpg
you may build these action methods:
sub want_small :Action :Args(0) {
my ($self, $c) = @_;
$c->stash(scale => {w => 200, h => 200, mode => 'fill'});
}
sub want_size :Action :Args(2) {
my ($self, $c, $w, $h) = @_;
$c->stash(scale => {w => $w, h => $h, mode => 'fill'});
}
sub want_watermark :Action :Args(0) {
my ($self, $c) = @_;
### FIXME: action or subref???
push @{$c->stash->{after_scale}}, \&watermark_generator;
}
METHODS
BUILD
base :Chained :PathPrefix :CaptureArgs(0)
start of the action chain -- eats package namespace, eg. /image
scale :Chained('base') :PathPart('') :CaptureArgs(1)
second chain step -- eat up modifier parameter(s)
Modifier parameters and their args must be separated by single dashes ('-'). For every modifier there must exist an action named want_modifiername
declared with the number of args it wants to consume
# modifier 'h', one argument
# eg h-200
sub want_h :Action :Arg(1)
# modifier 'size, two arguments
# eg size-300-200
sub want_size :Action :Arg(2)
image :Chained('scale') :PathPart('') :Args
final chain step --consumes image path relative to root_dir plus optional format extension for conversion
convert_image :Action
The converting function. Consumes all conversion-relevant parameters from stash and does the conversion (or delivers a file from stash).
end :Action
deliver the data or fire a 404-status in case something went wrong.
Yes, I know, a 404 means 'not found', but for the end-user there is no difference between a not found image and an error that occured. And basically if somebody puts rubbush into the URL and calling an unknown action internally is a Internal server error, but for the end-user the requested image and its modification could not get retrieved.
scale_min :Action
scales an image by the minimum scaling factor needed to either match the desired width or height.
scale_max :Action
scales an image by the maximum scaling factor needed to either match the desired width or height.
scale_fit :Action
first scales an image by the maximum scaling factor needed to either match the desired width or height. Then, crops the image to make it fit the desired size.
scale_fill :Action
scales an image by the minimum scaling factor needed to either match the desired width or height. Then, expand the image with white color to make it fit the desired size.
want_thumbnail :Action :Args(0)
Logic for the 'thumbnail' modifier without further args. Sets the requested width and height to the thumbnail_size
configuration parameter (default is 80).
want_w :Action :Args(1)
Logic for the 'w' modifier with one arg. Sets the requested width of the image.
want_h :Action :Args(1)
Logic for the 'h' modifier with one arg. Sets the requested height of the image.
BUGS
probably many... Don't get confused if tests fail and carefully read the messages. The test-suite only will pass if Imager is configured with gif, jpeg and png support. In doubt install the required binary libraries and reinstall Imager.
AUTHOR
Wolfgang Kinkeldei, <wolfgang@kinkeldei.de>
LICENSE
This library is free software, you can redistribute it and/or modify it under the same terms as Perl itself.