tags:

views:

201

answers:

3

I'm trying to process a directory of JPEG images (roughly 600+, ranging from 50k to 500k) using PHP: GD to resize and save the images but I've hit a bit of a snag quite early in the process. After correctly processing just 3 images (30K, 18K and 231K) I get a Allowed memory size of 16777216 bytes exhausted PHP Fatal error.

I'm cycling through the images and calling the code below:

    list($w, $h) = getimagesize($src);

    if ($w > $it->width) {
        $newwidth = $it->width;
        $newheight = round(($newwidth * $h) / $w);
    } elseif ($w > $it->height) {
        $newheight = $it->height;
        $newwidth = round(($newheight * $w) / $h);
    } else {
        $newwidth = $w;
        $newheight = $h;
    }

    // create resize image
    $img = imagecreatetruecolor($newwidth, $newheight);
    $org = imagecreatefromjpeg($src);

    // Resize
    imagecopyresized($img, $org, 0, 0, 0, 0, $newwidth, $newheight, $w, $h);
    imagedestroy($org);

    imagejpeg($img, $dest);

    // Free up memory
    imagedestroy($img);

I've tried to free up memory with the imagedestroy function but it doesn't seem to have any affect. The script just keeps consistently choking at the imagecreatefromjpeg line of code.

I checked the php.ini and the memory_limit = 16M setting seems like it's holding correctly. But I can't figure out why the memory is filling up. Shouldn't it be releasing the memory back to the garbage collector? I don't really want to increase the memory_limit setting. This seems like a bad workaround that could potentially lead to more issues in the future.

FYI: I'm running my script from a command prompt. It shouldn't affect the functionality but might influence your response so I thought I should mention it.

Can anyone see if I'm just missing something simple or if there's a design flaw here? You'd think that this would be a pretty straightforward task. Surely this has to be possible, right?

+3  A: 

It's possible that one or more of your images actually inflate to 16M in raw memory. One way to check is to open it in Photoshop or Irfanview and check the color space and pixel dimensions.

It doesn't take much to reach 16M, for example, consider a "lowly" 6 megapixel camera. It creates a 3072 pixel by 2048 pixel image. At a byte per color (RGB) the raw size is:

3072 x 2048 x 3 = 18,874,368

So, you might want to increase the memory according to the largest images you expect to process. But you have to consider their raw size.

JYelton
I'll check it out. Thanks.
gurun8
And gd not only stores three but four bytes per pixel ~ 25M
VolkerK
I assume that's an alpha channel? Good point, VolkerK.
JYelton
Hold up. Are you saying that gd stores all image files in memory even after they've been destroyed? This would make mass processing a group of images like mine virtually impossible. Shouldn't gd release the memory on destroy?
gurun8
No, it just inflates the compressed JPG to raw memory size for manipulation. When you destroy it, it frees up the memory. You just need ample space for it to work on an image at its raw size.
JYelton
Apparently it was a memory_limit issue. I wasn't aware that I could set the memory_limit at a script level.
gurun8
+1  A: 
ini_set('memory_limit', '64M');

problem solved

TravisO
I'll give this a try. My guess is it will error out later in the process. I hope I'm wrong.
gurun8
I was wrong. This worked. Thanks.
gurun8
I guess I should have just posted what to do instead of why to do it.
JYelton
I hear ya. Your answer was helpful but this was the solution. Thanks for the help. No hard feelings.
gurun8
curious, does the memory clear up after the php page load, or does it all get stored in a permanent queue somewhere and accumulate till the server crashes?
ina
A: 

Simply use ini_set(); and set the memory_limit to whatever size you want.

Mark