![]() |
|
sfImageTransformExtraPlugin - 0.9.4Christian Schaefer <caefer@ical.ly> |
|
![]() |
53
users
Sign-in
to change your status |
Christian Schaefer <caefer@ical.ly> |
Utilising the fantastic sfImageTransformPlugin this plugin provides all means to configure any set of thumbnail formats with all possible transformations in a YAML file. All these configured settings can be applied to any kind of source image using a nice URL schema.
| Name | Status | |
|---|---|---|
|
|
lead | yl.laci <<ta>> refeac |
Copyright (c) 2010 Christian Schaefer
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
OR OTHER DEALINGS IN THE SOFTWARE
| Version | License | API | Released |
|---|---|---|---|
| 1.0.12stable | MIT license | 1.0.0stable | 24/11/2010 |
| 1.0.11stable | MIT license | 1.0.0stable | 22/11/2010 |
| 1.0.10stable | MIT license | 1.0.0stable | 16/08/2010 |
| 1.0.9stable | MIT license | 1.0.0stable | 22/07/2010 |
| 1.0.8stable | MIT license | 1.0.0stable | 22/07/2010 |
| 1.0.7stable | MIT license | 1.0.0stable | 21/07/2010 |
| 1.0.6stable | MIT license | 1.0.0stable | 21/07/2010 |
| 1.0.5stable | MIT license | 1.0.0stable | 24/06/2010 |
| 1.0.4stable | MIT license | 1.0.0stable | 31/05/2010 |
| 1.0.3stable | MIT license | 1.0.0stable | 18/05/2010 |
| 1.0.2stable | MIT license | 1.0.0stable | 12/05/2010 |
| 1.0.1stable | MIT license | 1.0.0stable | 28/04/2010 |
| 1.0.0stable | MIT license | 1.0.0stable | 26/04/2010 |
| 0.9.9beta | MIT license | 0.9.0beta | 13/04/2010 |
| 0.9.8beta | MIT license | 0.9.0beta | 06/04/2010 |
| 0.9.7beta | MIT license | 0.9.0beta | 31/03/2010 |
| 0.9.6beta | MIT license | 0.9.0beta | 25/03/2010 |
| 0.9.5beta | MIT license | 0.9.0beta | 24/03/2010 |
| 0.9.4beta | MIT license | 0.9.0beta | 23/03/2010 |
| 0.9.3beta | MIT license | 0.9.0beta | 21/03/2010 |
| 0.9.2beta | MIT license | 0.9.0beta | 21/03/2010 |
| 0.9.1beta | MIT license | 0.9.0beta | 14/03/2010 |
| 0.9.0beta | MIT license | 0.9.0beta | 14/03/2010 |
| Name | Channel | Version |
|---|---|---|
| sfImageTransformPlugin | plugins.symfony-project.org | 1.3.0-1.3.2 |
$ php symfony --color transforms:check-caching frontend
Run this task to check if your settings allow the thumbnail caching to work properly.
>> no script name sf_no_script_name is set to true.
>> caching sf_cache is set to true.
>> route 'sf_image' exists.
>> route Route 'sf_image' points to '/thumbnails/in/some/deeper/path/'.
>> route The absolute path for this is '/path/to/your/project/web/thumbnails/in/some/deeper/path/'.
>> cache dir Path '/thumbnails/in/some/deeper/path' does not exist. Let's move one level up.
>> cache dir Path '/thumbnails/in/some/deeper' does not exist. Let's move one level up.
>> cache dir Path '/thumbnails/in/some' does not exist. Let's move one level up.
>> cache dir Path '/thumbnails/in' does not exist. Let's move one level up.
>> cache dir Path '/path/to/your/project/sfiteptask/web/thumbnails' exists.
>> cache dir Path '/path/to/your/project/sfiteptask/web/thumbnails' is a directory.
>> cache dir Path '/path/to/your/project/sfiteptask/web/thumbnails' is writable.
Please note that this check is testing priviledges for your current user account.
If your web server is running from a different user account (as it should) the result could be different.
Everything seems to be alright. If it still does not work it's probably a permissions problem.
This is a bugfix release. Remote image sources depending on their binary structure might not have been able to detect the mime type of. This was caused by getimagesize() seeking when mime information could not be read from the first chunk of data.
PLEASE NOTE! In this release there is a bugfix of the autoboxing feature which requires you to change your thumbnailing.yml if you use transformations like overlay or alphamask. In this case you have to prefix the overlay and mask parameters with "sfImage|". See http://trac.symfony-project.org/changeset/29292 for an example.
> THIS IS HIGHLY PRELIMINARY!

On a website you ususally find lots of images and a set of formats.
For example let's say a user avatar is always 80x80 PNG while a homepage top image is always 320x140 JPG with round corners.
As it is far too costly to prepare all these different formats by hand there are automated ways to generate them from source images uploaded by a user. One of the best tools for this in the symfony world is the sfImageTransformPlugin which enables you to perform many sophisticated transformations on your images such as resizing, color manipulation, overlays and more.
Using such an automatism means you have to write code and perform all necessary transformation on upload, no matter if the generated files are ever requested. It also means that design changes that also change the formats lead to change of business logic rather than just templates.
This is where sfImageTransformExtraPlugin springs to action as it provides a way to configure formats with multiple transformations. In your templates you only refer to the format by name which results in an SEO friendly image URL. The image itself will be generated on first request and (in production environments) written to the filesystem.
Here are some of the key features:
Consider the following source image.
![]()
Here are just a few examples that were all transformed from the above image.
![]()
![]()
![]()
![]()
![]()
And of course:
![]()
Of course you can chain transformations!
In fact most of the above thumbnails have two transformations applied one for resizing and another for the effect.
Let's see how it works and start with the original again. The format looks like this.
star0:
quality: 25
mime_type: image/png
transformations: ~
With the following result.
![]()
Now let's add a crop transformation to get to the correct dimensions.
star1:
quality: 25
mime_type: image/png
transformations:
- { adapter: GD, transformation: crop, param: { left: 90, top: 72, width: 120, height: 120 }}
![]()
And just to be a bit different we want to rotate.
star2:
quality: 25
mime_type: image/png
transformations:
- { adapter: GD, transformation: crop, param: { left: 90, top: 72, width: 120, height: 120 }}
- { adapter: GD, transformation: rotate, param: { angle: 20, background: '#FFFFFF' }}
![]()
The blank spots are not what we want so let's crop it again.
star3:
quality: 25
mime_type: image/png
transformations:
- { adapter: GD, transformation: crop, param: { left: 90, top: 72, width: 120, height: 120 }}
- { adapter: GD, transformation: rotate, param: { angle: 20, background: '#FFFFFF' }}
- { adapter: GD, transformation: crop, param: { left: 17, top: 17, width: 120, height: 120 }}
![]()
So we are back to the dimensions we wanted. Now we want a watermark on top of it.
star4:
quality: 25
mime_type: image/png
transformations:
- { adapter: GD, transformation: crop, param: { left: 90, top: 72, width: 120, height: 120 }}
- { adapter: GD, transformation: rotate, param: { angle: 20, background: '#FFFFFF' }}
- { adapter: GD, transformation: crop, param: { left: 17, top: 17, width: 120, height: 120 }}
- { adapter: GD, transformation: overlay, param: { overlay: overlays/logo.png, position: center }}
![]()
Of course this is not "Web 2.0" enough yet..
star5:
quality: 25
mime_type: image/png
transformations:
- { adapter: GD, transformation: crop, param: { left: 90, top: 72, width: 120, height: 120 }}
- { adapter: GD, transformation: rotate, param: { angle: 20, background: '#FFFFFF' }}
- { adapter: GD, transformation: crop, param: { left: 17, top: 17, width: 120, height: 120 }}
- { adapter: GD, transformation: overlay, param: { overlay: overlays/logo.png, position: center }}
- { adapter: GD, transformation: overlay, param: { overlay: overlays/star_frame.png, position: center }}
![]()
Now we want to get rid of the bits that stick out by applying an alpha mask.
star6:
quality: 25
mime_type: image/png
transformations:
- { adapter: GD, transformation: crop, param: { left: 90, top: 72, width: 120, height: 120 }}
- { adapter: GD, transformation: rotate, param: { angle: 20, background: '#FFFFFF' }}
- { adapter: GD, transformation: crop, param: { left: 17, top: 17, width: 120, height: 120 }}
- { adapter: GD, transformation: overlay, param: { overlay: overlays/logo.png, position: center }}
- { adapter: GD, transformation: overlay, param: { overlay: overlays/star_frame.png, position: center }}
- { adapter: GD, transformation: alphaMask, param: { mask: masks/star_mask.gif }}
![]()
Done! ;)
The generation process that we designed so far works like this:
The thumbnail image is generated on the first request. All succeeding requests are coming from cache (per default the filesystem) and are served by Apache without spawning a PHP process.
Image generation is quite expansive in terms of CPU and memory. This is why sfsfImageTransformExtraPlugin by default stores generated images for the production environment on the filesystem.
For this the custom cache class sfRawFileCache is used which is basically a copy of sfFileCache but does not prepend the cached file with expire time information but instead saves only the generated image.
You can see the typical lifecycle of a generated image in the following Firebug screenshots.
![]()
The image is generated, saved to the filesystem and sent to the requesting browser.
![]()
The image is read directly from the filesystem without invoking a PHP process.
![]()
Apache automatically informs the browser that the image has not been modified by sending a 304 status.
As you can see the time needed to deliver a generated image after the second request is drastically reduced. (The times will vary on different installations.)
The deletion of generated images use the sfCache interface and can be triggered by a task of a symfony event.
To install the plugin for a symfony project, the usual process is to use the symfony command line:
$ php symfony plugin:install sfImageTransformExtraPlugin
Alternatively, if you don't have PEAR installed, you can download the latest package attached to this plugin's wiki page and extract it under your project's plugins/ directory.
Activate the plugin in your ProjectConfiguration.class.php.
// /config/ProjectConfiguration.class.php
... $this->enablePlugins(..., 'sfImageTransformPlugin', 'sfImageTransformExtraPlugin'); ...
Enable the generating module in your settings.yml.
// /apps/yourapplication/config/settings.yml
all:
.settings:
enabled_modules: [ ..., sfImageTransformator ]
...
You also need to configure automatic mime detection for sfImageTransformPlugin in your applications app.yml.
// /apps/yourapplication/config/app.yml
all:
sfImageTransformPlugin:
mime_type:
auto_detect: true
library: gd_mime_type # gd_mime_type (GD), Fileinfo (PECL), MIME_Type (PEAR)
font_dir: %SF_PLUGINS_DIR%/sfImageTransformExtraPlugin/data/example-resources/fonts
...
Automatic mime detection is absolutely necessary!
Of course you can point the font_fir to your own location containing True Type Fonts.
Clear the cache to enable the autoloading to find the new classes:
$ php symfony cc
Note: The plugin requires sfImageTransformPlugin to be installed as well. The dependencies described there apply as well so please follow the README.
Next you have to configure your routes.
Your image sources lie in a directory accessible to your web server and you want to keep the filenames.
Create a route like the following in your applications routing.yml.
// /apps/yourapplication/config/routing.yml
sf_image: class: sfImageTransformRoute url: /thumbnails/:format/:filepath.:sf_format param: { module: sfImageTransformator, action: index } requirements: format: '[\w_-]+' filepath: '[\w/]+' sf_format: 'gif|png|jpg' sf_method: [ get ] options: image_source: File ...
You can now generate <img /> tags to these images like this.
<?php
echo image_tag(url_for('sf_image_file', array('format' => 'pixelate', 'filepath' => 'logo.png')));
// resulting in: http://localhost/thumbnails/pixelate/logo.png.jpg ?>
Please note that the filepath is expected relative to
sf_upload_dir!
Your image sources lie in a directory accessible to your web server and you want to keep the filenames.
Create a route like the following in your applications routing.yml.
// /apps/yourapplication/config/routing.yml
sf_image:
class: sfImageTransformRoute
url: /thumbnails/:type/:format/:path/:slug-:id.:sf_format
param: { module: sfImageTransformator, action: index, attribute: file }
requirements:
format: '[\w_-]+'
path: '[\w/]+'
slug: '[\w_-]+'
id: '\d+(?:,\d+)?'
sf_format: 'gif|png|jpg'
sf_method: [ get ]
options:
image_source: Doctrine
segment_separators: [ '/', '.', '-' ]
...
You can now generate <img /> tags to these images like this.
<?php
echo image_tag(url_for('sf_image_doctrine', array('format' => 'pixelate', 'sf_subject' => $record)));
// resulting in: http://localhost/thumbnails/News/pixelate/01/00/00/mytest-1.jpg ?>
$record in this example is either a Doctrine or Propel record.
Your image sources lie in a directory accessible to your web server and you want to keep the filenames.
Create a route like the following in your applications routing.yml.
// /apps/yourapplication/config/routing.yml
sf_image:
class: sfImageTransformRoute
url: /thumbnails/sfweb/:format/:filepath.:sf_format
param: { module: sfImageTransformator, action: index, protocol: http, domain: www.symfony-project.org }
requirements:
format: '[\w_-]+'
sf_format: http|https
domain: '[\w-_.]+'
filepath: '[\w/-_.]+'
sf_format: 'gif|png|jpg'
sf_method: [ get ]
options:
image_source: HTTP
...
You can now generate <img /> tags to these images like this.
<?php
echo image_tag(url_for('sf_image_http', array('format' => 'pixelate', 'filepath' => 'images/symfony-reloaded.png')));
// resulting in: http://localhost/thumbnails/sfweb/pixelate/images/symfony-reloaded.png.jpg ?>
trigger event run task
see also twiggering invalidation when using sfImageTransformExtraPlugin as a web service further down in this document.
To run sfImageTransformExtraPlugin as a web service you create a new symfony installation and install the plugin as described in the previous chapter.
You then have to create a configuration file called thumbnailing.yml in your applications config directory with the following contents:
all:
source_image:
class: sfImageSourceHTTP
param:
url_schema: http://yourhost/%type/%id/%attribute
As the invalidation of the generated images can not be triggered with an event you will have to create a new route that can be called as a trigger.
EXAMPLE
If you serve your generated images from a web service installation you have to prefix the URL with the domain of your service.
<?php echo image_tag('http://your.webservice.url'.url_for(...), array());
write a new stream wrapper
prepareParameters()
$ cd /path/to/sfImageTransformExtraPlugin
$ phpunit --tap test/sfImageTransformExtraPluginsTests.php
$ cd /path/to/sfImageTransformExtraPlugin
$ phpdoc ...

