Syomfony2: simple image resize helper

In almost every Symfony2 project I have the need for image resizing. So for each project I check (again) to see if there is a simple image resize helper introduced in Symfony2 core. Unfortunately there isn't and the community bundles are often way too advanced for my needs.

In the end I usually create my own simple image resize helper class that does one thing: Resize images. No advanced options like rotation, adding filters, etc. It just grabs an image and resizes it while keeping the original aspect ratio intact.

So, if you need a very simple image resize helper for Symfony 2, read on. If you are looking for a more advanced image manipulation bundle for Symfony2, grab the best one available @ https://github.com/liip/LiipImagineBundle.

Decide where to put the helper class

First you will need to decide where you want your helpers to live. In Symfony 2 terminology we will be adding a service. According to Symfony 2 best practises you can place your services anywhere, but it is advised to keep it in your bundle and to keep the name short.

I see a service as something bigger or more part of your custom core, so for this simple image resizing helper I used the following location: src/Company/MyBundle/Helper.
Services I place at src/Company/MyBundle/Service.

Create the image resize helper class

Now you can create the following file: src/Company/MyBundle/Helper/ImageResizer.php and paste in the following contents:

<?php

namespace Company\MyBundle\Helper;
use Symfony\Component\Filesystem\Filesystem;

class ImageResizer {

    /**
     * Resize an image
     *
     * @param string $image (The full image path with filename and extension)
     * @param string $newPath (The new path to where the image needs to be stored)
     * @param int $height (The new height to resize the image to)
     * @param int $width (The new width to resize the image to)
     * @return string (The new path to the reized image)
     */
    public function resizeImage($image, $newPath, $height=0, $width=0){

        // Get current dimensions
        $ImageDetails = $this->getImageDetails($image);
        $name = $ImageDetails->name;
        $height_orig = $ImageDetails->height;
        $width_orig = $ImageDetails->width;
        $fileExtention = $ImageDetails->extension;
        $ratio = $ImageDetails->ratio;
        $jpegQuality = 75;

        //Resize dimensions are bigger than original image, stop processing
        if ($width > $width_orig && $height > $height_orig){
            return false;
        }

        if($height > 0){
            $width = $height * $ratio;
        } else if($width > 0){
            $height = $width / $ratio;
        }
        $width = round($width);
        $height = round($height);

        $gd_image_dest = imagecreatetruecolor($width, $height);
        $gd_image_src = null;
        switch( $fileExtention ){
            case 'png' :
                $gd_image_src = imagecreatefrompng($image);
                imagealphablending( $gd_image_dest, false );
                imagesavealpha( $gd_image_dest, true );
                break;
            case 'jpeg': case 'jpg': $gd_image_src = imagecreatefromjpeg($image); 
                break;
            case 'gif' : $gd_image_src = imagecreatefromgif($image); 
                break;
            default: break;
        }

        imagecopyresampled($gd_image_dest, $gd_image_src, 0, 0, 0, 0, $width, $height, $width_orig, $height_orig);

        $filesystem = new Filesystem();
        $filesystem->mkdir($newPath, 0744);
        $newFileName = $newPath . $name . "." . $fileExtention;

        switch( $fileExtention ){
            case 'png' : imagepng($gd_image_dest, $newFileName); break;
            case 'jpeg' : case 'jpg' : imagejpeg($gd_image_dest, $newFileName, $jpegQuality); break;
            case 'gif' : imagegif($gd_image_dest, $newFileName); break;
            default: break;
        }

        return $newPath;
    }

    /**
     *
     * Gets image details such as the extension, sizes and filename and returns them as a standard object.
     *
     * @param $imageWithPath
     * @return \stdClass
     */
    private function getImageDetails($imageWithPath){
        $size = getimagesize($imageWithPath);

        $imgParts = explode("/",$imageWithPath);
        $lastPart = $imgParts[count($imgParts)-1];

        if(stristr("?",$lastPart)){
            $lastPart = substr($lastPart,0,stripos("?",$lastPart));
        }
        if(stristr("#",$lastPart)){
            $lastPart = substr($lastPart,0,stripos("#",$lastPart));
        }

        $dotPos     = stripos($lastPart,".");
        $name         = substr($lastPart,0,$dotPos);
        $extension     = substr($lastPart,$dotPos+1);

        $Details = new \stdClass();
        $Details->height    = $size[1];
        $Details->width        = $size[0];
        $Details->ratio        = $size[0] / $size[1];
        $Details->extension = $extension;
        $Details->name         = $name;

        return $Details;
    }
}
?>

Register the class as a service

Open up app/config/config.yml and add the following lines to the bottom:

services:
    helper.imageresizer:
        class: Company\MyBundle\Helper\ImageResizer

Please note that you need to use spaces in yml files, not tabs. You might need to refresh your cache afterwards.

Use the image resize helper in a controller

Now that we have registered the class we can use it in a controller as follows:

$this->get('helper.imageresizer')->resizeImage($originalFile, $path , $height=214);

Note:

You might have expected the class to also upload and cache the images. It does not, and with good reason. I like to decouple this functionality to allow myself to re-use it for other parts in the application. So yes, I also have cache and file upload helper classes :-)

There are plenty articles on how to create these, so if you need them, just grab one of those and port it to a Symfony2 Helper to handle these parts.

Questions?

Drop me a line on Twitter or Google+.