My (mostly technical) blog

Image Upload and Resize Component for CakePHP 1.2

Posted by: sabbour on: May 13, 2008

Update:
Newer version

I needed to upload images to my CakePHP based website and at the same time, I needed to resize and create thumbnails of those images.

I found some different components on the Bakery and I found some code here, but I needed something more, I needed to have the ability to generate square zoomed thumbnails out of the uploaded images.

Since I was new to CakePHP and I wanted to improve my skills, I ended up taking code from several sources, writing some of my own, and integrating them in a component.

Big version resized using scale: 573

Small version resized using scale 110

Small version resized using scale 110 / square

You can download the code from here or here and you can take a look at it below.

<?php
/*
 File: /app/controllers/components/image.php
*/
class ImageComponent extends Object
{
    /*
    *    Uploads an image and its thumbnail into $folderName/big and $folderName/small respectivley.
    *     the  generated thumnail could either have the same aspect ratio as the uploaded image, or could
    *    be a zoomed and cropped version.

    *     Directions:
    *    In view where you upload the image, make sure your form creation is similar to the following
    *    <?= $form->create('FurnitureSet',array('type' => 'file')); ?>
    *
    *    In view where you upload the image, make sure that you have a file input similar to the following
    *    <?= $form->file('Image/name1'); ?>
    *
    *    In the controller, add the component to your components array
    *    var $components = array("Image");
    *
    *    In your controller action (the parameters are expained below)
    *    $image_path = $this->Image->upload_image_and_thumbnail($this->data,"name1",573,80,"sets",true);
    *    this returns the file name of the result image.  You can  store this file name in the database
    *
    *    Note that your image will be stored in 2 locations:
    *    Image: /webroot/img/$folderName/big/$image_path
    *    Thumbnail:  /webroot/img/$folderName/small/$image_path
    *
    *    Finally in the view where you want to see the images
    *    <?= $html->image('sets/big/'.$furnitureSet['FurnitureSet']['image_path']);
    *     where "sets" is the folder name we saved our pictures in, and $furnitureSet['FurnitureSet']['image_path'] is the file name we stored in the database

    *    Parameters:
    *    $data: CakePHP data array from the form
    *    $datakey: key in the $data array. If you used <?= $form->file('Image/name1'); ?> in your view, then $datakey = name1
    *    $imgscale: the maximum width or height that you want your picture to be resized to
    *    $thumbscale: the maximum width or height that you want your thumbnail to be resized to
    *    $folderName: the name of the parent folder of the images. The images will be stored to /webroot/img/$folderName/big/ and  /webroot/img/$folderName/small/
    *    $square: a boolean flag indicating whether you want square and zoom cropped thumbnails, or thumbnails with the same aspect ratio of the source image
    */
    function upload_image_and_thumbnail($data, $datakey, $imgscale, $thumbscale, $folderName, $square) {
        if (strlen($data['Image'][$datakey]['name'])>4){
                    $error = 0;
                    $tempuploaddir = "img/temp"; // the /temp/ directory, should delete the image after we upload
                    $biguploaddir = "img/".$folderName."/big"; // the /big/ directory
                    $smalluploaddir = "img/".$folderName."/small"; // the /small/ directory for thumbnails

                    // Make sure the required directories exist, and create them if necessary
                    if(!is_dir($tempuploaddir)) mkdir($tempuploaddir,true);
                    if(!is_dir($biguploaddir)) mkdir($biguploaddir,true);
                    if(!is_dir($smalluploaddir)) mkdir($smalluploaddir,true);

                    $filetype = $this->getFileExtension($data['Image'][$datakey]['name']);
                    $filetype = strtolower($filetype);

                    if (($filetype != "jpeg")  && ($filetype != "jpg") && ($filetype != "gif") && ($filetype != "png"))
                    {
                        // verify the extension
                        return;
                    }
                    else
                    {
                        // Get the image size
                        $imgsize = GetImageSize($data['Image'][$datakey]['tmp_name']);
                    }

                    // Generate a unique name for the image (from the timestamp)
                    $id_unic = str_replace(".", "", strtotime ("now"));
                    $filename = $id_unic;

                    settype($filename,"string");
                    $filename.= ".";
                    $filename.=$filetype;
                    $tempfile = $tempuploaddir . "/$filename";
                    $resizedfile = $biguploaddir . "/$filename";
                    $croppedfile = $smalluploaddir . "/$filename";

                    if (is_uploaded_file($data['Image'][$datakey]['tmp_name']))
                    {
                        // Copy the image into the temporary directory
                        if (!copy($data['Image'][$datakey]['tmp_name'],"$tempfile"))
                        {
                            print "Error Uploading File!.";
                            exit();
                        }
                        else {
                            /*
                             *    Generate the big version of the image with max of $imgscale in either directions
                             */
                            $this->resize_img($tempfile, $imgscale, $resizedfile);                            

                            if($square) {
                                /*
                                 *    Generate the small square version of the image with scale of $thumbscale
                                 */
                                $this->crop_img($tempfile, $thumbscale, $croppedfile);
                            }
                            else {
                                /*
                                 *    Generate the big version of the image with max of $imgscale in either directions
                                 */
                                $this->resize_img($tempfile, $thumbscale, $croppedfile);
                            }

                            // Delete the temporary image
                            unlink($tempfile);
                        }
                    }

                     // Image uploaded, return the file name
                     return $filename;
        }
    }

    /*
    *    Deletes the image and its associated thumbnail
    *    Example in controller action:    $this->Image->delete_image("1210632285.jpg","sets");
    *
    *    Parameters:
    *    $filename: The file name of the image
    *    $folderName: the name of the parent folder of the images. The images will be stored to /webroot/img/$folderName/big/ and  /webroot/img/$folderName/small/
    */
    function delete_image($filename,$folderName) {
        unlink("img/".$folderName."/big/".$filename);
        unlink("img/".$folderName."/small/".$filename);
    }

    function crop_img($imgname, $scale, $filename) {
        $filetype = $this->getFileExtension($imgname);
        $filetype = strtolower($filetype);

        switch($filetype){
            case "jpeg":
            case "jpg":
              $img_src = ImageCreateFromjpeg ($imgname);
             break;
             case "gif":
              $img_src = imagecreatefromgif ($imgname);
             break;
             case "png":
              $img_src = imagecreatefrompng ($imgname);
             break;
        }

        $width = imagesx($img_src);
        $height = imagesy($img_src);
        $ratiox = $width / $height * $scale;
        $ratioy = $height / $width * $scale;

        //-- Calculate resampling
        $newheight = ($width <= $height) ? $ratioy : $scale;
        $newwidth = ($width <= $height) ? $scale : $ratiox;

        //-- Calculate cropping (division by zero)
        $cropx = ($newwidth - $scale != 0) ? ($newwidth - $scale) / 2 : 0;
        $cropy = ($newheight - $scale != 0) ? ($newheight - $scale) / 2 : 0;

        //-- Setup Resample & Crop buffers
        $resampled = imagecreatetruecolor($newwidth, $newheight);
        $cropped = imagecreatetruecolor($scale, $scale);

        //-- Resample
        imagecopyresampled($resampled, $img_src, 0, 0, 0, 0, $newwidth, $newheight, $width, $height);
        //-- Crop
        imagecopy($cropped, $resampled, 0, 0, $cropx, $cropy, $newwidth, $newheight);

        // Save the cropped image
        switch($filetype)
        {
            case "jpeg":
            case "jpg":
             imagejpeg($cropped,$filename,80);
             break;
             case "gif":
             imagegif($cropped,$filename,80);
             break;
             case "png":
             imagepng($cropped,$filename,80);
             break;
        }
    }

    function resize_img($imgname, $size, $filename)    {
        $filetype = $this->getFileExtension($imgname);
        $filetype = strtolower($filetype);

        switch($filetype) {
            case "jpeg":
            case "jpg":
            $img_src = ImageCreateFromjpeg ($imgname);
            break;
            case "gif":
            $img_src = imagecreatefromgif ($imgname);
            break;
            case "png":
            $img_src = imagecreatefrompng ($imgname);
            break;
        }

        $true_width = imagesx($img_src);
        $true_height = imagesy($img_src);

        if ($true_width>=$true_height)
        {
            $width=$size;
            $height = ($width/$true_width)*$true_height;
        }
        else
        {
            $width=$size;
            $height = ($width/$true_width)*$true_height;
        }
        $img_des = ImageCreateTrueColor($width,$height);
        imagecopyresampled ($img_des, $img_src, 0, 0, 0, 0, $width, $height, $true_width, $true_height);

        // Save the resized image
        switch($filetype)
        {
            case "jpeg":
            case "jpg":
             imagejpeg($img_des,$filename,80);
             break;
             case "gif":
             imagegif($img_des,$filename,80);
             break;
             case "png":
             imagepng($img_des,$filename,80);
             break;
        }
    }

    function getFileExtension($str) {

        $i = strrpos($str,".");
        if (!$i) { return ""; }
        $l = strlen($str) - $i;
        $ext = substr($str,$i+1,$l);
        return $ext;
    }
} ?>

25 Responses to "Image Upload and Resize Component for CakePHP 1.2"

Looks very nice. Good job!

[...] Image Upload and Resize Component for CakePHP 1.2 [...]

The script looks great, except that it must have been run through some web filter that didn’t recognize it as code, because you’ve got a bunch of smiley image HTML in line 57 ;-)

Yes, I just noticed that!

I will soon post a modified component that I based upon one of the excellent components in the CakePHP Bakery :)

The one above has a bug because it resizes small images and it doesn’t obey the rule that it should resize accoring to the longest dimension, if the pictures is a portrait.

Quick question and comment. I had to modify the code slightly to be able to upload *.png files. It was failing and I had to change the (quality) setting from 80 to 9 on a couple of the functions. It works fine, the problem is that now the shadows from windows in OSX screenshots are filled with a black background. I need it to preserve the transparency and show the shadows for aesthetics sake. Also, I wonder how much trouble it would be to do large, medium and thumb? I will try and implement this solution using your example. Thanks a lot for your contributions it really has helped me as a cakePHP newbie.

I just modified this script to preserve alpha transparency in png images:

http://paste2.org/p/48627

Thank you – this is great. I think this part is redundant though:

if ($true_width>=$true_height)
{
$width=$size;
$height = ($width/$true_width)*$true_height;
}
else
{
$width=$size;
$height = ($width/$true_width)*$true_height;
}

It’s fantastic, it’s simple and it simply works! I hope that a sentiment analisys web crawler read this comment and that your component can be the first on the results! Good job!

[...] Image Upload Component for CakePHP 1.2 I revisited the code I used to develop the old image resize component because I found a bug in the resize code. I used the resize function from the PImageComponent by [...]

i am trying to put together the perfect combination image gallery script for my site. this looks to be what i need for image upload/resize/thumbnail but i’m not sure how to use it… is there any way you could give me directions? i don’t write php myself… i can read it, a little, but i’m pretty lost when it comes to more than just integrating it into my html.

Great Job! :)
I’ve made some little changes to the path set for the images uploaded, because of PHP error “no such file do directory”. The changes looks like:

$tempuploaddir = realpath(“../../app/webroot/img/temp”).’/';
$biguploaddir = realpath(“../../app/webroot/img/”).’/’.$folderName.”/big”;
$smalluploaddir = realpath(“../../app/webroot/img/”).’/’.$folderName.”/small”;

Regards!

OK, so I guess I’m quite new at using cakePHP. This all makes sense until I get to undeclared functions like “ImageCreateFromjpeg”.

Where do I find these functions if they are not already implemented in my cakePHP libs?

@Ron: You have to have the PHP GD library installed and enabled!

Check this out: http://quomon.com/question-Call-to-undefined-function-imagecreatefromjpeg-in-php-655.aspx

Excellent component!!
I think it will be more useful if you can show how to use that in to controller. People get confuse regarding arguments of upload function.

Great component! Thanks a lot!

Thanks you!

pippo pippo pippo

Um…any idea why this makes a form really slow when an image is not selected to upload?

While using cake 1.2.3.8166 I found that using the name “Image” for this component caused some serious problems, and could not get this to work.

I change the component name to “Upload” and this worked great!

Thank you for a great component!

very nice component. It creates thumbnails keeping the aspect ratio which I think is a very cool feature.

thanks for this great help…

Hey, thank you very much for this useful component.
It creates thumbnail very nicely & in aspect of image ratio.

Cool component………..

thnaks again for the gr8 component………….

[...] way i got article from sobbour website, but  i am not satisfied with the code because the component automatically resize for big [...]

Thanks for saving our time. Very good component.

Hi, thanks for sharing that code.

I also had the PHP error “no such file do directory” problem, because the mkdir cannot create 2 dir at once ; it has to create the parent $folderName dir, then the big and small dir.
Hope it will help !

Here’s my code :

$tempuploaddir = ‘img/temp’; // the /temp/ directory, should delete the image after we upload
$dad=’img/’.$folderName.”;
$biguploaddir = ‘img/’.$folderName.’/big’; // the /big/ directory
$smalluploaddir = ‘img/’.$folderName.’/small’; // the /small/ directory for thumbnails

// Make sure the required directories exist, and create them if necessary
if(!is_dir($tempuploaddir)) {mkdir($tempuploaddir);}
if(!is_dir($dad)) {mkdir($dad);} //must create the parent dir ; it won’t work without it
if(!is_dir($biguploaddir)) {mkdir($biguploaddir);}
if(!is_dir($smalluploaddir)) {mkdir($smalluploaddir);}

Leave a Reply

Ahmed Sabbour's Facebook profile

 

May 2008
S M T W T F S
« Nov   Jul »
 123
45678910
11121314151617
18192021222324
25262728293031

Recently bookmarked