Mandarin Duck (North Wales)

Creative Commons License photo credit: Cj Roberts

We’ve all been there: You have a website design. There are placeholders for galleries or thumbnails or what-have-you. Sweet as.

You code, fire up the browser and -

the images are all wrong! They are too large, your page looks awful, or you get sliders all over the place. Not happy at all.


This is even worse when you don’t control the images. Say you have to hotlink from somewhere, e.g. Amazon. What are you going to do?

Well – here we go, rsz helper to the rescue!

The helper is simple. I coded two methods, but of course you can extend it whichever way you want.

The first method receives the image url, and the maximum dimensions (width and height) it can take on your screen. The helper finds the actual dimensions of the image, calculates the new height and width – according to the maximum dimensions you pass in – and returns an array with the new dimensions. The new dimensions keep the aspect ratio of the image so it doesn’t appear distorted.
You can later use this array to output the image on your website:

// in /views/helpers/rsz.php
class RszHelper extends AppHelper {
...
    function imgResize($url,$x,$y) {
        if (empty($url)) {
            //if no image url received - return zero dimensions.
            return array(0,0);
        } else {
            try {
                $size = getimagesize( $url);
                $rx = $size[0] / $x;
                $ry = $size[1] / $y;
                if ($rx<=1 and $ry<=1) {
                    //if both ratios are smaller than 1 - the image fits alright inside the designated space.
                    return array($size[0],$size[1]);
                } else {
                    //resize as per the larger ratio
                    $r = max($rx,$ry);
                    return array(ceil($size[0]/$r),ceil($size[1]/$r));
                }
            }catch(Exception $e) {
                return array($x,$y);
            }
        }
    }
...
}

The code above resizes any image to the right dimensions. It returns an array with the new width and height. You can use this is your view as follows:

...
    <?php $xy = $rsz->imgResize("http://farm3.static.flickr.com/2284/2248449557_1ec805d771.jpg",200,100);
             //this image is 500x329 pixels. ?>
    <img src="http://farm3.static.flickr.com/2284/2248449557_1ec805d771.jpg" width="<?php echo $xy[0];?>" height="<?php echo $xy[1];?>" />
...

The image will be displayed in its new size: 152x100px.

You can change the helper to output the img tag directly, making your views cleaner, and allowing less space for copy/paste mistakes:

// in /views/helpers/rsz.php
class RszHelper extends AppHelper {
...
    function imgResizeAndPrint($url,$x,$y) {
        if (empty($url)) {
            //if no image url received - return zero dimensions.
            $xy = array(0,0);
        } else {
            try {
                $size = getimagesize( $url);
                $rx = $size[0] / $x;
                $ry = $size[1] / $y;
                if ($rx<=1 and $ry<=1) {
                    //if both ratios are smaller than 1 - the image fits alright inside the designated space.
                    return array($size[0],$size[1]);
                } else {
                    //resize as per the larger ratio
                    $r = max($rx,$ry);
                    $xy = array(ceil($size[0]/$r),ceil($size[1]/$r));
                }
            }catch(Exception $e) {
                $xy = array($x,$y);
            }
        }
        echo '<img src="' . $url . '" width="' . $xy[0] . '" height="' . $xy[1] . '" />';
    }
...
}

and in your view:

    <?php rsz->imgResizeAndPrint("http://farm3.static.flickr.com/2284/2248449557_1ec805d771.jpg",200,100); ?>

The problem with this method

The problem with this method is that you actually load the image twice. The helper loads the image on the server side (with getimageresize), and the client’s browser loads it on the client side. This is a bit wasteful and can make your pages load slower.

There are a few ways to overcome this, but it depends on the way you store your data. In my application, for example, I constantly retrieve new images, but once I load them, I store them in a table containing the image’s url, size and width.

The first time I load an image, I use getimagesize() to find its dimensions. I then store them in the table, and the next calls to the helper’s imgresize method do not need to visit the image’s url at all:

// in /views/helpers/rsz.php
class RszHelper extends AppHelper {
...
    //$ix and $iy are the original image's width and height.
    function imgResizeAndPrint($url,$x,$y,$ix=null,$iy=null) {
        if (empty($url)) {
            //if no image url received - return zero dimensions.
            $xy = array(0,0);
        } else {
            try {
                if ($ix==null and $iy==null) {
                    $size = getimagesize( $url);
                } else {
                    $size = array($ix, $iy);
                }
                $rx = $size[0] / $x;
                $ry = $size[1] / $y;
                if ($rx<=1 and $ry<=1) {
                    //if both ratios are smaller than 1 - the image fits alright inside the designated space.
                    return array($size[0],$size[1]);
                } else {
                    //resize as per the larger ratio
                    $r = max($rx,$ry);
                    return array(ceil($size[0]/$r),ceil($size[1]/$r));
                }
            }catch(Exception $e) {
                return array($x,$y);
            }
        }
   }
...
}

In this very simple case, getimagesize is called only if the image’s dimensions are null. Depending on your application, this method can be extended to either receive an Image model and update it, or to return more values if this is the first time it is called.

See an image resizer demo on Choozza.com

Popularity: 14% [?]

Tagged with:
 

One Response to Resize images on the fly with CakePHP

  1. armand says:

    You do not resize the image. You just display it smaller using html tag attributes. It would be nice to resize it ad display the resized image. As your display is now you still have to load the big file with the client browser.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Set your Twitter account name in your settings to use the TwitterBar Section.