SSbits - Home page
Site by Carbon Crayon
Submit a Post >

Tutorials - Big bits of code to help you do more

Rotating and Greyscaling Images using GD and Decorators

SSBmanipulatingimages

Some of you might have noticed that SilverStripe's GD class has a couple of interesting looking functions, namely rotate($angle) and greyscale($Red, $Green, $Blue). However it was never quite clear how to use these functions (at least not to me anyway!). So after a bit of trial and error, it turns out it's pretty simple to achieve by decorating the image class and adding a couple of simple functions...

Before we get into the code, it's worth understanding how communication with GD works in SilverStripe. If you look in the Image class (sapphire/core/model/Image.php) you will see that it provides 2 functions for each type of resize. For instance for setting an images height we have SetHeight($height) and generateSetHeight(GD $gd, $height). The first of these functions is what is called from the template or controller, which in turn calls a generic function inside Image called getFormattedImage('SetHeight', $height) which searches for a cached image of that size and if it doesn't find one it calls generateFormattedImage('SetHeight', $height). This generic generate function then calls the generateSetHeight() function which then finally communicates with the GD class and generates the SetHeight image and returns it to whoever originally requested it.

Now all that may sound quite complex, but what it effectively means is that in order to take advantage of the rotate() and greyscale() functions inside GD, all we need to do is provide the two format specific functions inside a class that decorates Image. So here is our Image class decorator called FunkyImageDecorator with our 2 rotation functions:

<?php

class FunkyImageDecorator extends DataObjectDecorator
{
	/* Rotated image */
	public function RotatedImage($angle) 
	{
		return $this->owner->getFormattedImage('RotatedImage', $angle);
	}

	public function generateRotatedImage(GD $gd, $angle) 
	{
		return $gd->rotate($angle);
	}
}

So all we are doing here is providing ourselves with the ability to call $Image->RotatedImage(90) from within our Controller or $Image.RotatedImage(90) from within our template. As will all decorators, before we can use this we need to tell SilverStripe that we want to decorate the Image class. We do this by adding this line to our _config.php file:

Object::add_extension('Image', 'FunkyImageDecorator');

Greyscale

In order to do the same with greyscale, here are the two functions:

	/* Greyscale image */
	public function GreyscaleImage($RGB = '100 100 100') 
	{
		return $this->owner->getFormattedImage('GreyscaleImage', $RGB);
	}

	public function generateGreyscaleImage(GD $gd, $RGB) 
	{
		$Vars = explode(' ', $RGB);		
		
		return $gd->greyscale( $Vars[0], $Vars[1], $Vars[2]);
	}

The slight difference here is that because we can only pass in 2 extra parameters around the generate functions in the Image class and we need three, we have to pass all three as a single string and break them up just before passing them to GD. We also provide a default so that we can just call $Image.GreyscaleImage without any parameters. Let's say we actually wanted a greyscale version of an image based only on the Blue channel we would write this in our template: $Image.GreyscaleImage(0 0 255) or $Image->GreyscaleImage('0 0 255'); in our controller. Notice that we have spaces instead of commas between the values because we are passing them as a string which we then break into individual colours in the generateGreyscaleImage() function.

Resizing Rotated & Greyscaled Images

This is where things become a little limited. Because we are not actually changing the original image, in order to combine  two processes we have to create a specific function which returns the right Image. So let's say we wanted an image resized by a specified height and then rotated, we would need to add these two functions to our FunkyImageDecorator class:

	/* Thumbnail Rotated image */
	public function ThumbnailRotatedImage($angle) 
	{
		return $this->owner->getFormattedImage('RotatedImage', $angle);
	}

	public function generateThumbnailRotatedImage(GD $gd, $angle) 
	{
		return $gd->croppedResize(100,150)->rotate($angle);
	}

Then in our template to get a thumbnail 300 pixels high and rotated 180degrees we would do $Image.SetHeightRotatedImage(180,300).

Now remember that you can only pass up to 2 parameters. So if you wanted to say pass the width and height of a cropped image along with the rotation angle you will need to do something a little smarter like we did in the greyscale example above.

That's it! You can now start creating combinations of manipulating functions to your hearts content :)

 

Special Thanks

Special thanks go to Daniel Hensby for their contributions to this post.

Aram Balakjian avatar

Aram Balakjian

Aram is a web developer running London based agency Aab Web. He has a strong passion for developing attractive, usable sites around the SilverStripe CMS.

  • abyss
    08/12/2010 9:46pm (4 years ago)

    Thanks for this great article, was exactly the solution to my problem (again). Keep up the great work, highly appreciated.

    Credits given here: http://silverstripe.org/template-questions/show/15113#post296479

  • Jono Menz
    29/03/2012 7:21pm (2 years ago)

    The code under "Resizing Rotated & Greyscaled Images" doesn't seem to match the description? Doesn't seem to be using the specified height.

Post a comment ...

You cannot post comments until you have logged in. Login Here.

Advertisement

Site of the Month

Find SSbits on

Top Contributers

Rank Avatar Name
1 article image Aram Balakjian
2 article image Daniel Hensby
3 article image Marcus Dalgren
4 article image Hamish Campbell
5 article image njorndare
6 article image Ty Barho
7 article image Martijn van Nieuwenhoven
8 article image Darren-Lee
9 article image Roman Schmid
10 article image Matt Clegg

View full leaderboard


Advertisement