I running this script to create a jpg image from a pdf.
$im = new Imagick();
$im->setResolution(300, 300);
$im->readImage($temp_path . $file);
if ($im->getImageColorspace() == \Imagick::COLORSPACE_CMYK) {
$profiles = $im->getImageProfiles('*', false);
// we're only interested if ICC profile(s) exist
$has_icc_profile = (array_search('icc', $profiles) !== false);
// if it doesnt have a CMYK ICC profile, we add one
if ($has_icc_profile === false) {
$icc_cmyk = file_get_contents(dirname(dirname(__FILE__)) . '/USWebUncoated.icc');
$im->profileImage('icc', $icc_cmyk);
unset($icc_cmyk);
}
// then we add an RGB profile
$icc_rgb = file_get_contents(dirname(dirname(__FILE__)) . '/sRGB_v4_ICC_preference.icc');
$im->profileImage('icc', $icc_rgb);
unset($icc_rgb);
}
$im->setImageBackgroundColor('white');
$im = $im->flattenImages();
$im->setImageFormat('jpeg');
$im->thumbnailImage(900, 900, true);
Is working fine but the problem is that is taking to long to excecute. and some time if the file have to much detail I get a timeout excecution from php.
I was using it before without the profileImage() file and was working perfect, but the color on the CMYK was not right.
How can I make better and efficient. I running this on linux with php5.5.9
Thanks.
I recommend using cloudinary.com, check it out, it will save you a lot of time.
See if this is any faster and still contains the correct color:
<php
$im = new Imagick();
$im->readImage($temp_path . $file); //pdf
if ($im->getImageColorspace() == \Imagick::COLORSPACE_CMYK) {
$im->transformImageColorspace(\Imagick::COLORSPACE_SRGB);
}
$im->writeImage('out.jpg'); // jpg
?>
Related
I've managed to install Imagemagick 7 on my server and set-up the appropriate PHP module in order to work with HEIC and WebP files using Imagick.
I can convert these files easily to other formats like PNG or JPEG without any problems.
Now, I try to convert a HEIC sequence (original file) to GIF, but the result is imperfect.
First off all, it seems, that Imagick isn't able to determine the delay between every image. This results in a lightning fast animation. So for now, I've hardcoded a delay of 40 ticks using Imagick::setImageDelay. I'm not sure, if I'm missing something, or if Imagick/Imagemagick isn't able to do this on HEIC sequences.
The next problem I'm experiencing is, that Imagick can't handle the original image dimensions properly. To get around this, I have to get the original image's dimensions and perform Imagick::cropImage and Imagick::thumbnailImage on every frame, before I finalize it with Imagick::setImagePage.
However, my biggest problem for now is, that the result has a broken, first frame:
So the final (broken) result looks like this:
While the expected result (generated by heic2any) is:
The (simplified) code I am using:
<?php
if (!in_array('HEIC', \Imagick::queryFormats("HEI*"))) {
throw new \Exception('Unsupported format');
}
$sourceFile = __DIR__ . '/3.heic';
$targetFile = __DIR__ . '/3.gif';
if (!file_exists($sourceFile)) {
try {
$content = file_get_contents('https://github.com/alexcorvi/heic2any/blob/master/demo/' . basename($sourceFile) . '?raw=true');
if ($content === false) {
throw new \Exception('Unable to download source file.');
}
file_put_contents($sourceFile, $content);
} catch (\Exception $e) {
throw new \Exception('Unable to download source file: ' . $e->getMessage());
}
if (!file_exists($sourceFile)) {
throw new \Exception('Cannot find source file.');
}
}
$im = new \Imagick($sourceFile);
$width = $im->getImageWidth();
$height = $im->getImageHeight();
$im = $im->coalesceImages();
foreach ($im as $frame) {
$im->setImageDelay(40);
$frame->cropImage($width, $height, 0, 0);
$frame->thumbnailImage($width, $height);
$frame->setImagePage($width, $height, 0, 0);
}
$im = $im->deconstructImages();
$im->writeImages($targetFile, true);
echo 'Size: ' . $width . 'x' . $height . '<br />Result:<br /><br /><img src="' . basename($targetFile) . '?v=' . time() . '" alt="" />';
So my questions are:
Where does the 1st frame come from?
How can I avoid it?
Is there anything to optimize the conversion (code)?
UPDATE:
There's another .HEIC sequence to play with (click) and this one can be converted without problems:
UPDATE:
Even conversion services like cloudconvert can't handle the image correctly and producing GIF animations like this:
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.
This is currently what I have. When I include it in my index.php and then call the function on pageload, I get a blank page. So something is wrong here, but I don't know what. I feel like I'm really close though. I just want to create thumbnails of images in a directory, and then show them in HTML as a list of images you can click that trigger lightboxes.
I'm still really shaky in PHP. I'm trying to wrap my head around editing images in a directory.
<?php
function buildThumbGallery(){
$h = opendir('/Recent_Additions/'); //Open the current directory
while (false !== ($curDir = readdir($h))) {
if (!file_exists('/Recent_Additions/thumbs/')) {
$thumbDir = mkdir('/Recent_Additions/thumbs/', 0777, true);
}else{
$thumbDir = '/Recent_Additions/thumbs/';
}
$width = 200;
$height = 200;
foreach ($curDir as $image) {
$filePath = $curDir."/".$image;
$genThumbImg = $image->scaleImage($width, $height, true);
$newThumb = imagejpeg($genThumbImg, $thumbDir, 100);
echo '<li> <a class="fancybox" data-fancybox-group="'.basename($curDir).'" href="'.$filePath.'" title="'.basename($curDir)." ".strpbrk(basename($filePath, ".jpg"), '-').'"><img src="'.$newThumb.'"/>'.basename($curDir).'</a>';
imagedestroy($newThumb);
}echo '</li>';
}
?>
You are doing several things wrong:
You're not closing the while loop.
Readdir already loops through a directory, your foreach is not doing anything.
You are missing quotes in your echo.
You are calling the method scaleImage on a string, I think you meant to call the function imagescale.
You're missing and misunderstanding a lot of stuff, take a look at how to create a thumbnail here: https://stackoverflow.com/a/11376379/4193448
Also see if you can enable PHP errors, getting a blank page while your code is full of errors is not really helping is it?
::EDIT::
With help from #swordbeta, I got my script working properly. Here is the code for future reference:
<?php
function buildThumbGallery(){
$curDir = "./Recent_Additions/";
$thumbsPath = $curDir."thumbs/";
if (!file_exists($thumbsPath)) {
mkdir($thumbsPath, 0777, true);
}
foreach(scandir($curDir) as $image){
if ($image === '.' || $image === '..' || $image === 'thumbs') continue;
if(!file_exists($thumbsPath.basename($image, ".jpg")."_thumb.jpg")){
// Max vert or horiz resolution
$maxsize=200;
// create new Imagick object
$thumb = new Imagick($curDir.$image); //'input_image_filename_and_location'
$thumb->setImageFormat('jpg');
// Resizes to whichever is larger, width or height
if($thumb->getImageHeight() <= $thumb->getImageWidth()){
// Resize image using the lanczos resampling algorithm based on width
$thumb->resizeImage($maxsize,0,Imagick::FILTER_LANCZOS,1);
}else{
// Resize image using the lanczos resampling algorithm based on height
$thumb->resizeImage(0,$maxsize,Imagick::FILTER_LANCZOS,1);
}
// Set to use jpeg compression
$thumb->setImageCompression(Imagick::COMPRESSION_JPEG);
$thumb->setImageCompressionQuality(100);
// Strip out unneeded meta data
$thumb->stripImage();
// Writes resultant image to output directory
$thumb->writeImage($thumbsPath.basename($image, ".jpg")."_thumb.jpg"); //'output_image_filename_and_location'
// Destroys Imagick object, freeing allocated resources in the process
$thumb->destroy();
}else{
echo '<a class="fancybox" data-fancybox-group="'.basename($curDir).'" href="'.$curDir.basename($image, "_thumb.jpg").'" title="Recent Addition - '.basename($image, ".jpg").'"><img src="'.$thumbsPath.basename($image, ".jpg")."_thumb.jpg".'"/></a>';
echo '<figcaption>'.basename($image, ".jpg").'</figcaption>' . "<br/>";
}
}
}
?>
::Original Post::
Ok, after going back and doing some more research and suggestions from #swordbeta, i've got something that works. My only issue now is I can't get the images to show in my index.php. I'll style the output in CSS later, right now I just want to see the thumbnails, and then later build them into lightbox href links:
<?php
function buildThumbGallery(){
$curDir = "./Recent_Additions/";
$thumbsPath = $curDir."/thumbs/";
if (!file_exists($thumbsPath)) {
mkdir($thumbsPath, 0777, true);
}
$width = 200;
foreach(scandir($curDir) as $image){
if ($image === '.' || $image === '..') continue;
if(file_exists($thumbsPath.basename($image)."_thumb.jpg")){
continue;
}else{
// Max vert or horiz resolution
$maxsize=200;
// create new Imagick object
$thumb = new Imagick($curDir.$image); //'input_image_filename_and_location'
// Resizes to whichever is larger, width or height
if($thumb->getImageHeight() <= $thumb->getImageWidth()){
// Resize image using the lanczos resampling algorithm based on width
$thumb->resizeImage($maxsize,0,Imagick::FILTER_LANCZOS,1);
}else{
// Resize image using the lanczos resampling algorithm based on height
$thumb->resizeImage(0,$maxsize,Imagick::FILTER_LANCZOS,1);
}
// Set to use jpeg compression
$thumb->setImageCompression(Imagick::COMPRESSION_JPEG);
$thumb->setImageCompressionQuality(100);
// Strip out unneeded meta data
$thumb->stripImage();
// Writes resultant image to output directory
$thumb->writeImage($thumbsPath.basename($image)."_thumb.jpg"); //'output_image_filename_and_location'
// Destroys Imagick object, freeing allocated resources in the process
$thumb->destroy();
}
} echo '<img src="'.$thumbsPath.basename($image)."_thumb.jpg".'" />' . "<br/>";
}
?>
At the moment, the output from the echo isn't showing anything, but the rest of the script is working properly (i.e. generating thumbnail images in a thumbs directory).
I'm guessing i'm not formatting my echo properly. This script is called in my index.php as <?php buildThumbGallery(); ?> inside a styled <div> tag.
I'm very new to PHP and this is the very first time I've tried to use Imagick, so there must be plenty wrong with the script I wrote in order to achieve my goal. :-)
What I'd like to do:
Convert an image that was uploaded to JPEG and resize it;
Make a blurred version of it;
Move the two images to a certain directory.
I wrote a function that's supposed to do it, but, as you guessed, it doesn't do anything at all:
function convertAndBlur($inputIMG, $dst, $width, $quality) {
$img = new Imagick($inputIMG);
$img->scaleImage($width, 0, true); // keep aspect ratio
$img->setImageFormat('jpeg');
$img->setImageCompressionQuality($quality);
$img->writeImage($dst . ".jpg");
$imgBlur = new Imagick($img);
$imgBlur->blurImage(5,3);
$imgBlur->writeImage($dst . "_blur.jpg");
$img->clear(); $img->destroy();
$imgBlur->clear(); $imgBlur->destroy();
}
The function is called this way:
$picture = $_FILES["picture"]["tmp_name"];
$pictureName = "foo";
if(!is_image($picture)) { die("not an image"); }
$picturePath = "uploads/" . $pictureName;
convertAndBlur($picture, $picturePath, 1000, 90);
This will certainly make some of you roll their eyes, but again, that's completely uncharted territory to me. Could anyone help me out? Thanks!
Imagick's constructor cannot take an instance of Imagick as an argument. To create another object, try $imgBlur = clone $img; in place of $imgBlur = new Imagick($img);, which will create a carbon copy of $img. Read more about cloning Imagick objects here.
I tried to make a thumbnail of a pdf file which is hosted on another server. My current code is:
<?php
$im = new imagick("http://www.d3publisher.us/Walkthroughs/Naruto_NC_3_DS.pdf");
$im->setImageFormat('jpg');
header('Content-Type: image/jpeg');
echo $im;
?>
The problem is that code is only generating thumbnail for LAST PAGE of the pdf file. How can I make a thumbnail for first page only? I tried to add [0] at the imagick line.
$im = new imagick("http://www.d3publisher.us/Walkthroughs/Naruto_NC_3_DS.pdf[0]");
but it didn't work. It only work for local pdf file, i.e:
$im = new imagick("my-pdf-file.pdf[0]");
Please help me solve this problem.. Thanks..
You'll need to reset the active image to the first page. This can be done with Imagick::setIteratorIndex.
<?php
$im = new imagick("http://www.d3publisher.us/Walkthroughs/Naruto_NC_3_DS.pdf");
$im->setIteratorIndex(0);
$im->setImageFormat('jpg');
header('Content-Type: image/jpeg');
echo $im;
?>
Try...
$im->setImageIndex(0); //this will return 1th page of the pdf file
$im->setImageFormat('jpg');
"This can be done with Imagick::setIteratorIndex. .."
..or not. Simply has no effect . Setting it to one crashes something, setting it to 0 gets the last page..
function make_thumbnail($filename)
{
try
{
$imagick= new Imagick($filename);
}
catch(ImagickException $e)
{
// failed to make a thimbynail. what now?
// load up our trusty truetype font png instead?
$imagick->destroy();
return "0"; // shove any rubbish in the db - it will just say no image available when asked.
}
$imagick->setIteratorIndex(0);// rewind to first page or image of a multi series
$imagick->setImageFormat("png"); // turn it into a png
$imagick = $imagick->flattenImages(); // remove any transparency
$imagick->scaleImage(300,0); //resize...to less than 300px wide
$d = $imagick->getImageGeometry();
$h = $d['height'];
if($h > 300)
$imagick->scaleImage(0,300);
$imagick->setImageCompression(\Imagick::COMPRESSION_UNDEFINED);
$imagick->setImageCompressionQuality(0);
$imagick->setIteratorIndex(0);
$a = $imagick->getImageBlob(); // output as bytestream
$imagick->destroy();
return $a;
}