-1

I am trying to compress an uploaded image using imagefromjpeg but I get this error:

Fatal error: Allowed memory size of 67108864 bytes exhausted (tried to allocate 24000 bytes) 

The image is only 13215317 bytes big - why do I keep getting this error? I can not ramp up the memory for the server myself - so is there a way to compress without loading the entire image at once?

$image = imagecreatefromjpeg('../../uploads/DSC_0230.jpg');
imagejpeg($image, '../../uploads/DSC_0230.jpg.new', 0.8);

imagedestroy($image);
Curunir
  • 1,186
  • 2
  • 13
  • 30

2 Answers2

1

Loading an image into PHP this way will first uncompress the JPEG into raw pixel data in memory, and then generate the new version. It will therefore take memory equivalent to two raw bitmaps at the image's resolution, plus the other overhead of PHP and your script.

Since all you're doing is recompressing the image with different options, you will probably have better performance with a tool built for just that job, such as jpegtran or jpegstrip, or a general image manipulation tool like ImageMagick.

You could then call those from your PHP script using shell_exec - being very careful that you have validated the filename so that someone can't use it to run arbitrary commands.

IMSoP
  • 89,526
  • 13
  • 117
  • 169
  • The fremium hoster I am using only offers gd2. Guess I will have to search another hoster than ... – Curunir Feb 14 '18 at 18:11
  • Is there a way to view the amount of memory it tried to allocate total? – Curunir Feb 14 '18 at 18:12
  • @Martin Yeah, it's not ideal, but the only other way is if there's a function in some PHP extension which loads less of the data into memory. Or try and get a higher memory limit, since as you say, 64MB is pretty low. – IMSoP Feb 14 '18 at 18:13
  • 1
    @Curunir That's what the error message tells you: the last block it tried to allocate was 24kiB, and the limit was 64MiB. Whether it would have allocated more after that, you can't know without running with a higher limit, because the memory manager kills the process off before it goes any further. – IMSoP Feb 14 '18 at 18:14
  • Ok, thank you so one could assume it would be around 70MB – Curunir Feb 14 '18 at 18:22
  • It could actually need 500 MB - 1 GB. It take 3 or 4 bytes per pixel (*not per byte of the compressed file*) -- 24 bits color, and depending on the decoding function a byte for transparency. A 13 MB file could easily be a 10 MP or higher camera image. We ran into this issue with the Chromium browser engine doing raw decoding of camera pics to then rescale down to tiny display sizes. – Dave S Feb 14 '18 at 18:34
1

Issue:

  • Your hosting provider offers you service with only a 64Mb memory limit.
  • Your image upload has a larger than 64Mb memory usage as uncompressed raw pixel data.

Solutions:

1) Increase your memory limit in PHP.ini file, typically with :

memory_limit = 128M 

2) Increase your memory limit on your page only, editing the php.ini only for that page execution :

ini_set('memory_limit','128M');

3) Limit the size of the original file upload.

there are a few ways to do this, so please read the PHP manual as well as reaseach some useful posts found via Google Searching.

4) You can also try and resize the image before uploading.


From your statement that you cant edit the PHP.ini with ini_set then it looks like you should use option 4 and 3.

Also, your current code is incorrect.

imagejpeg($image, '../../uploads/DSC_0230.jpg.new', 0.8);

The compression value should be an integer between 0 and 100. to correctly set the saved JPEG to a proper compression level:

imagejpeg($image, '../../uploads/DSC_0230.jpg.new', 80);

This will save the image to a value of 80 compression(the value it looks like you're attempting with 0.8).

Martin
  • 22,212
  • 11
  • 70
  • 132
  • 1
    Note that if you only know the compressed size, only #4 (resize in the client) is guaranteed to work for all images unless you can allocate an extremely large amount of RAM for PHP. A 13K x 10K pixel camera image will require 520 MB per buffer. – Dave S Feb 14 '18 at 19:20