Recently I made an image uploader for my other website & I noticed that there isn’t a lot of tutorials around on how to crop thumbnails into squares. This tutorial requires that GD is enabled in PHP, I’m not sure whether you need GD2 or not but I don’t see any reason for it not [...]

Recently I made an image uploader for my other website & I noticed that there isn’t a lot of tutorials around on how to crop thumbnails into squares. This tutorial requires that GD is enabled in PHP, I’m not sure whether you need GD2 or not but I don’t see any reason for it not to work in older versions of GD.

Copy The Large Image

Just incase you don’t know how to do it, you can copy the original image across like this.

copy($_FILES["Filedata"]["tmp_name"],"path/to/folder/".$_FILES['Filedata']['name']);

Let’s Get Onto The Thumbnails

Ok now let’s get onto the code for the thumbnails.

$source_img = @imagecreatefromjpeg($_FILES["Filedata"]["tmp_name"]); //Create a copy of our image for our thumbnails...
if (!$source_img) {
	echo "could not create image handle";
	exit(0);
}

We create a copy of the image using imagecreatefromjpeg(). A quick note here is that this code will only work for uploads of jpg & jpeg file types. You could have a switcher checking for the mime type and use imagecreatefromjpeg, imagecreatefromgif & imagecreatefrompng to also do those file types. The switcher could be created by putting the image through getimagesize and handing the returned arrays ‘mime’ value through image_type_to_mime_type, but that’s not what this tutorial is about.

$new_w = 120;
$new_h = 120;

$orig_w = imagesx($source_img);
$orig_h = imagesy($source_img);

$w_ratio = ($new_w / $orig_w);
$h_ratio = ($new_h / $orig_h);

if ($orig_w > $orig_h ) {//landscape
	$crop_w = round($orig_w * $h_ratio);
	$crop_h = $new_h;
} elseif ($orig_w < $orig_h ) {//portrait
	$crop_h = round($orig_h * $w_ratio);
	$crop_w = $new_w;
} else {//square
	$crop_w = $new_w;
	$crop_h = $new_h;
}
$dest_img = imagecreatetruecolor($new_w,$new_h);
imagecopyresampled($dest_img, $source_img, 0 , 0 , 0, 0, $crop_w, $crop_h, $orig_w, $orig_h);

Mmmk. So first we set a width & height for our cropped thumbnails. They don’t have to be square, but for layout purposes square thumbnails create a nice foundation. We grab the image’s width & height. We create a ratio by dividing the new width by the original width, we do the same for the height too.

Next we do a check to see what shape our image is landscape, portrait or square. If the image is checked we use the ratio to get the right size for either the width or height. If it’s square it doesn’t matter. Really with a square thumbnail the check doesn’t matter since in our case the $crop_w & $crop_h variables should always be 120, but if you chose rectangular cropped thumbnails then it is very important or your images will be out of proportion.

Finally we create a blank image at the size of our thumbnail and then use imagecopyresampled to place our copied image into the blank image with the new crop sizes.

There’s only one more thing left to do & that is to save our image somewhere.

if(imagejpeg($dest_img, "path/to/folder/".$_FILES['Filedata']['name'])) {
	imagedestroy($dest_img);
	imagedestroy($source_img);
} else {
	echo "could not make thumbnail image";
	exit(0);
}

As I said before, this part of the script will only work with jpg and jpegs. If you want other formats you would need to use a switcher. If it was successful we destroy all the images used to free up memory.

That’s It

Yep, that’s it. You should end up with a nice cropped thumbnail at your desired size. If you have any problems let me know and I’ll see what I can do to help. :)

A Little Tip

Just a little after thought. In the code to copy the full image I just use the copy function. If you are going to use that instead of move_uploaded_file it is probably a good idea to make sure the file was uploaded via a form using is_uploaded_file. You could use something like this to cover all bases.

if (!isset($_FILES["Filedata"]) || !is_uploaded_file($_FILES["Filedata"]["tmp_name"]) || $_FILES["Filedata"]["error"] != 0) {
	echo "invalid upload";
	exit(0);
}

How To Center The Square Cropping Effect

There have been a few requests about how to take the square crop from the center of an image. Here’s how to do it. To do that we need to calculate the X & Y positions. This requires the code to be altered slightly.

if ($orig_w > $orig_h ) {//landscape
	$crop_w = round($orig_w * $h_ratio);
	$crop_h = $new_h;
	$src_x = ceil( ( $orig_w - $orig_h ) / 2 );
	$src_y = 0;
} elseif ($orig_w < $orig_h ) {//portrait
	$crop_h = round($orig_h * $w_ratio);
	$crop_w = $new_w;
	$src_x = 0;
	$src_y = ceil( ( $orig_h - $orig_w ) / 2 );
} else {//square
	$crop_w = $new_w;
	$crop_h = $new_h;
	$src_x = 0;
	$src_y = 0;
}
$dest_img = imagecreatetruecolor($new_w,$new_h);
imagecopyresampled($dest_img, $source_img, 0 , 0 , $src_x, $src_y, $crop_w, $crop_h, $orig_w, $orig_h);

Here is what we are doing. We need to figure out the X & Y positions from which to crop the image, to do that we do some math. If the image is landscape we work out the X position using the sum ((new image width / 2) – (thumbnail width /2)). We set the height to 0 as it has already been set to the height of the thumbnail.

We do the same again for portrait images except we do the sum on the height and set the width to 0. If the image is square we don’t need to do anything since it will fit straight into the square thumbnail with no cropping.

I hope that helps with centering the crop when cropping square thumbnails. Thank you to Elpres, and Deryk Wenaus in the comments for the sum to work out the X & Y positions.

Resizing Images Held In A Directory

Huge thanks to Ray for contributing this snippet of code in the comments:

$folder = $_POST['folder']; //POST if from form, GET if from URL
$thisdir = getcwd();
if(!file_exists($thisdir ."/"."$folder/thumbs")) {
    mkdir($thisdir ."/"."$folder/thumbs" , 0777);
}

function returnimages($dirname="") {

    $pattern="(\.jpg$)|(\.png$)|(\.jpeg$)|(\.gif$)"; //valid image extensions
    $handle  = opendir($dirname);
    while(false !== ($filename = readdir($handle))) {
        if(eregi($pattern, $filename)){ //if this file is a valid image
            $files[] = $filename;
        }
    }
    if (count($files)<>0) {
        sort($files);
    }

    $curimage=0;

    while($curimage !== count($files)){
        $cropfile=$dirname.'/'.$files[$curimage];echo '<br>'.$cropfile;
        $source_img = @imagecreatefromjpeg($cropfile); //Create a copy of our image for our thumbnails...
        if (!$source_img) {
            echo "could not create image handle";
            exit(0);
        }
        $new_w = 120;
        $new_h = 120;

        $orig_w = imagesx($source_img);
        $orig_h = imagesy($source_img);

        $w_ratio = ($new_w / $orig_w);
        $h_ratio = ($new_h / $orig_h);

        if ($orig_w > $orig_h ) {//landscape from here new
            $crop_w = round($orig_w * $h_ratio);
            $crop_h = $new_h;
            $src_x = ceil( ( $orig_w - $orig_h ) / 2 );
            $src_y = 0;
        } elseif ($orig_w < $orig_h ) {//portrait
            $crop_h = round($orig_h * $w_ratio);
            $crop_w = $new_w;
            $src_x = 0;
            $src_y = ceil( ( $orig_h - $orig_w ) / 2 );
        } else {//square
            $crop_w = $new_w;
            $crop_h = $new_h;
            $src_x = 0;
            $src_y = 0;
        }
        $dest_img = imagecreatetruecolor($new_w,$new_h);
        imagecopyresampled($dest_img, $source_img, 0 , 0 , $src_x, $src_y, $crop_w, $crop_h, $orig_w, $orig_h); //till here
        if(imagejpeg($dest_img, $dirname."/thumbs/".$files[$curimage])) {
            imagedestroy($dest_img);
            imagedestroy($source_img);
        } else {
            echo "could not make thumbnail image";
            exit(0);
        }
        $curimage++;
    }
}
returnimages($name=$folder);

PEAR Modules

A few people have asked me why I don’t use the two PEAR modules HTTP_Upload & Image_Transform… Well one reason is that HTTP_Upload is (according to the PEAR directory) without any maintainers at the moment. Also my host & quite a few others don’t allow you to install additional PEAR packages. I am lucky enough in that my host will however allow me to set up my own PEAR install which will then allow me to install additional packages, but this tutorial is useful for those who do not have that option. It might be