1

I'm trying to save an image using Imagick with php. When I call saveImage() or saveImageFile() I get

Fatal error: Uncaught exception 'ImagickException' with message 'Insufficient memory (case 4)

The image is about 1MB big and the script can use 256MB of memory, which I think should be enough. There is plenty of space available on disk.

What can be the problem?

The code is as follows:

<?php
list($type, $img) = explode(';', $img);
list(, $img)      = explode(',', $img);
$data = base64_decode($img);
$image = new Imagick();
$image->readImageBlob($data);
$image->setImageFormat("jpeg");
$image->setInterlaceScheme(Imagick::INTERLACE_PLANE);
$image->writeImageFile(fopen($name.'-original.jpg','w'));
?>

If I try to use file_put_contents() instead of saveImage() then an empty file is saved. Perhaps there is a problem with the server configuration?

Rizhiy
  • 775
  • 1
  • 9
  • 31
  • The memory being referred is RAM not disk. This might happen in case of shared hosting. If you have a dedicated server try pushing operations like these to background jobs :) – georoot Nov 19 '16 at 19:31
  • @raina77ow image is in JPEG. System is FreeBSD 8.3-RELEASE-p4 i386. PHP is PHP 5.6.16 – Rizhiy Nov 19 '16 at 19:32
  • Have you checked [this tip](https://www.mediawiki.org/wiki/Manual:%24wgMaxShellMemory)? – raina77ow Nov 19 '16 at 19:33
  • @georoot It is a shared hosting, but the host says that I should always have at least 256MB of memory available. – Rizhiy Nov 19 '16 at 19:33
  • On the second thought, this tip probably has nothing to do with your case. Can you share some more details - show the code, for example? Also, what's result of `ini_get('memory_limit')`? – raina77ow Nov 19 '16 at 19:36
  • @Rizhiy and that memory is also being used by PHP, Apache and other stuff running. I never used shared hosting but it is a pretty safe bet to say that if a single request requires 200M ram for execution, its bad program design. Maybe try profiling the code or pushing it into background job. I think that might help – georoot Nov 19 '16 at 19:37
  • @georoot The thing is, I'm pretty sure that the process should use way less memory since it's just saving an image. – Rizhiy Nov 19 '16 at 19:45
  • @Rizhiy first post the relevant code snippets, no one can help without that. About ram consumption, did you profile your application before deployment ? – georoot Nov 19 '16 at 19:46
  • @raina77ow response from `ini_get('memory_limit')`: 256M. – Rizhiy Nov 19 '16 at 19:48
  • @georoot No, it's for my personal site, I'm just learning how to do all of this. – Rizhiy Nov 19 '16 at 19:51
  • @Rizhiy the code seems fine but the ram usage doesn't add up for this. Try profiling the code to see where is that ram being used. For reference refer to question over here http://stackoverflow.com/questions/880458/php-memory-profiling – georoot Nov 19 '16 at 19:57
  • @georoot I added `echo memory_get_peak_usage();` just before image write. It returned 4118528, which is about 4MB, so there is plenty of memory available. – Rizhiy Nov 19 '16 at 20:07
  • Ok, can you narrow the problem? Exclude `setInterlaceScheme`; does it take you somewhere? What's `$image->getImageProperties()` output? – raina77ow Nov 20 '16 at 11:32

1 Answers1

0

The problem was with $image->readImageBlob($data) even though it was returning success, the resulting image was empty. Which I would guess caused division by zero somewhere later on during saving.

The solution I used was to first save the data to a file and then load it back in:

list($type, $img) = explode(';', $img);
list(, $img)      = explode(',', $img);
list(,$type) = explode('/',$type);
$data = base64_decode($img);
file_put_contents($name,$data);
$image = new Imagick($name);

While this adds a lot of delay since we have to go through the disk, it is the best I could think of.

Rizhiy
  • 775
  • 1
  • 9
  • 31