4

I want to generate a thumbnail image for a PDF file stored on google bucket using imagick and PHP
I deploy my application on google app engine(GAE) standard environment
the problem is that I keep getting this error

Fatal error: Uncaught exception 'ImagickException' with message  
'UnableToWriteBlob `magick--1noB3XBwJhgfn': Read-only file system

I know that the file system the application is deployed to is not writable, but I need a way to achieve this...

this is my code

<?php
putenv('MAGICK_TEMPORARY_PATH='.sys_get_temp_dir());

$imagick = new Imagick();

// get the content of pdf url
$imagenblob=file_get_contents('http://www.pdf995.com/samples/pdf.pdf');      

// read the content and load it inn imagick instance
$imagick->readimageblob($imagenblob);                                        

// point to the first page, because I want thumbnail for first page
$imagick->setIteratorIndex(0);        

// set image format
$imagick->setImageFormat('png');       

// resize image
$imagick->resizeImage(320,320,Imagick::FILTER_LANCZOS,1,1);

// return the result
header("Content-Type: image/png");          
$base64 = 'data:image/png;base64,' . base64_encode($imagick);
exit($base64);

Maybe if I can change the directory which imagick use to write, but I was not able to achieve this !!

Hamzeh Hirzallah
  • 263
  • 2
  • 17
  • If the directory is a 'read-only' or in another words if you don't have thee permissions to do that, you will not be able to write any data in that directory, 1- set the right permissions, or 2- save your thumbs in another directory that you have the permission to write into, 3- store your thumbs in the cloud (some API or any other external storage) or 4- save it into a data storage like MYSQL (**NOT A GOOD CHOICE**) – hassan Mar 26 '18 at 13:30
  • I cant change the permission to add the write.... this is not allowed in my case, I tried to change the write directory for imagick but I was not able to achieve that... – Hamzeh Hirzallah Mar 26 '18 at 15:23

4 Answers4

1

ImageMagick requires a temp directory to write artifacts during the delegate decoding/encoding process. I'm not familiar with , but the documents suggest tempnam() & sys_get_temp_dir() should be used.

putenv('MAGICK_TEMPORARY_PATH='.sys_get_temp_dir());
$imagick = new Imagick(); 
// ...

Also note, Ghostscript is used by ImageMagick for PDF decoding. Verify that the gs binary is installed & available if working w/ PDF files.

emcconville
  • 23,800
  • 4
  • 50
  • 66
  • I tried your solution, But I am sorry it throws this error Uncaught exception 'ImagickException' with message 'UnableToWriteBlob `magick--1lFkoxwYxJHF4': Read-only file system @ error/blob.c/BlobToFile/266' – Hamzeh Hirzallah Mar 28 '18 at 13:54
  • by the way... I can generate thumbnail for jpg images successfully, the problem is in the pdf files only .... – Hamzeh Hirzallah Mar 28 '18 at 14:01
1

You're hitting one of the restrictions of the standard environment sandbox:

An App Engine application cannot:

  • write to the filesystem. PHP applications can use Google Cloud Storage for storing persistent files. Reading from the filesystem is allowed, and all application files uploaded with the application are available.

One option (more costly) would be to use the flexible environment, which doesn't have such restriction.

Another approach would be to try to configure imagick to not use intermediate/temporary files (no clue if it supports that) or to use in-memory file emulation (donno if PHP supports that, I'm a python user) and specify that via Imagick::setFilename.

Another thing to try would be using setFormat instead of setImageFormat, the notes on the setImageFormat suggest that it might be possible to make the transformations before/without writing to the file:

To set the format of the entire object, use the Imagick::setFormat method. E.g. load TIFF files, then use setFormat('pdf') on the Imagick object, then writeImagesFile('foo.pdf') or getImagesBlob().

Dan Cornilescu
  • 39,470
  • 12
  • 57
  • 97
  • moving to flex environment is not an option for me... and the exception is thrown at this line "$imagick->readimageblob($imagenblob);" .... that is before setFormat... I tried for the past 3 days to configure imagick to not use intermediate/temporary files but with no luck ... – Hamzeh Hirzallah Mar 28 '18 at 15:56
  • if there is a full solution using python I can use it instead of PHP – Hamzeh Hirzallah Mar 28 '18 at 15:58
  • Unfortunately not. All I can point to is a potentially useful way of using in-memory `StringIO` filehandler to avoid writing to the filesystem: https://stackoverflow.com/questions/38885764/how-to-zip-or-tar-a-static-folder-without-writing-anything-to-the-filesystem-in/38888667#38888667 – Dan Cornilescu Mar 29 '18 at 02:19
  • Or one example of writing to a GCS file: https://stackoverflow.com/questions/35708725/how-to-open-gzip-file-on-gae-cloud/35709022#35709022 – Dan Cornilescu Mar 29 '18 at 02:20
1

There's no real way to make this work due to the two opposing forces at play:

1) Google App Engine Standard's sandbox limitations

2) Imagick apparently needing local file system access (at least temporarily) in order to work.

So if you can't change how Imagick work, then the only remaining solution is to not use GAE Standard. You can either use GAE Flex or Google Compute Engine. I don't know why Flex is not an option for you; you don't need to move the whole project over. You can just port this part over as a microservice on GAE Flex in the same project. The sole function of the service would be to process the image and get the thumbnail. You can then place the thumbnail in a Google Cloud Storage bucket for the rest of your app (in GAE Standard) to use.

Graham P Heath
  • 7,009
  • 3
  • 31
  • 45
Ying Li
  • 2,500
  • 2
  • 13
  • 37
  • I have tried your solution, and I moved the thumbnailGenerator file into Flex Enviroment... now I facing the following error "Uncaught ImagickException: Unable to read image blob in /app/thumpnailGenerator.php:31 Stack trace: #0 /app/thumpnailGenerator.php(31): Imagick->readimageblob('%PDF-1.3\n%\xC7\xEC\x8F\xA2\n...')" – Hamzeh Hirzallah Mar 29 '18 at 10:58
  • Show us the code that throw that? I assume this is from your GAE Standard App reading a GCS img (the post-processed thumbnail)? – Ying Li Mar 29 '18 at 16:38
0

to anyone facing the same problem , I solved mine by created a new Google Compute Engine , with PHP installed on it, I created a function to convert the pdf to image using Imagick and it returns the response as base64 stream.

Imagick does not work well with pdf files on GAE

Hamzeh Hirzallah
  • 263
  • 2
  • 17