Create PDF thumbnail with Imagick and write to file - php

I'm trying to create a pdf thumbnail with Imagick and save it on the server in the same location as the pdf. The code below works fine as is. The problem is that I don't want to echo the image. But if I remove the echo statement, the resulting jpg file contains errors and is unreadable. How can I create the thumbnail and write to a file without sending it to the browser?
$pdfThumb = new \imagick();
$pdfThumb->setResolution(10, 10);
$pdfThumb->readImage($filePath . $fileName . $fileExt . '[0]');
$pdfThumb->setImageFormat('jpg');
header("Content-Type: image/jpeg");
echo $pdfThumb;
$fp = fopen($filePath . $fileName . '.jpg', "x");
$pdfThumb->writeImageFile($fp);
fclose($fp);
DaGhostman Dimitrov provided some helpful code on #16606642, but it doesn't work for me for some reason.

I would try:
$pdfThumb = new imagick();
$pdfThumb->setResolution(10, 10);
$pdfThumb->readImage($filePath . $fileName . $fileExt . '[0]');
$pdfThumb->setImageFormat('jpg');
$fp = $filePath . $fileName . '.jpg';
$pdfThumb->writeImage($fp);

Bonzo's answer requires imagick on the webserver. If imagick is not on the webserver you can try to execute imagemagick from the commandline by php command exec():
exec('convert -thumbnail "178^>" -background white -alpha remove -crop 178x178+0+0 my_pdf.pdf[0] my_pdf.png')
And if you like to convert all pdfs in one step from same folder where your script is located try this:
exec('for f in *.pdf; do convert -thumbnail "178^>" -background white -alpha remove -crop 178x178+0+0 "$f"[0] "${f%.pdf}.png"; done');
In this examples I create a png thumbnail 178x178 pixel from the first page (my_pdf.pdf[0] the 0 means first pdf page).

Related

Php Imagick : Pdf are converted into JPG with Very bad quality

I am using Imagick extension in my one of project. This is new for me.
The following is my code.
$pdfPath = $config['upload_path'] . '/' . $fileName;
$im = new imagick();
$im->setResolution(300, 300);
$im->readImage($pdfPath);
$im->setImageFormat('jpeg');
$im->setImageCompression(imagick::COMPRESSION_JPEG);
$im->setImageCompressionQuality(100);
$im->writeImage($config['upload_path'] . '/' . str_replace('pdf', 'jpeg', $fileName));
$im->clear();
$im->destroy();
This gives me very poor quality in image.
All text are converted into black background. Images are also not showing proper.
See below image, which is converted from PDF.
Please help me.
You need to put options for the image background color set white. For here I have added options of $im->->flattenImages();
Here you can find out the solutions https://www.binarytides.com/convert-pdf-image-imagemagick-php/
From
$pdfPath = $config['upload_path'] . '/' . $fileName;
$im = new imagick();
$im->setResolution(300, 300);
$im->readImage($pdfPath);
$im->setImageFormat('jpeg');
$im->setImageCompression(imagick::COMPRESSION_JPEG);
$im->setImageCompressionQuality(100);
$im->writeImage($config['upload_path'] . '/' . str_replace('pdf', 'jpeg', $fileName));
$im->clear();
$im->destroy();
TO
$pdfPath = $config['upload_path'] . '/' . $fileName;
$im = new imagick();
$im->setResolution(300, 300);
$im->readImage($pdfPath);
$im->setImageFormat('jpeg');
$im->setImageCompression(imagick::COMPRESSION_JPEG);
$im->setImageCompressionQuality(100);
// -flatten option, this is necessary for images with transparency, it will produce white background for transparent regions
$im = $im->flattenImages();
$im->writeImage($config['upload_path'] . '/' . str_replace('pdf', 'jpeg', $fileName));
$im->clear();
$im->destroy();
I am not sure it will be help for you or not.
I think the problem lies in the fact that we are inputing a resolution of dots per inch from the pdf and outputting it as pixels per inch as we make the jpeg.
This codes works as far as it appears to keep the correct aspect ration and I can make out the pdf that I used to test. But it's not very clear at all, I cant read any text. Here is what I used.
$pdfPath = $config['upload_path'] . '/' . $fileName;
$img = new imagick();
$img->setResolution(300, 300);
$img->readImage($pdfPath); //Open after yuo set resolution.
$img->setImageUnits(imagick::RESOLUTION_PIXELSPERINCH); //Declare the units for resolution.
$img->setImageFormat('jpeg');
$img->setImageCompression(imagick::COMPRESSION_JPEG);
$img->setImageCompressionQuality(100);
$img->writeImage($config['upload_path'] . '/' . str_replace('pdf', 'jpeg', $fileName));
$img->clear();
$img->destroy();
From what I have read you may need to install Ghostscript on your machine and executing the script from your command line seems to be preferred and offer better results and performance.
I found this article and it looks like it's loaded with a bunch of info for image formats and how imagemagik handles them. It has a bit in there on PDFs.
http://www.imagemagick.org/Usage/formats/#tiff
I might look into a PHP PDF library that has all the stuff already built into it. No sense in reinventing the wheel. There might be a function already build in to do exactly what your trying to do.

IMagick RGB to CMYK corrupt conversion

I'm converting images from RGB to CMYK with IMagick in PHP.
During conversion some images get black grids on them.
Code:
$IMagick = new IMagick();
$IMagick->clear();
$IMagick->readImage(SITE_ROOT . 'userfiles/image/products/' . $image);
$IMagick->negateImage(false, Imagick::CHANNEL_ALL);
$IMagick->setImageColorspace(13);
$icc_cmyk = file_get_contents(dirname(__FILE__).'/USWebCoatedSWOP.icc');
$IMagick->profileImage('icc', $icc_cmyk);
unset($icc_cmyk);
$IMagick->setImageColorspace(12);
$IMagick->writeImage (SITE_ROOT . 'userfiles/image/products/cmyk/' . $image);
Images:
Original
Converted
I'm converting around 80 images in a loop and most of them are OK.
Any idea why it happens?
EDIT:
Working code:
$IMagick = new IMagick();
$IMagick->clear();
$IMagick->readImage(SITE_ROOT . 'userfiles/image/products/' . $image);
$icc_cmyk = file_get_contents(dirname(__FILE__).'/USWebCoatedSWOP.icc');
$IMagick->profileImage('icc', $icc_cmyk);
unset($icc_cmyk);
$IMagick->transformImageColorspace(12);
$IMagick->writeImage (SITE_ROOT . 'userfiles/image/products/cmyk/' . $image);
setImageColorspace should only be used when creating new images, either through Imagick::newPseudoImage or rendering an ImagickDraw instance into an image.
For existing images, the correct method to change the colorspace of the image is Imagick::transformImageColorspace.

Why is convert creating to files in some instances?

I am using a php script to convert PDF files into images when users upload supporting documentation. It is working great, however ocasionaly it creates 2 near identical files and appends "-0" and "-1". This is throwing me for a loop because my script does not know when this happens and then points to the wrong file name. Any idea what causes this and how to correct would be greatly appreciated.
This is the code:
$filename = $_FILES['file']['name'];
$filename1 = $upload_dir.$_FILES['file']['name'];
rename($_FILES['file']['tmp_name'], $upload_dir.$_FILES['file']['name']);
chmod($filename, 0777);
//If the file is a pdf change it to a jpg.
$file_array = explode(".", strtolower($filename));
$file_jpg = $file_array[0];
$file_jpg = $upload_dir.$file_jpg . ".jpg";
$file_extn = end(explode(".", strtolower($filename)));
if($file_extn == 'pdf'){
$filename3 = substr($filename1, 0, -3);
$filename3 = $filename3 . "jpg";
$createjpgpath = $filename3;
$basefile_jpg = substr($filename, 0, -3) . "jpg";
exec('convert -geometry 1600x1600 -density 130x130 -quality 20 "'.$filename1.'" "'.$filename3.'"');
unlink($filename1);
}
Else{
$filename3 = $upload_dir.$_FILES['file']['name'];
$basefile_jpg = $filename;
}
This is what I use:
exec('convert "'.$targetFile.'[0]" -flatten -geometry 1600x1600 -density 130x130 -quality 20 "'.$previewTargetFile.'"');
The "[0]" and "-flatten" will flatten the file and output only one image. Some PDF's have multiple pages.

Uploaded image: converting format

I want to convert a uploaded image to its original format, (jpg, jpeg rpng, etc.) but I need to re-size these images to be 150px width and 210px height. Is it possible to change the size while copying, or do I have to convert it?
This was unsucessful:
$uploaddir1 = "/home/myweb/public_html/temp/sfds454.png";
$uploaddir2 = "/home/myweb/public_html/images/sfds454.png";
$cmd = "/usr/bin/ffmpeg -i $uploaddir1 -vframes 1 -s 150x210 -r 1 -f mjpeg $uploaddir2";
#exec($cmd);
You can use gd instead of ffmpeg. To convert or resize an image, see this example: http://ryanfait.com/resources/php-image-resize/resize.txt
Php lib for gd:
http://php.net/manual/en/function.imagecopyresampled.php
There is also some samples of resizing scripts in that page.
I recently had to solve just this problem, and implemented this simple caching solution:
<?php
function send($name, $ext) {
$fp = fopen($name, 'rb');
// send the right headers
header("Content-Type: image/$ext");
header("Content-Length: " . filesize($name));
// dump the picture and stop the script
fpassthru($fp);
exit;
}
error_reporting(E_ALL);
ini_set('display_errors', 'On');
if (isset($_REQUEST['fp'])) {
$ext = pathinfo($_REQUEST['fp'], PATHINFO_EXTENSION);
$allowedExt = array('png', 'jpg', 'jpeg');
if (!in_array($ext, $allowedExt)) {
echo 'fail';
}
if (!isset($_REQUEST['w']) && !isset($_REQUEST['h'])) {
send($_REQUEST['fp']);
}
else {
$w = $_REQUEST['w'];
$h = $_REQUEST['h'];
//use height, width, modification time and path to generate a hash
//that will become the file name
$filePath = realpath($_REQUEST['fp']);
$cachePath = md5($filePath.filemtime($filePath).$h.$w);
if (!file_exists("tmp/$cachePath")) {
exec("gm convert -quality 80% -colorspace RGB -resize " .$w .'x' . $h . " $filePath tmp/$cachePath");
}
send("tmp/$cachePath", $ext);
}
}
?>
Some things that I noticed:
Graphicsmagick converted much faster than imagemagick, although I did not test conversion with cuda processing.
For the final product I re-implemented this code in ASP using the language's native graphics library. This was much faster again but would break if out-of-memory errors occurred (worked fine on my workstation, but wouldn't work on 4GB RAM server).

Image creation from pdf

I am creating a cron job in which I copy files from one directroy to another. The cron job works fine it copies the files to the import directory. The structure of import directory is like this.
import
folder1
pdf_file1
folder2
pdf_file2
I am trying to create a thumbnail image for each pdf file that is copied to the folders, I installed ImageMagik and my php code to create a thumnail image is
if ($preview != "") {
$copy_res = ftp_get("files/upload/" . $ftp_upload["path"] . "/" . $preview, "files/import/" . $ftp_upload["preview"] . "/" . $preview);
$md5_checksum = md5("files/import/" . $ftp_upload["path"] . "/" . $preview);
} else {
//$pdf_file = 'files/import/folder1/pdf_file1';
$pdf_file = 'files/import/' . $ftp_upload["path"]."/".$filename_new;
if (file_exists($pdf_file)){
echo 'I am here';
exec("convert -density 300 " . $pdf_file . "[0]" . $filename_new . ".jpg");
}
}
When I run the code it comes to the else statement and echo the line but its not executing the exec command.
I checked the convert command from Command Prompt for that I navigated to
C:\wamp\www\project\files\import\folder1
and then I run this command
exec("convert -density 300 test.pdf[0] test.jpg");
From the command prompt it worked but in my code it s not working .
Is there any issue with the path ? because the file is alreday copied when I try to create the thumbnail for it.
The ImageMagik is installed in
C:\Program Files(x86)\ImageMagik
Any ideas what I am doing wron ? and is there any other faster way to create thumbail image for pdf ?
Thanks in advance
I now write my code seperating the code form the exec() so that you can display the information you are sending to Imagemagick.
I would also try setting the filenames outside the exec()
$input = $pdf_file . "[0]";
$output = $filename_new . ".jpg"
$cmd = " -density 300 $input -thumbnail 200x300 $output ";
// echo $cmd."<br>";
exec("convert $cmd");
Added a resize but it will keep the image proportions - if you need an exact size you could crop the image or pad it with a colour.
There seems to be a missing space that separates the path to the pdf file and the new name for the image file.
exec("convert -density 300 " . $pdf_file . "[0]" . $filename_new . ".jpg");
Should be:
exec("convert -density 300 " . $pdf_file . "[0] " . $filename_new . ".jpg");
-----------------------------------------------^

Categories