PHP Imagick ReadImage WriteImage different quality - php

I am scaling images with php-imagick. The image I want to scale is a jpg without exif data (1600x1200+0+0 8-bit sRGB). The quality of the scaled image is lower than the original. By quality I mean that the image has more artifacts (visible quality). So I made a test where I simply read an image and write it under another filename without chaning anything else:
$im = new Imagick();
$im->readImage(realpath('./a.jpg')); // image quality checked with $im->getImageCompressionQuality() 50
$im->writeImage('./b.jpg'); // image quality checked with $im->getImageCompressionQuality() 50
The result is:
Image a.jpg > 254kb (original image)
Image b.jpg > 183kb
So by simply writing the image to a new file, php-imagick changes something that I don't want.
Can anyone explain to me:
What happens to the generated image?
How can I write the image without changing any other stuff except scaling?
Thanks

Related

Increment file size after convert image with PHP imagick

I have a function to convert jpg image to tiff image, keep the original size and quality. I used Imagick class to do that. Convert success but image size has increment too much. My original image was taken from iPhone with 2.6Mb after converting, it increment to 36.6Mb.
I had tried to use some PHP image manipulation libraries like Intervention/image but nothing change.
I also test convert original jpg to new jpg and file size increment from 2.6Mb to 3.3Mb.
My code here:
$image = new \Imagick('image_path_file.jpg);
$image->setImageFormat("tiff");
$image->writeImage("path_new_file.tiff");
Have any options that can help Imagick not increment file size too much?
Thanks you 🙇‍♂️

PDF to PNG from iMagick is very bad quality

I am converting PDF files to PNG files using imagick in PHP.
For this example I have a PDF file with only 5 lines of text on the first (and only) page. This PDF is generated from a Word file (it's not scanned in).
My code to convert the file looks like this:
$im = new Imagick();
$im->setResolution(200,200);
$im->readImage($_SERVER['DOCUMENT_ROOT'] . '/codeigniter/vrm/documents/uploaded_documents/2020/04/buddy_voor_lennert-01042020130414.pdf[0]');
$im->scaleImage(500,500);
$im->setImageFormat('png');
$im->writeImage($_SERVER['DOCUMENT_ROOT'] . '/codeigniter/vrm/documents/images/thumbnails/lennert.png');
$im->clear();
$im->destroy();
After this, the png is created, but the quality of the text is horrible, it becomes unreadable, see the screenshot i attached below.
How do I retain the same quality? I want to generate a thumbnail and a normal size image. So the thumbnail can be of lower quality, but the normal size image should be at least of a readable quality.
I've tried putting the resolution down to 50x50 or tried using the following methods, to no avail:
$im->setImageCompressionQuality(0); (also to 100)
$im->resizeImage(500, 500, Imagick::FILTER_LANCZOS, 0, true);

PHP GD method imagecopy larger the image filesize than the origin image

In my work , I use PHP GD lib function imagecopy to add watermark to images , but find the generated image is larger than the origin image before , is there any way optimize filesize , except the jpegoptim to trim the exif metadata.
The test code on the github : https://github.com/zeanwork/Watermark , u can test with exmaple , the to.jpg filesize is too much larger than from.jpg and watermark.png filesize
file mediainfo
But I dont want image with watermark is to much larger than the origin file , In my test , the to.jpg filesize sometime 4 times of origin image
any best methods to reduce the filesize ?
It's the image quality, but again, I don't think it is possible to have identical JPEG image size, even if you just copy one jpg image to the other one. Watermark does save the image with 100 quality, which is the biggest. I guess your original image has no such big quality, thus the difference in the file size.
Just have a look at 204 line of the Watermark class:
# Save image
$functionTarget($this->imgSource, $imgTarget, 100);
You'll have to hardcode it in order to change the quality.

Convert PDF (with transparency *and* CMYK) to jpg

I need to generate jpg images from PDF files (first page only). The PDF files are user generated, so they can contain anything. I'm currently using the following code:
// Load PDF.
$i = new Imagick;
// Create thumbnail of first page of PDF.
$i->setResolution(150, 150);
$i->loadImage("test.pdf[0]");
$i->thumbnailImage(640, 480, true);
// Remove transparency, fill transparent areas with white rather than black.
$i->setImageBackgroundColor("white");
$i->setImageAlphaChannel(11); // Imagick::ALPHACHANNEL_REMOVE
$i->mergeImageLayers(Imagick::LAYERMETHOD_FLATTEN);
// Output.
$i->writeImage("test.jpg");
This works as expected in that transparency becomes white instead of black. However, I've run into problems with some generated jpg images, so I ran jpeginfo on them:
$ jpeginfo -c test.jpg
test.jpg 960 x 480 32bit JFIF N 9481 Unsupported color conversion request [ERROR]
It turns out that some source PDFs actually use CMYK, and apparently are not converted to RGB when saved as jpg. So I changed my code to the following (addition of a single line) to explicitly convert to RGB:
// Load PDF.
$i = new Imagick;
// Create thumbnail of first page of PDF.
$i->setResolution(150, 150);
$i->loadImage("test.pdf[0]");
$i->thumbnailImage(640, 480, true);
// Remove transparency, fill transparent areas with white rather than black.
$i->setImageBackgroundColor("white");
$i->setImageAlphaChannel(11); // Imagick::ALPHACHANNEL_REMOVE
$i->mergeImageLayers(Imagick::LAYERMETHOD_FLATTEN);
// Convert to RGB to prevent creating a jpg with CMYK colors.
$i->setImageColorspace(Imagick::COLORSPACE_RGB);
// Output.
$i->writeImage("test.jpg");
This creates a jpeg with an RGB color profile, all right. However, for some obscure reason it results in an image with a black background again. In other words: the transparency problem is back. Why does Imagick do this, and more importantly, what's the solution to both the transparency problem and the CMYK problem?
The correct function to use is transformImageColorspace not setImageColorspace. transformImageColorspace is used for existing images, setImageColorspace is for new images e.g. svg drawing..
I've added it to the manual and it should show up soon.

Optimize PNG when resizing with GD/PHP - How to determine color palette?

I had troubles resizing a PNG and maintaining small file sizes. Solution found here.
When resizing the PNG, however, I ran into problems regarding image quality. As far as I could see, GD uses indexed 8-bit-color palette which distorts text and colors get lost, see:
Original Image
Resized Image with solution given above
Resized Image with a tweak²
²The idea for the tweak I found here in stackoverflow: Create truecolor-image, resize it, and copy it to a new image, so the palette is determined based on the resampled result and the image quality is better as you can see in the image above.
// create new image
$newImageTmp = imagecreatetruecolor($newwidth,$newheight);
// we create a temporary truecolor image
// do the image resizing by copying from the original into $newImageTmp image
imagecopyresampled($newImageTmp,$src,0,0,0,0,$newwidth,$newheight,$width,$height);
// create output image
$newImage = imagecreate($newwidth,$newheight);
// copy resized truecolor image onto index-color image
imagecopy($newImage,$newImageTmp,0,0,0,0,$newwidth,$newheight);
// write image to buffer and save in variable
ob_start(); // stdout --> buffer
imagepng($newImage,NULL,6);
$newImageToSave = ob_get_contents(); // store stdout in $newImageToSave
ob_end_clean(); // clear buffer
// remove images from php buffer
imagedestroy($src);
imagedestroy($newImageTmp);
imagedestroy($newImage);
Problem: None of both results are satisfactory.
I am quite sure that there must be a way to 1. determine the color palette, and 2. maintain most of the image's colors, so that 3. the PNG looks similar to the original and has an acceptable file size.
Now, I only see going for JPG instead of PNG. But if you know a solution, it would greatly be appreciated if you let me/us know.
Thank you!
All you need is to replace
$newImage = imagecreate($newwidth,$newheight);
With
$newImage = imagecreatetruecolor($newwidth, $newheight);
Output $maxImgWidth = 200;
PHP's fork of GD doesn't have usable palette generation, so you only get PNG32 with vanialla libpng compression.
For small PNG8 with palette use pngquant, e.g. http://pngquant.org/php.html
And then compress it further with advpng or zopfli-png.

Categories