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

Tutorials - Big bits of code to help you do more

Improving image quality by preventing correctly sized images being resized

SSBimagequality

Sometimes you'll have to create websites for clients that are very demanding when it comes to image quality, say graphic designers or photographers. SilverStripe can be a showstopper here, since images are always being re-saved when you're using something like $SetHeight in your template. This can reduce image quality quite a lot, especially when using JPEG images.

A first thing to do is to crank up the GD default quality, by putting this in your _config.php file:

GD::set_default_quality(95);

But sometimes a client might prefer to prepare his images by himself. Then you really don't want SilverStripe to mess with these images. A simple solution would be to just use $Image in your template. But what if somebody uploads a huge image by mistake?

In an ideal world, SilverStripe would leave images that already match the target size untouched and only resize the ones that actually have to be resized. Luckily, this can be achieved by subclassing the Image class. Here's the class I use in all my projects:

<?php
/**
 * Prevents creation of resized images if the uploaded file already
 * fits the requested dimensions
 */
class BetterImage extends Image
{	
	public function SetWidth($width) {
		if($width == $this->getWidth()){
			return $this;
		}
			
		return parent::SetWidth($width);
	}
	
	public function SetHeight($height) {
		if($height == $this->getHeight()){
			return $this;
		}
			
		return parent::SetHeight($height);
	}
	
	public function SetSize($width, $height) {
		if($width == $this->getWidth() && $height == $this->getHeight()){
			return $this;
		}
		
		return parent::SetSize($width, $height);
	}
	
	public function SetRatioSize($width, $height) {
		if($width == $this->getWidth() && $height == $this->getHeight()){
			return $this;
		}
		
		return parent::SetRatioSize($width, $height);
	}
	
	public function getFormattedImage($format, $arg1 = null, $arg2 = null) {
		if($this->ID && $this->Filename && Director::fileExists($this->Filename)) {
			$size = getimagesize(Director::baseFolder() . '/' . $this->getField('Filename'));
			$preserveOriginal = false;
			switch(strtolower($format)){
				case 'croppedimage':
					$preserveOriginal = ($arg1 == $size[0] && $arg2 == $size[1]);
					break;
			}
			
			if($preserveOriginal){
				return $this;
			} else {
				return parent::getFormattedImage($format, $arg1, $arg2);
			}
		}
	}
}

This class overrides the SetWidth, SetHeight, SetSize, SetRatioSize and CroppedImage methods and always uses the original image if it already fits the requested dimensions.

Making use of the class is simple. Instead of having:

public static $has_one = array(
	'MyImage' => 'Image'
);

in your Pages/DataObjects you would now write:

public static $has_one = array(
	'MyImage' => 'BetterImage'
);

and use it like a regular image. Migrating an existing project to use the BetterImage class is simple as well. Just put the class (BetterImage.php) somewhere in cour mysite/code folder and replace all relations from Image to BetterImage (as shown above). Then run dev/build and you're set.

Feel free to merge in methods for rotating and grayscale conversion from Aram's tutorial, to get the "Uber-Image-Class".

Roman Schmid avatar

Roman Schmid

Graphic Designer and Software Developer. Also known as 'banal'

  • swaiba
    07/01/2011 12:35pm (4 years ago)

    Hi, does this overide the 600x600 limitation in... cms\code\ThumbnailStripField.php?

    This is one of a handful of hacks I perform on the core code each time...

  • Roman Schmid
    07/01/2011 12:41pm (4 years ago)

    @swaiba: I don't think so.

  • swaiba
    07/01/2011 12:49pm (4 years ago)

    shame :( I have no idea why but this has affected a couple of sites where a graphcis guy is complaining "why are my images maxed at 600" I'll get round to a patch one day

  • Matty Balaam
    08/01/2011 1:46pm (4 years ago)

    Brilliant! I'm mainly a Graphic Designer and have been frustrated by the re-compressing of images since I started using Silverstripe, I'll definitely be putting this onto my site ASAP.

  • Brice Burgess
    11/01/2011 6:14pm (4 years ago)

    I agree with "In an ideal world, SilverStripe would leave images that already match the target size untouched and only resize the ones that actually have to be resized."

    What about patching the base Image class with this behavior and submitting to open.silverstripe.org?

  • Roman Schmid
    11/01/2011 8:20pm (4 years ago)

    @Brice You're right. This could just as well be in the core. Will prepare a patch in the near future.

  • Matt Clegg
    12/01/2011 12:22pm (4 years ago)

    Hi Brice / Roman,

    There is already a patch for SilverStripe GD

    http://open.silverstripe.org/attachment/ticket/5416

    This patch pads images in both directions as opposed to only padding one and stretching the other.

  • Bodkin
    17/01/2011 1:16pm (4 years ago)

    Agree, this should be in the Sapphire core base Image class ASAP for sure, current GD treatment gives poor results for such things as portfolios. Excellent tip, thanks Roman, would you have a quick howto on augmenting this in Arrons ImageGallery mod perhaps? I suspect this is where this mod would be extremely useful. I did try, unsuccessfully so any pointers would be great.

  • William Melbourne
    17/01/2011 9:04pm (4 years ago)

    would this effect the image tool crashing when big images are uploaded. I have had a problem / opportunity with quite a few of my clients where they tried to upload a big image from their camera. everyone has 10MP cameras these days whether needed or not and but not many of them know how to compress images or want to, so when they use the cms to upload the images it crashes. any thoughts?

  • Roman Schmid
    25/01/2011 4:42pm (4 years ago)

    @William No this won't help with memory problems, since you'll hit the memory limit as soon as the image is being read into a GD image (for example to create the thumbnail in the CMS). That would actually require another patch that would check image-size against available memory before doing any image processing whatsoever.

  • Ryan M
    22/03/2011 1:09am (3 years ago)

    I'd like to add that this function doesn't do anything to prevent smaller images from being enlarged. So the height & width operators should be changed from == to >=

  • Mom Bunheng
    05/04/2011 4:42am (3 years ago)

    I have tested it work great! Thanks for sharing.

  • Darren-Lee
    09/04/2011 1:49pm (3 years ago)

    Thanks...this snippet came in handy to satisfy the whims of a graphics designer who was complaining about the Silverstripe CMS affecting the quality of her images that she painstakingly prepared, optimised and trimmed to the correct size beforehand. Thanks for sharing.

  • Hoop
    26/06/2012 9:05am (2 years ago)

    Is this also working for Silverstripe 3?

  • Nivanka Fonseka
    15/09/2012 4:06am (2 years ago)

    I think this is not needed for SS 3, there was a discussion going on about not to resize if the images are a correct sizes

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 Ty Barho
6 article image Martijn van Nieuwenhoven
7 article image Darren-Lee
8 article image Roman Schmid
9 article image Matt Clegg
10 article image dalesaurus

View full leaderboard


Advertisement