I have a big pdf file that about >100mb.
I want to save that pdf page by page converting to jpg.
My php script works well but image quality sucks even quailty set to 100. Jpg output max width set to 1024.
Each file size about 2.5mb. I have searched for this problem but i get everytime about command line solutions. I must use php.
$file = 'e-magazine/1/ebook.pdf';
if($file === null && !file_exists($file)) {
throw new \Exception('FILE NOT EXISTS');
}
$nop = new \Imagick($file);
for($i = 0; $i <= $nop->getnumberimages(); $i++) {
$image_file = 'e-magazine/1/'.($i+1).'.jpg';
$im = new \Imagick();
$im->readimage($file.'['.$i.']');
$im->setImageCompressionQuality(100);
$im->setimageformat('jpeg');
$im->resizeImage(1024, 0, \Imagick::FILTER_CATROM, 1);
$im->writeimage($image_file);
$tm = new \Imagick();
$tm->readimage($image_file);
$tm->setImageCompressionQuality(60);
$tm->setimageformat('jpeg');
$tm->resizeImage(200, 0, \Imagick::FILTER_CATROM, 1);
$tm->writeimage('e-magazine/1/thumbnails/'.($i+1).'_thumb.jpg');
}
What can i do to correct file quality?
PDFs are vector, rather than bitmap, based so you need to set the density before reading the file in order to tell ImageMagick what sort of size you are going to need then it can rasterize accordingly on input. Try the following PRIOR to reading the image:
$im->setResolution(288,288);
Then try reducing that value, say to 144, and comparing the quality till you have enough quality. It is a tradeoff of quality versus processing time and memory demand. The higher the number the higher the quality but the longer and the more memory.
My full solution to this with compensation for PNG transparency alpha channels
$im = new imagick();
$im->setResolution(300, 300);
$im->readimage($pdf_path.'_0.pdf[0]');
$im->setImageResolution(300, 300);
$im->setImageBackgroundColor('#ffffff');
$im = $im->flattenImages();
$im->setImageFormat('jpeg');
$im->setImageCompression(imagick::COMPRESSION_JPEG);
$im->setImageCompressionQuality(100);
$im->resizeImage(1200, 0, imagick::FILTER_LANCZOS, 1);
Related
I'm trying to convert an pdf to a jpeg, trim the whitespaces around the content and resize it to 300x600
In PHP using ImageMagick 6.7.7-10
here's my code:
$im = new \Imagick();
$im->setBackgroundColor("white");
$im->readimage($url);
$im->setImageFormat("jpeg");
$im->trimImage(0);
$im->resizeImage(300, 600, Imagick::FILTER_LANCZOS, 0.9);
$im->writeImage($tmpFilePath);
$im->clear();
$im->destroy();
here is the PDF
http://cs1.fuman.de/file.php/1AOrL6-PzT71Z-dk0000-CsjquC
and here the resulting JPG
http://cs1.fuman.de/file.php/1AOrL0-kWAl8P-ml0000-xAhOiw
Does anyone know, what's going wrong here?
Thanks in advance
JD
I don't know why the background color is being ignored. I think it's to do with JPEG not having a concept of a 'background' colour, and so when the image is converted from having alpha to not having alpha, bad things happen.
I suggest using this code:
$imagick = new \Imagick();
// Make the image be large when read from PDF so have decent quality later
$imagick->setResolution(92, 92);
// only use the first page of the PDF
$imagick->readimage("./orig.pdf[0]");
// Make a white background imge
$canvas = new Imagick();
$canvas->newPseudoImage(
$imagick->getImageWidth(),
$imagick->getImageHeight(),
'canvas:white'
);
// Need to use png format to keep alpha channge
$imagick->setImageFormat('png');
// Composite our image, into the white background
$canvas->compositeImage($imagick, \Imagick::COMPOSITE_ATOP, 0, 0);
$canvas->resizeImage(300, 600, Imagick::FILTER_LANCZOS, 1);
$canvas->setImageFormat('png');
$canvas->writeImage("output.png");
I'm using imagecopyresampled to resize (shrink) an image, which happens to be a gif. The image contains text which, when resized, is quite blurry. I wouldn't necessarily mind that, but when displaying the original image on a web page, at the reduced size, my browser scales it down with much nicer results. Any idea what I can do to improve what PHP produces?
UPDATE: Here's an example of the code I'm running:
$x1 = 0;
$y1 = 0;
$w1 = 196;
$h1 = 260;
$x2 = 0;
$y2 = 0;
$w2 = 140;
$h2 = 186;
$r1 = imagecreatefromgif($source);
$r2 = imagecreatetruecolor($w2, $h2);
imagealphablending($r2, false);
imagesavealpha($r2, true);
$res = imagecopyresampled($r2, $r1, $x2, $y2, $x1, $y1, $w2, $h2, $w1, $h1);
imagegif($r2, $dest);
Here's an example of the image scaled by the browser:
Here's an example of the image scaled with the above code:
Try to use imagepng instead of imagegif. imagepng third parameter is quality. Check specs: http://php.net/manual/en/function.imagepng.php
The PHP libraries aren't going to produce the best quality resize operation however you may find you have better results if you stick to a ratio based on the original file such that resizing a 200x200 to 100x100 or 50x50 would be find as its easy maths for the process to handle (i.e. merge 2/4 pixels into one). Your current operation is producing blurry results as it'll be a random value such as scaling to 0.63% of the original size.
I have a simple watermark script which works well, but it seems adobe sRGB images lose color quality.
Running a watermark command via shell/imagemagick works great - no color quality lost.
Using imagick, however, dulls the color.
Here is the series of commands I use:
$image = new Imagick();
$image->readImage($this->source_path);
$watermark = new Imagick();
$watermark->readImage($this->watermark_path);
// how big are the images?
$iWidth = $image->getImageWidth();
$iHeight = $image->getImageHeight();
$wWidth = $watermark->getImageWidth();
$wHeight = $watermark->getImageHeight();
// calculate the position
$x = ( $iWidth - $wWidth ) / 2;
$y = ( $iHeight - $wHeight ) / 2;
//we have to make the transparency go to white, or it will become an awefull black color in jpeg version
$white = new Imagick();
$white->newImage($image->getImageWidth(), $image->getImageHeight(), "white");
if ($image->getImageColorspace() == Imagick::COLORSPACE_SRGB) {
$watermark->setColorspace(imagick::COLORSPACE_RGB);
$white->setColorspace(imagick::COLORSPACE_RGB);
}
$white->compositeimage($image, Imagick::COMPOSITE_OVER, 0, 0);
//now apply watermark
$white->compositeImage($watermark, imagick::COMPOSITE_OVER, $x, $y);
//save
$white->writeImage($this->destination);
//save memory
$image->destroy();
$white->destroy();
I made a half-educated assumption that if I convert the other two elements (the white background, and the png overlay) to sRGB, nothing would be lost. I did that with this segment here:
if ($image->getImageColorspace() == Imagick::COLORSPACE_SRGB) {
$watermark->setColorspace(imagick::COLORSPACE_RGB);
$white->setColorspace(imagick::COLORSPACE_RGB);
}
...Still no shrimp Lieutenant Dan...
Is there any possible way around this issue? Ideally I'd like to use the shell commands, but I'd like to perfect the imagick version for those who do not have shell access in their environments.
I found the solution here: http://www.php.net/manual/ru/imagick.compositeimage.php (was like a scavenger hunt!)
The solution as stated in above link:
You might need to set the colorspace the same when composing two
images over each other
<?php
//Creating two Imagick object
$first = new Imagick('first.jpg');
$second = new Imagick('second.jpg');
// Set the colorspace to the same value
$first->setImageColorspace($second->getImageColorspace() );
//Second image is put on top of the first
$first->compositeImage($second, $second->getImageCompose(), 5, 5);
//new image is saved as final.jpg
$first->writeImage('final.jpg');
?>
I'm using FPDF with an extension I found online called TransFPDF that allows for transparent PNG's to be put into the PDF that I am dynamically generating with PHP. The problem I am having however is that the PDF takes a long time to generate (the script takes about 30 seconds to run when I am embedding about 6 characters, where each characters is a transparent PNG. This time also includes text and the background but I checked times and those only take about a second or two and are not slowing down the code).
I have found that the main slow point is the following function:
// needs GD 2.x extension
// pixel-wise operation, not very fast
function ImagePngWithAlpha($file,$x,$y,$w=0,$h=0,$link='')
{
$tmp_alpha = tempnam('.', 'mska');
$this->tmpFiles[] = $tmp_alpha;
$tmp_plain = tempnam('.', 'mskp');
$this->tmpFiles[] = $tmp_plain;
list($wpx, $hpx) = getimagesize($file);
$img = imagecreatefrompng($file);
$alpha_img = imagecreate( $wpx, $hpx );
// generate gray scale pallete
for($c=0;$c<256;$c++) ImageColorAllocate($alpha_img, $c, $c, $c);
// extract alpha channel
$xpx=0;
while ($xpx<$wpx){
$ypx = 0;
while ($ypx<$hpx){
$color_index = imagecolorat($img, $xpx, $ypx);
$alpha = 255-($color_index>>24)*255/127; // GD alpha component: 7 bit only, 0..127!
imagesetpixel($alpha_img, $xpx, $ypx, $alpha);
++$ypx;
}
++$xpx;
}
imagepng($alpha_img, $tmp_alpha);
imagedestroy($alpha_img);
// extract image without alpha channel
$plain_img = imagecreatetruecolor ( $wpx, $hpx );
imagecopy ($plain_img, $img, 0, 0, 0, 0, $wpx, $hpx );
imagepng($plain_img, $tmp_plain);
imagedestroy($plain_img);
//first embed mask image (w, h, x, will be ignored)
$maskImg = $this->Image($tmp_alpha, 0,0,0,0, 'PNG', '', true);
//embed image, masked with previously embedded mask
$this->Image($tmp_plain,$x,$y,$w,$h,'PNG',$link, false, $maskImg);
}
Does anyone have any ideas of how I could speed this up? I can't seem to get it to go faster than about 4 seconds per character which really adds up fast (a character probably is about 1000x2000 pixels, and yes I know this is a lot, but yes it is neccessary for a printable PDF).
Thank you.
How to do that with GD?
Create a new truecolor image resource (t) with the same dimensions as the source image (s) and then copy (s) to (t).
e.g. (without error handling):
$imgSource = imagecreatefromgif('xyz.gif');
$width = imagesx($imgSource);
$height = imagesy($imgSource);
$imgTC = imagecreatetruecolor($width, $height);
imagecopy($imgTC, $imgSource, 0, 0, 0, 0, $width, $height);
// save or send $imgTC
You'll have both images in memory in the gd2 format (4 bytes per pixel? 5?), so you better check your memory_limit setting before trying this with larger images.
Since PHP 5.5 there's a fast, easy and less memory-hungry solution: just use the imagepalettetotruecolor PHP function:
$imgSource = imagecreatefromgif('xyz.gif');
if (!imageistruecolor($imgSource)) {
imagepalettetotruecolor($imgSource);
}
All you need to do is use imagecreatetruecolor to create a new image and then imagecopy your palette-based image onto it.