Image upload and resize: what is the best way?

Hi everyone,

Just looking for a few opinions here. Basically my situation is that I have a script that resizes a user-uploaded image to two different sizes - a medium size, and a thumbnail. The script does this using GD Library.

The problem I have with this script is that it has trouble with images that are large in file size, or with doing more than one image at once. The page offers no error - just (eventually) loads a blank white page. It’s extremely possibly that this happens because my script is inefficient, as I’m by no means a coding expert.

I want the user to be able to upload a number of images, of pretty much any file size, and have all the images resized. I’ve seen a lot of things in my recent searching that suggest using ImageMagick instead of GD Library for image manipulation. This isn’t really an option, as the host that this site is with do not offer ImageMagick. Changing hosts is would be a last resort, and I’d only really do it if there was overwhelming support in that direction.

The other things I am thinking of:

  1. Perhaps my script can be improved to make it more efficient, or at least someone can let me know if this is most likely where things are going so wrong?
  2. Maybe I can use some other sort of library or script that someone else has written - if anyone has any suggestions about a good one that might fit my purposes? Preferably this would be free, or cheap.

Thanks for any opinions, I would be interested to hear what people think.

This is my code. The memory limit is something that I have previously tried to help this porblem, it has no effect whatsoever.

I did read something in my searching that suggested using the large original image to make the largest resized version, then using the resized file to make the thumbnail. I haven’t had a chance to implement it yet to see if it helps. It seems like it would, though I’m not sure it would fix the whole thing.

ini_set("memory_limit","64M");

$numPics = 0;
$mainPath = "../images/gallery/";
$thumbPath = "../images/gallery/thumbs/";

foreach ($_FILES['ufile']['name'] as $key=>$value)
{
	if ($value != "")
	{
	$numPics ++;
	}
}

for ($i = 0; $i <= ($numPics - 1); $i++) {
	

	/********************THUMBNAIL*********************/

	$thumbName = "thm_" . $_FILES['ufile']['name'][$i];
	
	$uploadedfile = $_FILES['ufile']['tmp_name'][$i];
	
	$src1 = imagecreatefromjpeg($uploadedfile);
	
	list($width,$height)=getimagesize($uploadedfile);
	
		
	$cropWidth = 150;
	$cropHeight = 113;
	
	//landscape
	if (($width/$height) > 1)
	{
		$newheight = $cropHeight;
		$newwidth = ($newheight/$height)*$width;
		
		$x_pos = ($newwidth - $cropWidth) / 2;   
		$x_pos = ceil($x_pos);   
		$y_pos = 0;
	
	//portrait	
	} else {
		
		$newwidth = $cropWidth;
		$newheight = ($newwidth/$width)*$height;
		
		$x_pos = 0;  
		$y_pos = ($newheight - $cropHeight) / 2; 
		$y_pos = ceil($y_pos); 
		
	}
	
	$tmp = imagecreatetruecolor($newwidth,$newheight);
	imagecopyresampled($tmp,$src1,0,0,0,0,$newwidth,$newheight,$width,$height);
		
	$cropped = imagecreatetruecolor($cropWidth, $cropHeight);
	imagecopy($cropped, $tmp, 0, 0, $x_pos, $y_pos, $cropWidth, $cropHeight);
	
	
	$fileName = $thumbPath . $thumbName;
	imagejpeg($cropped,$fileName,100);	
	
	
	imagedestroy($src1);
	imagedestroy($cropped);
	imagedestroy($tmp);
	
	 
	
	/********************LARGE*********************/

	$largeName = $_FILES['ufile']['name'][$i];
	
	
	$uploadedMain = $_FILES['ufile']['tmp_name'][$i];
	
	$src2 = imagecreatefromjpeg($uploadedMain);
	
	list($width,$height)=getimagesize($uploadedMain);
	
	
	//portrait
	if (($width/$height) < 1)
	{
		$newheight=600;
		$newwidth=($newheight/$height)*$width;
		
	//landscape	
	} else {
		$newwidth=800;
		$newheight=($newwidth/$width)*$height;
		
		
	}
	$tmp=imagecreatetruecolor($newwidth,$newheight);
	
	
	imagecopyresampled($tmp,$src2,0,0,0,0,$newwidth,$newheight,$width,$height); 
	
	$filename = $mainPath . $largeName;
	imagejpeg($tmp,$filename,100);

	imagedestroy($src2); 
	imagedestroy($tmp); 
	
} // end for

if you getting blank page try to set error reporting to all
http://ca2.php.net/manual/en/function.error-reporting.php
or check error logs to see where the issue is

You are not the only one experiencing this symptom and the most likely reason is your script exceeds php memory limit, see http://www.talkphp.com/advanced-php-programming/4034-resizing-large-images-php-gd.html

I’m afraid this is your best option - unless your current host allows you to raise memory_limit to an acceptable value. ImageMagick is not limited by php memory_limit and can work with large images. As a benefit you can also get better image quality and jpg compression if you use the right settings (GD is limited in that respect).

To me ImageMagick is a must when I make any dynamic web site. Now plenty of shared hosts offer IM so that I simply refuse to use a host when I see they don’t have IM. And if people upload images then relying on GD is out of question for me.

Uh oh, I was afraid that might come back as the answer! I’m pretty sure this host does not allow me to raise teh memory_limit either - or I’m sure I’d be getting at least a slightly better result than I am.

The reason I’m so reluctant to change hosting on this one is that the site came with months of faffing around trying to get it to work on the client’s own server (they tried two different IT companies who couldn’t get it configured so the site would work!) before we all just gave up and they accepted that they would have to get hosting elsewhere. I’m imagining the conversation that I’d have to have to tell them they need to switch, 2 months into the new hosting . . .

If you don’t change hosts I can think of some workarounds you can do but none of them will solve the problem completely:

  1. Find out the maximum image size your current server can handle and when your php upload script receives the file first check the image size with getimagesize() and if it’s too large then abort the script and display a message to the user telling them the image is too large and they need to resize it before uploading (you can offer them a web service like http://www.shrinkpictures.com/) . At least they will not go to a blank page not knowing what is going on.

  2. Use an image processing web service in your php upload script to resize the image on an external server, for example http://www.lightspun.com/. But then this may slow things down a bit as the data will need to travel back and forth to another server. Better to change hosts and switch to IM.

  3. Use a java applet that will resize the image on the client side and upload the smaller version. One of the tools I found is http://jumploader.com/ but there are many more if you search. Actually, this is the ideal solution performance-wise since the transfer will be small even if the user uploads a huge picture. And as a bonus they will see the progress bar and thumbnails. This is all sweet but not all users have java and the java applet will ask for permissions (because it will need to access the user’s filesystem). However, you could use it as an alternative method to your standard upload form, if someone can run java they would certainly appreciate such a tool.

Thanks for that reply, Lemon Juice. I’m just running a few tests with ImageMagick (on a different host). It’s actually working no better - the real issue seems to be that these two hosts do not allow such large file uploads - my ImageMagick script works perfectly with images less than 1MB, but as soon as I try it with a larger file (4MB, currently) the file upload is failing - no data ends up in my $_FILES[‘ufile’][‘tmp_name’] variable.

It also takes too long to upload the smaller images in the first place anyway - there is no noticeable improvement on my GD script there. I’m thinking it’s the hosting - or perhaps the speed of Australian internet?

So I guess my question has changed a little - what is the best way of surmounting this issue? Is it reasonable to expect to be able to upload 4MB files through an HTML form? If I sign up with an overseas host, will this make it any faster?

For a bit of background, the reason I’m going for such a large max file size with these images is that the client the site is for is particularly un-technically savvy. He doesn’t want to have to do any extra steps, or to even understand anything about the process at all - he just wants to be able to take the files straight off his camera and upload them straight to his website.

The client-side Java solution above may answer my purpose, however it does seem like a bit of a complicated workaround. It seems like there should just be an easier way - surely not everyone in Australia is limited to small file uploads?

Well, then it is a separate problem. Large file uploads must be enabled on your server, when you look at phpinfo() they are controlled by two variable settings: post_max_size and upload_max_filesize - the largest possible file size is the smaller of these so both of them must be set to the limit you need. I think you should be able to find a host who allows max 8MB, that should suffice for most current digital cameras. So now you have two requirements: max file size and ImageMagick. Even if your point of failure wasn’t GD it’s a good idea to switch to IM because you never know when you hit the limit.

It also takes too long to upload the smaller images in the first place anyway - there is no noticeable improvement on my GD script there. I’m thinking it’s the hosting - or perhaps the speed of Australian internet?

You will not notice much speed improvement using IM over GD unless you process lots of photos in a batch.

So I guess my question has changed a little - what is the best way of surmounting this issue? Is it reasonable to expect to be able to upload 4MB files through an HTML form?

Sure! Even though HTTP is not best suited for large uploads 4MB is not much. I once made an upload script on a site where people uploaded files above 100MB through a standard form! That was 3 years ago - they could upload a single zip full of images and then a php script was called every minute by cron and processed (resized) the images one by one with ImageMagick. Occasionally, people reported hiccups (understandable) but for the most part it worked pretty well.

If I sign up with an overseas host, will this make it any faster?

I think a good host without too many limits will be okay regardless of location.

For a bit of background, the reason I’m going for such a large max file size with these images is that the client the site is for is particularly un-technically savvy. He doesn’t want to have to do any extra steps, or to even understand anything about the process at all - he just wants to be able to take the files straight off his camera and upload them straight to his website.

The client-side Java solution above may answer my purpose, however it does seem like a bit of a complicated workaround. It seems like there should just be an easier way - surely not everyone in Australia is limited to small file uploads?

Actually, I think the solution with a client-side script is the proper solution and uploading whole images is a workaround because it’s very inefficient. The only problem is availability of plugins required to handle such a script but if your clients can run java then I’d go for it. If you grab one of the ready applets available it shouldn’t be that difficult to set up. As a bonus clients will have a useful progress bar. You could make a progress bar with a standard upload but it’s quite convoluted and you may again run against restrictions imposed by the hosting company.

From memory there is a maximium upload filesize set in php.ini and by default its 2mb; add some code to display any errors with upload and see if your problem is there:File upload errors

I have done some tests and Imagemagick can handle a lot larger file sizes with default settings.

OK, so I checked the post_max_size and upload_max_filesize values. On the original site, that is causing the problem, these are set to 24MB and 10MB respectively. So I just tested my GD library upload script with a 4.33MB file - and weirdly, no blank page . . . instead it gave me a 500 Internal Server Error. No idea where to find the error logs, I have emailed the host to ask.

On the other server, where I was testing ImageMagick, the values are set to 8MB and 2MB. So, no mystery about why my 4MB upload was failing, then.

At least I’m learning new things . . .