RisingSun
RisingSun

Reputation: 1733

PHP - imagecreatefromjpeg uses 100M memory for <1M image

The image is less than 1MB but the size is roughly 5500x3600. I am trying to resize the image down too something less than 500x500. My code is pretty simple.

    $image = imagecreatefromjpeg("upload/1.jpg");
    $width = imagesx($image);
    $height = imagesy($image);
    $pWidth = 500;
    $pHeight =  334;
    $image_p = imagecreatetruecolor($pWidth, $pHeight);
    setTransparency($image,$image_p,$ext);
    imagecopyresampled($image_p, $image, 0, 0, 0, 0, $pWidth, $pHeight, $width, $height);

I found out that to process this image, the imagecreatefromjpeg uses 100M using memory_get_usage.

Is there a better way to do imagecreatefromjpeg? is there a workaround or a different function that uses less memory?

I did ask my server admins to increase the memory but I doubt they will increase it to 100M or more. I am considering limiting the dimensions of an image a user can upload but not before exhausting all my options as users will most likely upload images they took.

Btw, the following is the image i used which uses 100M of memory

enter image description here

Upvotes: 1

Views: 1601

Answers (3)

Kenneth
Kenneth

Reputation: 555

I've been using vipsthumbnail for years. I use it to resize 700MP images (enormous 16,384 x 42,731 = 2.6BG if loaded into php) to a viewable size. This takes about 10 seconds to generate a small preview that's 3000px tall.

https://www.libvips.org/API/current/Using-vipsthumbnail.html

By specifying one dimension, it keeps the original aspect ratio and limits the x or y, which ever is greater

$exec_command = sprintf('vipsthumbnail --size 3000 "%s" -o "%s"', $source, $destination);

exec( $exec_command, $output, $return_var );

if($return_var != 0) {
    // Handle Error Here
}

I was still using php to resize smaller images, but my system recently generated a secondary image that was 15,011 x 15,011 (1.075GB uncompressed). My PHP settings allow for 1GB of ram, and it was crashing!. I increased PHP's memory limit over time to deal with these images. I finally converted this function to also use vipsthumbnail. These smaller images only take about 100ms each to generate. Should have done this a long time ago.

$exec_command = sprintf('vipsthumbnail --size 150 "%s" -o "%s"', $src, $dst);
exec( $exec_command, $output, $return_var );
        

Upvotes: 2

Mark Setchell
Mark Setchell

Reputation: 207355

ImageMagick, on the command-line at least, is able to use a feature of libjpeg called "Shrink on Load" to avoid unnecessarily loading the whole image if you are only planning on scaling it down.

If I resize your image above up from its current 3412x2275 to the size you are actually dealing with, 5500x2600 like this

convert guys.jpg -resize 5500x2600 guys.jpg

I can now do some tests... first, a simple resize

/usr/bin/time -l convert guys.jpg -resize 500x334 small.jpg
        0.85 real         0.79 user         0.05 sys
 178245632  maximum resident set size                    <--- 178 MB
         0  average shared memory size
         0  average unshared data size
         0  average unshared stack size
     44048  page reclaims
         0  page faults
         0  swaps

you can see it uses a peak of 178 MB on my Mac.

If I now use the "Shrink on Load" feature I mentioned:

/usr/bin/time -l convert -define jpeg:size=500x334 guys.jpg -resize 500x334 small.jpg
        0.06 real         0.04 user         0.00 sys
   8450048  maximum resident set size                 <--- Only 8 MB
         0  average shared memory size
         0  average unshared data size
         0  average unshared stack size
      2381  page reclaims
        33  page faults
         0  swaps

you can see it only takes 8MB now. It's faster too!

Upvotes: 1

Pekka
Pekka

Reputation: 449385

What @dev-null-dweller says is the correct answer:

With 5500x3600 you will need at least 5500*3600*4 bytes in memory =~ 80MB. For large pictures Imagick extensions might have better performance than GD

There is no way to "improve" on that because that's the amount of memory needed to process the image. JPEG is a compressed format so its file size is irrelevant, it's the actual dimensions that count. The only way to deal with such an image inside GD is increasing the memory limit.

You may be able to do better using a library/command line client like ImageMagick if you have access to that - when you run ImageMagick from the command line, its memory usage won't count towards the memory limit. Whether you can do this, you'd need to find out from your web host or server admin.

Another idea that comes to mind is using an image resizing API that you send the image to. That would take the load completely off your server. This question has some pointers: https://stackoverflow.com/questions/5277571/is-there-a-cdn-which-provides-on-demand-image-resizing-cropping-sharpening-et

Upvotes: 2

Related Questions