PDF Thumbnail always generated as grayscale using Imagick - php

I am stuck and could really use some help on this one. I am using PHP and Imagick to generate a thumbnail which is working great. However, I noticed that CMYK PDFs are generated always as grayscale. So I tested this by taking the CMYK PDF and manually converting it to RGB with Adobe Acrobat Pro. Then I re-ran it through the following code and it produced a color image. I know about
$image->transformImageColorSpace(1);
or
$image->setImageColorSpace(1);
However this doesn't work. What is the correct way for converting a pdf to a color PNG image? I have looked at the following links with no luck:
http://php.net/manual/en/imagick.setimagecolorspace.php
Convert PDF to JPEG with PHP and ImageMagick
Any help on this one would be great.
Here is the code:
$filePath = fileSaveUserUpload("path/to/file", ""); //path changed here...
$_SESSION['FILEPATH'] = $filePath;
//-------------first makes a thumbnail of first page in image/pdf
$extension_pos = strrpos($filePath, '.'); // find position (number) of the last dot, so where the extension starts
$image = new Imagick();
$image->readImage($filePath."[0]"); //reads an image at a path(first page only in this case)
$image->transformImageColorSpace(1); //convert to RGB
$image->setbackgroundcolor('white'); //replace transparency with this color
$image->setCompression(Imagick::COMPRESSION_LOSSLESSJPEG);
$image->setCompressionQuality(150);
$image->setImageAlphaChannel(Imagick::ALPHACHANNEL_REMOVE); //remove transparency
$image->mergeImageLayers(Imagick::LAYERMETHOD_FLATTEN); //make everything that was transparent white
$image->thumbnailImage(0,250); //max height 300 but try and preserve aspect ratio (wdithxheight)
$thumbnail = substr($filePath, 0, $extension_pos) . '_thumb.png';// . substr($filePath, $extension_pos);
$image->writeImage($thumbnail);
$image->clear();
$image->destroy();
UPDATE:
I am using the following imagick version:
ImageMagick 6.9.1-2 Q16 x86 2015-04-14
3.3.0RC2
GhostScript Version:
9.18
Here is the original PDF (changed it to a picture here):
Here is the thumbnail that it produced:
This ONLY happens with CMYK PDFs. If I take this same PDF and convert it to RGB through adobe acrobat it comes out color. I tested this and it still holds true.

greeting from 2019. was having this problem still on gs 9.26 (9.27 doesnt work at all)
set the colourspace BEFORE loading the file, transform it AFTER.
// setup imagick for colour
$Img = new Imagick();
$Img->SetResolution(200,200);
$Img->SetColorspace(Imagick::COLORSPACE_SRGB);
// now read pdf first page.
$Img->ReadImage("{$File}[0]");
$Img->TransformImageColorSpace(Imagick::COLORSPACE_SRGB);
// the rest of your stuff.

You may try changing:
$image->transformImageColorSpace(1);
to
$image->transformImageColorSpace(Imagick::COLORSPACE_RGB);.
I'm not sure what you are trying to do with the 1, but according to PHP.net, there are predefined colorspaces that can be added to transformImageColorSpace(); to have the image output with the correct colorspace.

The problem you are seeing is likely to be an old version of GhostScript that is not doing the conversion correctly. Below is the image produced when calling your code on a system that has GhostScript version 8.70 installed:
btw you almost certainly want to be using SRGB colorspace, not plain old RGB. SRGB is the correct one to use for displaying images on computer screens.
$image->transformImageColorSpace(\Imagick::COLORSPACE_SRGB);
Here is a command line to test ghostscript by itself doing the conversion:
./gs-916-linux_x86_64 \
-q -dQUIET -dSAFER -dBATCH \
-dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 \
-dAlignToPixels=0 -dGridFitTT=1 -sDEVICE=pngalpha \
-dFirstPage=1 -dLastPage=3 \
-dTextAlphaBits=4 -dGraphicsAlphaBits=4 -r72 \
-sOutputFile=gs-%d.png tree-blackandwhite.pdf
It should convert the image to a PNG. You'd probably need to replace ./gs-916-linux_x86_64 with just gs.

Related

Convert CMYK PDF to SRGB JPG using PHP and Imagick

I'm trying to convert the first page of PDF documents to a JPEG using Imagick and PHP. As long as the colorspace of the PDF is SRGB, conversion succeeds and the resulting images have correct colors. However, if the PDF has a CMYK colorspace, after conversion, the image colors are off (much brighter or darker).
I'm currently using the following software:
PHP 7.4.3
ImageMagick 6.9.10-23 Q16 x86_64 20190101 (deb package)
Ghostscript 9.50 (2019-10-15)
I'm working on WSL2 on Windows 10.
My test PDF can be found here.
Because I was not happy with the resulting conversions, I firstly tried to see if it is possible to do a successful conversion using Imagick cli. After lots of trial and error, I found that the following command yielded the best result:
convert -density 300 -colorspace srgb input.pdf[0] -layers flatten -strip output.jpg
Result:
I then rewrote the command to PHP:
$input = 'input.pdf';
$output = 'output.pdf';
$image = new Imagick();
$image->setResolution(300, 300);
$image->readImage("{$input}[0]");
$image->transformImageColorspace(Imagick::COLORSPACE_SRGB);
$image = $image->mergeImageLayers(Imagick::LAYERMETHOD_FLATTEN);
$image->setImageFormat('jpeg');
$image->stripImage();
$image->writeImage($output);
$image->destroy();
Result:
The result of the PHP code is not the same as the result of the CLI version and the original PDF. The result is the same as if I would run te following CLI command:
convert -density 300 input.pdf[0] -colorspace srgb -layers flatten -strip output.jpg
The command looks almost the same, however the transforming of the color space happens later.
My question is: what step do I miss in my PHP code to achieve the same result as the command
convert -density 300 -colorspace srgb input.pdf[0] -layers flatten -strip output.jpg
Additional information:
I also tried using color profiles to do the colorspace transformations. Instead of
$image->transformImageColorspace(Imagick::COLORSPACE_SRGB);
I used
$cmyk = file_get_contents('USWebCoatedSWOP.icc');
$rgb = file_get_contents('sRGB_v4_ICC_preference.icc');
$image->profileImage('icc', $cmyk);
$image->profileImage('icc', $rgb);
Besides these two profiles, I also tried combinations of other CMYK (CoatedFOGRA39, JapanColor2001Coated...) and SRGB (AdobeRGB1998, AppleRGB, sRGB_v4_ICC_preference_displayclass...) profiles.
However, I couldn't find a profile combination that came close to the result of the CLI output and the original PDF file.
Thanks to #fmw42, I was able to fix my issue. To fix it, set the color space using setColorSpace() before reading in the pdf.
$input = 'input.pdf';
$output = 'output.pdf';
$image = new Imagick();
$image->setResolution(300, 300);
$image->setColorSpace(Imagick::COLORSPACE_SRGB); // Add this line
$image->readImage("{$input}[0]");
// $image->transformImageColorspace(Imagick::COLORSPACE_SRGB); // You don't need this line
$image = $image->mergeImageLayers(Imagick::LAYERMETHOD_FLATTEN);
$image->setImageFormat('jpeg');
$image->stripImage();
$image->writeImage($output);
$image->destroy();

Merging PDF's using Ghostscript outputs as grayscale / loses color

I have a script which takes a base64 string and converts it into a png image. I then use Imagick to to convert the png into a pdf which uses a AdobeRGB1998 icc profile. This all works as expected and creates a color pdf.
$data = str_replace("data:image/png;base64,","",$_POST["rsa"]);
$save = $path.$_POST["pdfname"].".png";
$imagick = new Imagick();
$decoded = base64_decode($data);
$imagick->readimageblob($decoded);
$imagick->writeImage($save);
$imagick->clear();
$imagick->destroy();
exec("convert $path.$_POST["pdfname"].".png -profile AdobeRGB1998.icc -density 300 ".$path.".$_POST["pdfname"].".pdf", $array);
However, when I then use Ghostscript to merge a bunch of these PDFs together using the below code it outputs in grayscale and I'm not sure why.
function getPDFs($e)
{
return $path.$e['pdffilename'].".pdf ";
}
$fileArray = array_map("getPDFs(", $_POST['item']);
$outputName = $path."LatestDispatch.pdf";
$cmd = "gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=$outputName ";
foreach($fileArray as $file) {
$cmd .= $file." ";
}
$result = shell_exec($cmd);
I switched to using Ghostscript as opposed to imagick to merge pdfs. Imagick returned a merged color pdf but seemed to hit a limit as to how many PDF's imagick was able to merge at once. Ghostscript doesn't have any problems or limits as to how many PDFs it merges so would like to continue with this method as opposed to Imagick, however I need to resolve this issue of PDF's outputting in grayscale, not color. Can anyone help please?
Thanks!
First; Ghostscript doesn't 'merge' PDF files. When you present it with a list of PDF files as input, and use the pdfwrite device to output a single PDF file, it isn't 'merging' the PDF files.
What happens is that each PDF file is fully interpreted to produce a sequence of marking operations, these operations are then passed to the device. For rendering devices they render a bitmap. For PDF output, they are emitted as PDF equivalent operations.
So the content of the output PDF file bears no relation to the content of the input files. The appearance should be the same, but its not 'merging'.
You haven't said what version of Ghostscript you are using, or where you sourced it from (or even what OS you are using, but I guess some flavour of Linux). There's nothing obviously wrong with the command line, but if I were you I'd start by not using a script. Just use Ghostscript manually from the shell to see what happens. If that works, ans the script doesn't, then there's something wrong with the script, and you aren't mimicking it properly from teh shell. Have the script print out the precise command line and try to see if there's some difference in what you typed at the shell.
If it behaves the same, then its puzzling. But without some example to look at, there's little I can advise.

Imagemagick How to Convert PDF with transparency to PNG

I have a project that has makes a PDF for print. I then have it converted to PNG to show back to the client, but the PNG is not retaining the transparency that is in the PDF. I checked the PDF by opening it up in Photoshop and the transparency exists, but it's not converting this data over to the PNG.
The PDF I am using is at: http://mattodesigns.com/PDFs/PNG/testing2.pdf
The page that I am running the conversion on is at: http://mattodesigns.com/PDFs/PNG/pdf2png.html
The PHP Code that I am using to convert the PDF to PNG is:
<?php
$source = 'http://mattodesigns.com/PDFs/PNG/testing2.pdf';
$target = 'testing2.png';
//PNG preview for front
$imagefront = new Imagick();
$imagefront->setResolution( 150, 150 );
$imagefront->readimage($source);
$imagefront->setImageFormat( "PNG32" );
$imagefront->writeImage($target);
?>
This is not working and not sure how I get this to retain the transparency that is in the PDF.I have been looking all over for a solution that is not via a command line and haven't been able to find out. I have also been trying all sorts of various combonation of Imagemagick settings with no luck.
If I need to make a mask, I can do that, but would rather not do that if I don't have to, as all the data is in the PDF itself.
For those who have the same issue, I ended up using GhostScript, following the answer on this topic : http://www.imagemagick.org/discourse-server/viewtopic.php?f=1&t=14546&start=15
exec("gs -dSAFER -dBATCH -dNOPAUSE -sDEVICE=pngalpha -dTextAlphaBits=4 -dGraphicsAlphaBits=4 -r300 -dFirstPage=1 -dLastPage=1 -sOutputFile=output.png input.pdf");
It looks like ImageMagick is having problems handling semi-transparent PNGs, and GhostScript has much better results.

Convert PDF to JPG image with PHP

I am using ImageMagik to try and convert the contents of a PDF to JPG, but keep getting an empty jpg. I have made sure the perms are 777 on everything for testing so I am a little lost how to continue.
Here is the script I am running
<?php
exec('convert testfile.pdf output.jpg', $output, $return_var);
?>
Try this.
<?php
$pdf = 'testfile.pdf';
$save = 'output.jpg';
exec('convert "'.$pdf.'" -colorspace RGB -resize 800 "'.$save.'"', $output, $return_var);
?>
Use the absolute path to the binary, like this:
exec('/usr/bin/convert testfile.pdf output.jpg', $output, $return_var);
But make sure your convert binary is actually on /usr/bin you can check that out with the following command:
which convert
convert -normalize yourfile.pdf[0] yourdestination.jpg
ImageMagick internally use GhostScript and Generally the conversion of ImageMagick is slow Comparing to Ghoastscript, so If you are only interested on getting convert pdf to images then Ghostscript gs command is faster.
below is an sample wrapper around Ghostscript which I wrote few days back.
PDFLib-Php
$pdflib = new ImalH\PDFLib\PDFLib();
$pdflib->setPdfPath($pdf_file_path);
$pdflib->setOutputPath($folder_path_for_images);
$pdflib->setImageQuality(95);
$pdflib->setDPI(300);
$pdflib->setPageRange(1,$pdflib->getNumberOfPages());
$pdflib->convert();
Here you have my solution. Use Imagick directly in your php code.
Convert all PDF pages to JPG
// create Imagick object
$imagick = new Imagick();
// Reads image from PDF
$imagick->readImage('file.pdf');
// Writes an image
$imagick->writeImages('converted.jpg', false);
Convert specific PDF page to JPG
// create Imagick object
$imagick = new Imagick();
// Read image from PDF
$imagick->readImage('test.pdf[0]');
// Writes an image
$imagick->writeImages('converted_page_one.jpg');
Another way to deal with this problem is to use spatie/pdf-to-image library.
Cheers!

PHP IMagick RGB to CMYK inverts?

I'm trying to convert a RGB .gif to a CMYK .gif using IMagick PHP module.
I've wrote this piece of code
$i = new Imagick('mosaique.gif');
$i->setImageColorspace(Imagick::COLORSPACE_CMYK);
$i->setImageFormat('gif');
$i->writeImage('mosaique-cmyk.gif');
But the resultant "mosaique-cmyk.gif" still a RGB... but with inverted colors (O_O)
What am I doing wrong?
EDIT:
I've tried with a .jpg and the image is converted to CMYK but it stills in negative.
EDIT 2:
I've tried to run my script making a .pdf on another server and it works fine.
Are there any known bug in IMagick?
Are there some options to set in the php5 library?
The version that returns me the inverted image is newer than the one that works correctly
WRONG RESULT
PHP 5.3.3
IMagick 3.0.0RC1
ImageMagick 6.6.2
CORRECT RESULT
PHP 5.2.10
IMagick 2.1.1
ImageMagick 6.5.1
The error in fact it's a bug ;)
I reported it, some other has confirmed my fear and now it's assigned to a developer for a fix: http://pecl.php.net/bugs/bug.php?id=22184
At this moment the solution it's to use a different version of the libraries.
GIF is 256-color format aka "indexed." I do not think one can save a gif as cmyk. Each of the 256 colors is an RGB value, but it is not capable of storing the full RGB gamut.
Try this:
$im->stripImage();
$icc_cmyk_profile_path='image_functions/cmyk_icc_profiles/USWebUncoated.icc';
//[http://www.mattbeals.com/icc/][1]
$icc_cmyk = file_get_contents($icc_cmyk_profile_path);
$im->profileImage('icc', $icc_cmyk);
unset($icc_cmyk);
$colorspace=$im->getImageColorspace();
if ($colorspace==12) {
echo "CMYK";
}
$im->stripImage();
$im->writeImage($destination);
$im->clear();
$im->destroy();
see here http://imagemagick.org/Usage/formats/#color_profile
convert cmyk_image.jpg -colorspace
rgb rgb_image.jpg

Categories