[CakePHP] How to re-size images at run-time

This is a helper + controller combo for CakePHP which I often use. It helps to re-size images at run-time and also aid display them. Oh yes! once the image is resized it also caches them.

First let’s look at helper method.

  1. class MyHelper extends AppHelper
  2. {
  3.     function getImageUrl($path, $size, $file)
  4.     {
  5.         $filepath = WWW_ROOT . $path . DS . $size . DS . $file;
  6.  
  7.         if (is_file($filepath))
  8.         {
  9.             return r(array(WWW_ROOT, DS), '/', $filepath);
  10.         }
  11.  
  12.         return array
  13.         (
  14.             'controller' => 'images'
  15.             , 'action' => 'resize'
  16.             , 'file' => $file
  17.             , 'path' => $path
  18.             , 'size' => $size
  19.         );
  20.     }
  21. }

What above code does? If re-sized version of image already available then return it otherwise ‘/images/resize’ page will handle re-sizing.

So, how to use this? Set ‘My’ in $helpers array of your application controller or the needed controller and use it in view like

  1. echo $html->image($my->getImageUrl('files' . DS . 'avatars', '75-s', 'test.png'));

Now, you will wonder what ’75-s’ is. This is my way of handling various re-sizing methods, ’75-s’ means resize+crop to 75×75 (square) size. Also it has been assumed that ‘test.png’ exists in ‘[WWW_ROOT]/files/avatars’ directory.

Now let’s move to re-size part. The basic controller/action code contains

  1. class ImagesController extends AppController
  2. {
  3.     function resize()
  4.     {
  5.         $file = $this->params['size']
  6.         $path = $this->params['path']
  7.         $size = $this->params['size'];
  8.  
  9.         $aspect = false;
  10.         $resizedHeight = $resizedWidth = 0;
  11.  
  12.         // $size = 100; (Proportional - 100 as height or width whichever is longer)
  13.         if (ereg('^([1-9]+[0-9]*)$', $size))
  14.         {
  15.             $aspect = 'p';
  16.             $resizedHeight = $resizedWidth = $size;
  17.         }
  18.         /**
  19.          * $size = 100:h; (Proportional - 100 as height)
  20.          * $size = 100:s; (Square/crop - 100 as height and width)
  21.          * $size = 100:w; (Proportional - 100 as width)
  22.          */
  23.         else if (ereg('^([1-9]+[0-9]*:[h|s|w]+)$', $size))
  24.         {
  25.             list($dimension, $aspect) = explode(':', $size);
  26.  
  27.             if ('w' == $aspect)
  28.             {
  29.                 $resizedHeight = $dimension;
  30.             }
  31.             else if ('h' == $aspect)
  32.             {
  33.                 $resizedWidth = $dimension;
  34.             }
  35.         }
  36.         // $size = 100x150; (Exact [not proportional and no cropping] - 100 as width and 150 as height)
  37.         else if (ereg('^([1-9]+[0-9]*x[1-9]+[0-9]*)$', $size))
  38.         {
  39.             list($resizedWidth, $resizedHeight) = explode('x', $size);
  40.         }
  41.  
  42.         $original = WWW_ROOT . $path . DS . $file;
  43.         $resized = WWW_ROOT . $path . DS . $size . DS . $file;
  44.  
  45.         list($originalWidth, $originalHeight, $originalType) = getimagesize($original);
  46.  
  47.         $clipX = $clipY = 0;
  48.  
  49.         if (false !== $aspect)
  50.         {
  51.             if ('h' == $aspect)
  52.             {
  53.                 $ratio = ($originalHeight / $resizedHeight);
  54.             }
  55.             else if ('p' == $aspect)
  56.             {
  57.                 $ratio = (max($originalWidth, $originalHeight) / $resizedWidth);
  58.             }
  59.             else if ('s' == $aspect)
  60.             {
  61.                 $ratio = (min($originalWidth, $originalHeight) / $resizedWidth);
  62.             }
  63.             else if ('w' == $aspect)
  64.             {
  65.                 $ratio = ($originalWidth / $resizedWidth);
  66.             }
  67.  
  68.             $ratio = max($ratio, 1);
  69.  
  70.             if ('s' == $aspect)
  71.             {
  72.                 $resizedHeight = $resizedWidth = (int)(min($originalWidth, $originalHeight) / $ratio);
  73.  
  74.                 if ($originalHeight > $originalWidth)
  75.                 {
  76.                     $clipY = (int)(($originalHeight - $originalWidth) / 2);
  77.                     $originalHeight = $originalWidth;
  78.                 }
  79.                 else if ($originalWidth > $originalHeight)
  80.                 {
  81.                     $clipX = (int)(($originalWidth - $originalHeight) / 2);
  82.                     $originalWidth = $originalHeight;
  83.                 }
  84.             }
  85.             else
  86.             {
  87.                 $resizedWidth = (int)($originalWidth / $ratio);
  88.                 $resizedHeight = (int)($originalHeight / $ratio);
  89.             }
  90.         }
  91.         else
  92.         {
  93.             if ($resizedWidth > $originalWidth)
  94.             {
  95.                 $resizedWidth = $originalWidth;
  96.             }
  97.  
  98.             if ($resizedHeight > $originalHeight)
  99.             {
  100.                 $resizedHeight = $originalHeight;
  101.             }
  102.         }
  103.  
  104.         // If both width and height are same as original width and original height
  105.         if ($resizedWidth == $originalWidth && $resizedHeight == $originalHeight)
  106.         {
  107.             copy($original, $resized);
  108.         }
  109.         else
  110.         {
  111.             $types = array(1 => 'gif', 'jpeg', 'png');
  112.             $image = call_user_func('imagecreatefrom' . $types[$originalType], $original);
  113.  
  114.             if (function_exists('imagecreatetruecolor') && ($temp = imagecreatetruecolor($resizedWidth, $resizedHeight)))
  115.             {
  116.                 imagecopyresampled($temp, $image, 0, 0, $clipX, $clipY, $resizedWidth, $resizedHeight, $originalWidth, $originalHeight);
  117.             }
  118.             else
  119.             {
  120.                 $temp = imagecreate($resizedWidth, $resizedHeight);
  121.                 imagecopyresized($temp, $image, 0, 0, $clipX, $clipY, $resizedWidth, $resizedHeight, $originalWidth, $originalHeight);
  122.             }
  123.  
  124.             call_user_func('image' . $types[$originalType], $temp, $resized);
  125.         }
  126.     }
  127. }

which re-sizes the image properly (thanks to Coppermine Photo Gallery from which I borrowed re-sizing code).

That’s all. Please try and let me know how it worked for you.

Thanks

This code is best used when you are not really sure about the target size of the images, even with caching this is more CPU expensive than linking directly to resized images

About Amit Badkas

Amit Badkas is Zend certified PHP5 and Zend Framework engineer, and has been working in SANIsoft for past 10 years, his present designation is 'Technical Manager'

7 Responses to [CakePHP] How to re-size images at run-time

  1. Daniel Hofstetter August 30, 2010 at 9:02 pm #

    Wouldn’t it be cleaner to put everything into the helper? Or is there a special reason for using a controller for the resizing?

Trackbacks/Pingbacks

  1. Tweets that mention [CakePHP] How to re-size images at run-time at SANIsoft – PHP for E Biz -- Topsy.com - August 30, 2010

    [...] This post was mentioned on Twitter by Tarique Sani and Amit Badkas, Rohan Faye. Rohan Faye said: RT @amitrb: SANIsoft Blog: [CakePHP] How to re-size images at run-time http://t.co/eCprpXu [...]

  2. CakePHP : signets remarquables du 26/08/2010 au 02/09/2010 | Cherry on the... - September 2, 2010

    [...] How to re-size images at run-time at SANIsoft [...]

  3. [How To] Use of image magick instead of GD for run-time image re-sizing at SANIsoft – PHP for E Biz - October 4, 2010

    [...] image magick instead of GD for run-time image re-sizing TweetIn my last post, we looked at a way to re-size images at run time. That method used PHP's built-in GD library for image processing. So it may happen that image [...]

  4. jCrop Demo using PHP at SANIsoft – PHP for E Biz - November 8, 2010

    [...] last step is the actual cropping using PHP's GD library. Most of the code is borrowed from one of my previous articles. PLAIN TEXT [...]

Leave a Reply