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;
}
} ?>
[...] 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
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.
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?
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!
May 13, 2008 at 3:51 am
Looks very nice. Good job!