The whole reason I resorted to rejecting large images was because the PHP function that causes the memory error doesn't handle its errors very well. What I would have liked to do was recover from one of these memory errors and display a different image in its place, but instead the error kills the script.
So there is no way I could have done something like this:
// loading image!
$im = @imagecreatefromjpeg("test-image.jpg");
// oh no! image too big to load into memory!
if(!$im){
// special function that creates new image and puts the filename in it
imageCenterString( $THUMBNAIL_WIDTH, $THUMBNAIL_HEIGHT, basename($image), $imageFontSize );
}
Unfortunately, PHP would have none of this! The script will die at the first line and ignore everything after it. It makes sense because if your PHP script is exceeding its memory limit it's not going to continue down the script, it doesn't have enough memory too! Still, I wish the "imagecreatefromjpeg" function had a feature that makes it purge the image when it hit the memory limit.
Someone e-mailed me the other day, asking about why some of their larger images weren't thumbnailing. I kindly explained to him that he'd need to adjust PHP's memory limit to get them to thumbnail, or modify the script to prevent it from trying, but then this got me thinking; is there a way that I can dynamically adjust the memory limit to conform to the needs of the image?
Thankfully, someone had already doled out the details of the algorithm used to calculate memory usage over in the PHP documentation community:
// starting memory usage
$start_mem = memory_get_usage();
// Place the images to load in the following array:
$ffs = array();
// loop through array of images to test
foreach ($images as $image) {
// get array of image data
$info = getimagesize($image);
// load image
$im = imagecreatefromjpeg($image);
// get current memory usage (after loading image)
$mem = memory_get_usage();
// calculate fudge factor
$ff = (($mem - $start_mem) /
($info[0] * $info[1] * ($info['bits'] / 8) * $info['channels']));
// stick fudge factor in cumulative array
$ffs[] = $ff;
// remove image from memory
imagedestroy($im);
// get new starting memory
$start_mem = memory_get_usage();
}
// calculate the mean of all the fudge factors
echo 'Mean fudge factor: ' . (array_sum($ffs) / count($ffs));
What do you do with this number? Well, we can now calculate the estimated memory that an image will take to thumbnail. To do that you simply take the (width * height * bpp * the fudge factor), and to set PHP to use that you simply use the ini_set function!
All in all my final implementation into my directory lister looks like this:
// if it is set
if($fudge_factor){
// set memory limit
ini_set('memory_limit', (($imgsize[0] * $imgsize[1] * ($imgsize['bits']/8) * $fudge_factor)+5).'M');
}
That's right, it's only 3 lines! It could easily be one if I sacrificed readability. On top of all this, because I know this is sounding complicated for those that aren't programmers, I made a quick and easy form to randomly select images from a directory and calculate the mean fudge factor. I call it the "fudge factor calculator!"
You can download the new version here!