php imagick convert pdf to png high quality - php

I'm trying to convert a PDF to a high quality PNG via Imagick, but the file keeps coming out fuzzy. Currently, I'm running the following options but can't find the right flags to get a clear PNG out of the conversion. The original PDF file is 8.5 x 11. Suggestions? Thanks!
$image = new \Imagick(storage_path('app/'.$path));
$image->setResolution( 200, 200 );
$image->scaleImage(1700,2200);
$image->setImageFormat( "png32" );
$image->writeImage(storage_path('app/'.$split[0].'.png'));

You need to set the resolution before reading the image because the image is rasterised when read, so it doesn't help to set the resolution afterwards - it's too late!
Try along these lines:
$imagick = new Imagick();
$imagick->setResolution(288,288);
$imagick->readImage('someFile.pdf');

$imagick_i = new Imagick();
$imagick_i->setResolution( 595, 842 );
$imagick_i->readImageblob($blob);
$imagick_i->setImageFormat( "png32" );
foreach ($imagick_i as $auxiliaryvalue) {
echo '<img src="data:image/png;base64,' . base64_encode($auxiliaryvalue->getimageblob()) . '" /><br>';
}

Related

Set background colour in PHP Imagick montage function

I am composing an image from 6 images using this code:
$imagick = new Imagick();
foreach ( $productImages as $productImage ) {
$imagick->addImage(new Imagick($productImage));
}
$categoryCollage = $imagick->montageImage(
$categoryImage,
"3x2+0+0",
"150x100+2+2",
Imagick::MONTAGEMODE_CONCATENATE,
"1x1+2+2"
);
Below the result when images with different size and ratio are added. The background colour is grey. How to set it to white?
According to the manual with the command line version it would be the -background parameter but I don't know how to set it in PHP:
https://legacy.imagemagick.org/Usage/montage/
I found a very trivial solution where the grey background disappears:
foreach ( $productImages as $productImage ) {
$subImage = new Imagick($productImage);
$subImage->resizeImage(150, 100, Imagick::FILTER_BOX, 1);
$imagick->addImage($subImage);
}
I just resize the image to the size which will be then anyway used in the collage and as each original image is bigger, there is no an up-scaling issue.
Using then the Imagick::MONTAGEMODE_FRAME constant it looks then quite OK.

get and set image dpi

I need some info about images inside cardimg folder.
$arr = glob("../cardimg/*.jpg");
foreach ($arr as $item){
list($width, $height) = getimagesize($item);
echo $width . '<br>';
echo $height . '<br>';
}
Works fine for width and height, but don't know how to see if an image is 72 or 300 dpi?
my php is 7.0.20 and using
print_r(imageresolution($item));
result is error - Call to undefined function
Also is there a way to change 300dpi to 72dpi using php?
This is straight from PHP.net for imageresolution(). (PHP 7 >= 7.2.0)
<?php
$im = imagecreatetruecolor(100, 100);
print_r(imageresolution($im));
imageresolution($im, 300, 72);
print_r(imageresolution($im));
?>
This should get you what you need once you update your php version:
$im = imagecreatefromstring(file_get_contents($path));
print_r(imageresolution($im));
imagedestroy($im);
Here is a link on how to get gd library up and going.. I'm sure this varies on server setup hosted or not, I don't know. But should help I imagine.
Enable GD support in PHP

PHP Imagick don't use custom font > convert does

It's driving me insane.. Just searched for hours to find a solution. But nothing really found. So hopefully anyone can help me.
I'm trying to create an customized image on the fly. I use this to create the images: https://github.com/Treinetic/ImageArtist
Everything works fine except the font. This is the snippet from the class:
$im = new \Imagick();
$background = new \ImagickPixel('none');
$im->setBackgroundColor($background);
$im->setFont($font->getPath());
$im->setPointSize($writer->getSize() * (0.75));
$im->setGravity(\Imagick::GRAVITY_EAST); //later we will have to change this
$width = $writer->getWidth();
$height = $writer->getHeight();
$text = $writer->getText();
$margin = $writer->getMargin();
$im->newPseudoImage($width, $height, "pango:" . $text );
$clut = new \Imagick();
$clut->newImage(2, 2, new \ImagickPixel($color->toString()));
$im->clutImage($clut);
$clut->destroy();
$im->setImageFormat("png");
$image = imagecreatefromstring($im->getImageBlob());
$template = $this->imageHelper->createTransparentTemplate($width+ (2*$margin),$height+ (2 *$margin));
$img = new Image($template);
$text = new Image($image);
imagedestroy($image);
imagedestroy($template);
return $img->merge($text,$margin,$margin);
The $font-getPath(); looks correct and echo /var/www/vhosts/example.com/dev-test/ImageArtist/src/lib/AssetManager/../../resources/Fonts/Gotham-Light.ttf
This is the full code
use Treinetic\ImageArtist\lib\PolygonShape;
use Treinetic\ImageArtist\lib\Text\TextBox;
use Treinetic\ImageArtist\lib\Text\Color;
use Treinetic\ImageArtist\lib\Text\Font;
use Treinetic\ImageArtist\lib\Overlays\Overlay;
use Treinetic\ImageArtist\lib\Image;
require('../vendor/autoload.php');
$main_image = new Image("ranks/main-image.png");
$textBox = new TextBox(720,40);
$textBox->setColor(new Color(0,0,0, 125));
$textBox->setFont(Font::getFont('./Gotham-Light.ttf'));
$textBox->setSize(42);
$textBox->setMargin(0);
$textBox->setText($_GET["name"]);
$main_image->setTextBox($textBox, 40, 620);
$main_image->save("./newImage.png",IMAGETYPE_PNG);
But the font specified is not used by Imagick. If i try to create an image from den command line via
convert -font /var/www/vhosts/example.com/dev-test/ImageArtist/src/lib/AssetManager/../../resources/Fonts/Gotham-Light.ttf -pointsize 72 label:Test test.gif
And... The Font is used on command line created image :/ The font file is reachable and readable via php but not used via Imagick ....
Does anyone has an idea why php imagick can't use my font but convert -font can?
The script is running on PHP-FPM 7.0.23 on an dedicated root server with nginx as an RPS.
Hope you can help me out.. It really drives me crazy :)
Thanks
Stanlay
SOLVED
Found out that $im->newPseudoImage($width, $height, "pango:" . $text ); cause the issue. Switching to $im->newPseudoImage($width, $height, "caption:" . $text ); and everything works fine.

PHP - "FPDF error: Not a PNG file", but the image is

I'm currently running into a very odd issue with fpdf. I found a similar question with no answer: not a PNG file in FPDF. I have an image uploaded through a browser to my file server, and then pulled into a fpdf report. When this image is a png, I get the error: "FPDF error: Not a PNG file". I don't get any errors when the uploaded image is a jpg. This issue seemingly appeared overnight a few weeks ago.
Even stranger, it's only happening with new png's being uploaded. There was a png in a report that was generating fine. When I downloaded that png from the system and re-uploaded it, the errors appeared again.
Here are some of the steps I've taken while attempting to troubleshoot the issue:
I've made sure the image is actually a png (through its properties).
Nothing has changed with the way I've been saving the images, but here's the code:
$original = $time."_".$name."_o.".$extension;
$thumbnail = $time."_".$name."_t.".$extension;
include('SimpleImage.php');
$image = new SimpleImage();
$image->load($_FILES['file']['tmp_name']);
$image->save($A_path."images/".$original);
$image->resizeToHeight(200);
$image->save($A_path."images/thumbs/".$thumbnail);
$photo = "images/".$original;
$thumb = "images/thumbs/".$thumbnail;
I've checked to see if their were any changes to the PNG format or FPDF updates, with no luck.
I've converted a jpg that works into a png through gimp.
Converting a png to a jpg through gimp and then uploading the jpg to the system does not generate any errors.
WORKAROUND- I've gone ahead and converted png's to jpg's on save, rather than re-encoding the image. Thanks for the help.
Fixed it by changing the picture format manually to JPG and then repeating the process.
The error message indicates that there is something wrong with the first eight bytes of the file (the "png signature").
Use "od -c | head -1" to inspect the first 16 bytes. Every PNG file
begins with these:
211 P N G \r \n 032 \n \0 \0 \0 \r I H D R
If you prefer, use "xxd file.png | head -1" and expect to see this:
0000000: 8950 4e47 0d0a 1a0a 0000 000d 4948 4452 .PNG........IHDR
These 16 bytes are the PNG signature and the length and name of the first chunk. The first 8 bytes are the format
name, plus newlines (linefeeds) and carriage returns that are designed
to detect various transmission errors. The next 8 bytes are the beginning
of the IHDR chunk, which must be length=13 expressed as a 4-byte integer, and the name="IHDR".
See the PNG specification for details.
Check the depth of the image. FPDF supports 24bit depth (i'm not sure about 32bit depth), neither does it support alpha channel.
I'd try to reencode to png with ImageMagick (or paint.net under windows).
convert input.png -depth 8 +matte output.png
I found a crud solution that works for me but this will take little more space on your host. But you can determine which extension worked and delete the rest However its worth it.
First take the file contents and convert them to base64_encode.
Create an array of the file formats you want the file to be in "png","jpg","jpeg" and decode the base64 image looping through the file extensions. This recreates the image with three file extensions in your folder.
Use the
try{
}catch (Exception $e) {
}
to loop trough and find which image extension works and use it.
Here is my full code
$base64 = base64_encode(file_get_contents("full/domain/path/to/image"));
$f_ex = array('.png', '.jpg', '.jpeg'); //array of extensions to recreate
$path = "path/to/new/images"; //this folder will have there images.
$i = 0;
$end = 3;
while ($i < $end) {
$data = base64_decode($base64); //decode the image file from base64
$filename = "unique_but_memorable_filename(eg invoice id)" . $f_ex[$i]; //$f_ex loops through the file extensions
file_put_contents($path . $filename, $data); //we save our new images to the path above
$i++;
}
Inside your FPDF where your image is set, we loop through the images we recreated and see which one works and stop there
try {
$filename = "remember_unique_but_memorable_filename(eg invoice id)" . $f_ex[0];
$logo = "your domail.com where image was stored" . '/' . $path . $filename;
$pdf->Image($logo, 10, 17, 100, 100);
//Put your code here to delete the other image formats.
} catch (Exception $e) {
try {
$filename = "remember_unique_but_memorable_filename(eg invoice id)" . $f_ex[1];
$logo = "your domail.com where image was stored" . '/' . $path . $filename;
$pdf->Image($logo, 10, 17, 100, 100);
//Put your code here to delete the other image formats.
} catch (Exception $e) {
try {
$filename = "remember_unique_but_memorable_filename(eg invoice id)" . $f_ex[2];
$logo = "your domail.com where image was stored" . '/' . $path . $filename;
$pdf->Image($logo, 10, 17, 100, 100);
//Put your code here to delete the other image formats.
} catch (Exception $e) {
//if all the three formats fail, lets see the error
echo 'Message: ' . $e->getMessage();
}
}
}

circularize an image with imagick

Trying to take a rectangular photo, crop it into a square region, and then mask it into a circular with a transparent background.
//$dims is an array with the width, height, x, y of the region in the rectangular image (whose path on disk is $tempfile)
$circle = new \Imagick();
$circle->newImage($dims['w'], $dims['h'], 'none');
$circle->setimageformat('png');
$circle->setimagematte(true);
$draw = new \ImagickDraw();
$draw->setfillcolor('#ffffff');
$draw->circle($dims['w']/2, $dims['h']/2, $dims['w']/2, $dims['w']);
$circle->drawimage($draw);
$imagick = new \Imagick();
$imagick->readImage($tempfile);
$imagick->setImageFormat( "png" );
$imagick->setimagematte(true);
$imagick->cropimage($dims['w'], $dims['h'], $dims['x'], $dims['y']);
$imagick->compositeimage($circle, \Imagick::COMPOSITE_DSTIN, 0, 0);
$imagick->writeImage($tempfile);
$imagick->destroy();
The result is the rectangular image, uncropped and without being circularized. What am I doing wrong?
Example image:
Example input for $dims = {"x":253,"y":0,"x2":438.5,"y2":185.5,"w":185.5,"h":185.5}
Rough expected output:
Image i'm getting looks roughly like the input image.
For those with an older version of Imagick (setimagematte does not exist in version lower than 6.2.9), I came up with an easy solution. The thing here is to copy opacity from the mask to the original image.
Original Image:
Mask:
Result:
The code:
$base = new Imagick('original.jpg');
$mask = new Imagick('mask.png');
$base->compositeImage($mask, Imagick::COMPOSITE_COPYOPACITY, 0, 0);
$base->writeImage('result.png');
You could use an Imagick black circle as mask but I though it wasn't perfect so I used my own.
Of course you will certainly have to resize / crop your images but that's another story.
Hope this helps.
J.
This works for me:
<?php
//$dims is an array with the width, height, x, y of the region in the rectangular image (whose path on disk is $tempfile)
$tempfile = 'VDSlU.jpg';
$outfile = 'blah.png';
$circle = new Imagick();
$circle->newImage(185.5, 185.5, 'none');
$circle->setimageformat('png');
$circle->setimagematte(true);
$draw = new ImagickDraw();
$draw->setfillcolor('#ffffff');
$draw->circle(185.5/2, 185.5/2, 185.5/2, 185.5);
$circle->drawimage($draw);
$imagick = new Imagick();
$imagick->readImage($tempfile);
$imagick->setImageFormat( "png" );
$imagick->setimagematte(true);
$imagick->cropimage(185.5, 185.5, 253, 0);
$imagick->compositeimage($circle, Imagick::COMPOSITE_DSTIN, 0, 0);
$imagick->writeImage($outfile);
$imagick->destroy();
?>
<img src="blah.png">
I always try to keep the code simple until I get it working and then add all the variables etc. That could be the problem or there could be a problem with your version of Imagick.
It's namespaced
Still do not know what it means! - I am getting a bit behind with php as I do not use it very much these days.
There's also another workaround that I suggest here :
// create an imagick object of your image
$image = new \Imagick('/absolute/path/to/your/image');
// crop square your image from its center (100px witdh/height in my example)
$image->cropThumbnailImage(100, 100);
// then round the corners (0.5x the width and height)
$image->roundCorners(50, 50);
// force the png format for transparency
$image->setImageFormat("png");
// write the new image
$image->writeImage('/absolute/path/to/your/new/image');
// done!
Many thanks to all previous answers and contributors that lead me to this code!
Feel free to test/comment my solution!
I stumbled upon this as I was searching for a similar solution for Ruby on Rails, notice that this Stackoverflow question uses vignette instead which seems to be a much simpler way to solve the problem.
I used vignette to solve my problem with rounded images in Ruby on Rails using Dragonfly.

Categories