php imagick won't save PNG compressed but shows compressed in browser - php

I have the following code in PHP to take the screenshot of first page of the PDF.
$name = getcwd()."\\testfile";
$img = new imagick();
$img->setResolution(200,200);
$img->readImage($name.'.pdf[0]');
$img->setImageResolution(100,100);
$img->resampleImage(100,100,imagick::FILTER_LANCZOS,1);
$img->setImageCompression(\Imagick::COMPRESSION_ZIP );
$img->setImageCompressionQuality('0');
$img->setImageFormat('png8');
$img->writeImage($name.".png");
header("Content-type : image/png");
echo $img;
This code produces the PNG of 62kb only in the Google Chrome's Resource monitor tab. But the image which is written by Imagick() is above 114kb. Just to make sure image isn't compressed and or any other issues i have used a online service called TinyPNG and they compressed the image shrinking it to exactly 62kb i get in browser...
What could be wrong in this code? Also i am using PNG8 format because thats more efficient.
Best
Ahsan

I think this is caused by your writeImage statement. If you write a PNG image without specifying png8: specifically in the filename your image will not be stored in that format. In essence setImageFormat will only affect when you retrieve the image as a string (echo $img).
If you do the following:
$img->writeImage ('png8:' . $name . ".png");
it should be stored as a png8. You can verify this with identify -verbose and checking the Depth / Channel Depth.

These are the default compression methods used for the following common image formats:
PNG: Imagick::COMPRESSION_ZIP
JPEG: Imagick::COMPRESSION_JPEG
GIF: Imagick::COMPRESSION_LZW

Related

Convert PNG to black and white GIF with gd or imagemagick

I am generating barcodes in a PHP webpage with the Picqer library, which can output to PNG, JPG, SVG or HTML.
On-screen they look great and are readable with the wand, but when printing they are apparently dithered, preventing them from being read.
If I save the generated PNG image to a file and use Photoshop to convert it to GIF (no transparency, 0 dither, 2 colors), then re-open the image with the browser and print, I get a perfect, crisp image with no dithering.
So I tried converting directly to GIF with the gd library in PHP:
// Create a GD image from the PNG generated by getBarcode. ($result = the Picqer\Barcode\BarcodeGeneratorPNG::getBarcodeoutput
$gd_image = imagecreatefromstring($result);
// Convert to palette image with no dithering and 2 colors
imagetruecolortopalette($gd_image, false, 2);
// Output the image as a GIF:
header('Content-Type: image/gif');
imagegif($gd_image, false); // Output directly to browser
However, this generates an exact duplicate of the PNG - when printed, it's dithered.
How can I fix this in order to generate a 2-color GIF with no dithering and no transparency? I think this would solve the output clarity issue. If there's a better way, I'm open to it.
I'm also open to using other image processing libraries like Imagick if that would be a better choice.
Thanks!
UPDATE #1:
OK so I have made some progress: I switched to Image Magick and performed the following conversion from the original PNG file to a 2-color, non-dithered GIF, which renders a beautifully clean and crisp black and white image:
$im = new Imagick();
$im->readImageBlob($result); // convert string to Imagic
// Quantize:
$im->quantizeImage(2, imagick::COLORSPACE_GRAY, 1, false, false);
// Output image as GIF
$im->setIMageFormat('gif');
header("Content-Type: image/gif");
echo $im->getImageBlob();
PROBLEM: this method seems to be very resource-intensive. When I request a page filled with barcode images (20-30 qty) several of the images appear as "broken", generating http 500 errors "end of script output before headers".
I assume this means the Imagick routines are using hefty memory/cpu resources, so when the browser requests lots of images at once, PHP is reaching the limits of its resources.
UPDATE #2:
Performance tests reveal that Imagick is the bottleneck:
Generating 133 barcodes on a single HTML page, in PNG format:
Average time to execute getBarcode() function: 733uS
Average time to echo result: 13uS
Generating same 133 barcodes using the Imagick conversion listed above:
getBarcode() - avg 1mS
Conversion to GIF: avg 0.76 S
So I wonder why Imagick is so slow... ? These are tiny files, on the order of 200 bytes (PNG).
SAMPLE INPUT PNG IMAGE:

PHP - Possible to take a base64 encoded pdf data string and compress it?

So I have an XML file that has a base64 encoded data string for a pdf file, which just has an image taken from an iPad.
This pdf file can be excessively large, as much as 14MB with dimensions of 57"x38".
These images are taken from an iPad through a DocuSign session, thus I have no way at the moment of controlling their size or format before they get to my php listener script.
However, my script cannot work with such large files as my CRM's API file size max is 10MB, and I need a way of reducing the file size before I can upload it through my CRM's API.
Now if it was just a jpg, it would be ok as there are plenty of ways to reduce file size in PHP, but it is a PDF. I have found plenty of PHP extensions for making PDFs, but I haven't found any for reading a PDF and extracting an image from it.
So is there a way to extract the image from the PDF through PHP, or perhaps compress the pdf file?
UPDATE
I didn't think about the possibility of converting a pdf into a jpg, which apparently is easier to do with imagick. Having my server admin install it and I will see if I can make it work with my script.
UPDATE 2
So I was able to get imagick working and locally I am able to convert pdf files into jpg, and reduce file size dramatically.
However, I am running into an issue using it with my application. I get the following error from my CRM's API:
Failed to parse XML-RPC request: Invalid byte 1 of 1-byte UTF-8 sequence.
So the process is the following:
XML file has a base64 encoded data stream of the pdf file.
I decode this data
I then convert with imagick and reduce file size
I base64 encode and prep for upload
CODE
$imageBlob = base64_decode((string)$pdf->PDFBytes);
$imagick.$x = new Imagick();
$imagick.$x->readImageBlob($imageBlob);
$imagick.$x->setImageFormat('jpeg');
$imagick.$x->setImageCompressionQuality(60);
$imagick.$x->adaptiveResizeImage(1024,768,true);
$imageBlob = $imagick.$x->getImageBlob();
$PDFdata[] = base64_encode($imageBlob);
I can test the date by using the proper header and I can see the new jpeg fine, so I assume the data is properly formatted.
What I am missing?
Ok, so I figured it out.
Imagick was the way to go, and my use of it was good. I just goofed up on the file name because I wasn't using a proper dynamic variable name. Code should have looked like this:
CODE
$imageBlob = base64_decode((string)$pdf->PDFBytes);
${'imagick'.$x} = new Imagick();
${'imagick'.$x}->readImageBlob($imageBlob);
${'imagick'.$x}->setImageFormat('jpeg');
${'imagick'.$x}->setImageCompressionQuality(60);
${'imagick'.$x}->adaptiveResizeImage(1024,768,true);
$imageBlob = ${'imagick'.$x}->getImageBlob();
$PDFdata[] = base64_encode($imageBlob);
$PDFfile[] = $FormCustomField . $x . '.jpg';
So the error I was getting was because of an invalid file name, because the $x variable in the previous code was getting junk values. Now everything works fine.

How to convert webP image format to normal ? php

I have an ios and android application. sometime the users upload webP image to my server. the problem is ios can't show this image when it's downloaded from my server.
so I want to check within my php code. if the image is webP format . then i will convert it to png format.
How could i do that using php?
It's late but just for the sake of it. It can be done using PHP only. Without any external tool.
Quoted from PHP.net documentation:
<?php
// Load the WebP file
$im = imagecreatefromwebp('./example.webp');
// Convert it to a jpeg file with 100% quality
imagejpeg($im, './example.jpeg', 100);
imagedestroy($im);
?>
So I assume you can use imagepng() instead of imagejpeg that is in the example.
Using libwebp:
( I assume $file is an absolute path and libwebp is installed)
$regex="/^(.*)(\.webp)$/";
if(preg_match($regex, $file)){
$out=preg_replace($regex, "${1}.png", $file);
exec("dwebp $file -o $out");
}
Didn't test, but should work...

php iphone/IOS6 upload rotation issue: what is best way to save rotated image

Using the safari mobile browser with IOS6, the file upload function gives users the option to snap a photo. Unfortunately, upon snapping the photo, while the photo thumb shows up properly in the browser, when you upload to a server, the file is rotated 90 degrees. This appears to be due to the exif data that the iphone sets. I have code that fixes the orientation by rotating the image when serving. However, I suspect it would be better to save the rotated, properly oriented, image so I no longer have to worry about orientation. Many of my other photos do not even have exif data and i don't want to mess with it if I can avoid it.
Can anyone suggest code to save the image so it is properly oriented?
Here is the code that rotates the image. The following code will display the properly oriented image, however, what I want to do is save it so I can then serve it whenever I want without worrying about orientation.
Also I would like to replace impagejpeg call in code below so that any code works for gifs as well as jpgs.
Thanks for suggestions/code!
PHP
//Here is sample image after uploaded to server and moved to a directory
$target = "pics/779_pic.jpg";
$source = imagecreatefromstring(file_get_contents($target));
$exif = exif_read_data($target);
if(!empty($exif['Orientation'])) {
switch($exif['Orientation']) {
case 8:
$image = imagerotate($source,90,0);
//echo 'It is 8';
break;
case 3:
$image = imagerotate($source,180,0);
//echo 'It is 3';
break;
case 6:
$image = imagerotate($source,-90,0);
//echo 'It is 6';
break;
}
}
// $image now contains a resource with the image oriented correctly
//This is where I want to save resource properly oriented instead of display.
header('Content-type: image/jpg');
imagejpeg($image);
?>
Only JPEG or TIFF files can carry EXIF metadata, so there's no need to worry about handling GIFs (or PNGs, for that matter) with your code.
From page 9 of what I believe is the official specification:
Compressed files are recorded as JPEG (ISO/IEC 10918-1) with application marker segments (APP1 and APP2) inserted. Uncompressed files are recorded in TIFF Rev. 6.0 format.
http://www.cipa.jp/english/hyoujunka/kikaku/pdf/DC-008-2010_E.pdf
To save your image just use the same function imagejpeg and the next parameter to save the image, something like:
imagejpeg($image, $target, 100);
In this case you don't need the specify the header, because you are not showing nothing.
Reference:
http://sg3.php.net/manual/en/function.imagejpeg.php

Using a transparent PNG as a clip mask

Is it possible to take this image:
And apply this mask:
And turn it into this:
Using either GD or Imagick? I know it's possible to mask an image using shapes but I'm not sure how to go on about doing it with a pre-created alphatransparent image. :s
Using Imagick and ImageMagick version > 6 (I don't know if it will work on older versions):
// Set image path
$path = '/path/to/your/images/';
// Create new objects from png's
$dude = new Imagick($path . 'dude.png');
$mask = new Imagick($path . 'dudemask.png');
// IMPORTANT! Must activate the opacity channel
// See: http://www.php.net/manual/en/function.imagick-setimagematte.php
$dude->setImageMatte(1);
// Create composite of two images using DSTIN
// See: http://www.imagemagick.org/Usage/compose/#dstin
$dude->compositeImage($mask, Imagick::COMPOSITE_DSTIN, 0, 0);
// Write image to a file.
$dude->writeImage($path . 'newimage.png');
// And/or output image directly to browser
header("Content-Type: image/png");
echo $dude;
I think you are looking for imagealphablending. I use it for watermarks, and I believe it will do the effect you are looking for.
Great work with (ImageMagick) NOT GD .. I see the tags of this question is GD!!
Here is a GD version at this link:
PHP GD Use one image to mask another image, including transparency

Categories