Image filesize after resizing with Imagick and Gmagick - php

While resizing an image, I have noticed that Imagick and Gmagick produce images with different filesize on HDD with the same options:
$image = new Imagick("c.jpg");
$image->thumbnailImage(260,195);
$image->writeImage("c_imagick.jpg");
outputs an Image with 88kb
$image = new Gmagick("c.jpg");
$image->thumbnailImage(260,195);
$image->writeImage("c_gmagick.jpg");
outputs an Image with 15kb
Does someone have any idea, why the difference is so huge?

Try setting the image compression settings prior to resizing.
$image->setImageCompression(Imagick::COMPRESSION_JPEG);
$image->setImageCompressionQuality(80);
Additionally, check the size of the resulting image. Comments in the PHP documentation lead me to believe that the automatic fit portion of thumbnailImage does not work as you would expect in IMagick.
From PHP Docs:
The fit functionality of thumbnailImage doesn't work as one would anticipate. Instead, use >this to make a thumbnail that has max of 200x82:
// Create thumbnail max of 200x82
$width=$im->getImageWidth();
if ($width > 200) { $im->thumbnailImage(200,null,0); }
$height=$im->getImageHeight();
if ($height > 82) { $im->thumbnailImage(null,82,0); }

Related

PHP Resize Image to a specified size

Is it possible to resize an image in PHP, to a specified size in Kilobytes, with large images?
Example: IMGonline.com.ua
You can absolutely resize to a certain size using resize so if you know a certain number of pixels will be within that size you could set a pixel size. I've used 100x100 for reference.
$resize = new ResizeImage('image.png');
$resize->resizeTo(100, 100, 'exact');
$resize->saveImage('/resized/image.png');
Using this theory you could take the same approach and if an image is already that size or below you could resize it.
if ($file_size < 5000) {
$resize = new ResizeImage('image.png');
$resize->resizeTo(100, 100, 'exact');
$resize->saveImage('/resized/image.png');
} else {
// Error
}
So you could run it like this
// Upload Image
// Resize image
$resize = new ResizeImage('image.png');
$resize->resizeTo(100, 100, 'exact');
$resize->saveImage('/resized/image.png');
// Save image
// Open saved image
// Check image size
// Confirm or resize progressively smaller.
Hopefully the resize property is of some use. You've provided no code in your question but I think the best approach would be to check the size and save if it's fine then if not you would resize again and check again. Obviously you'd have to do this until it was at the correct size so execution time could take longer. I can't think of a direct way to compress the image with a php function unless you compressed the images instead of resizing them.

PHP Imagick ReadImage WriteImage different quality

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

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.

PHP Imagick - convert image to greyscale (very bad result)

I was doing some image editing with PHP, since GD provides less functionalities, I switched to Imagick.
One of the processes is to greyscale images. Everything went fine (locally on Windows 7, Imagick 2.2.1-dev 6.5.8-7 Q16) till I uploaded the script to my web hosting server (Linux, Imagick 3.0.1, 6.2.8, 2010-10-20, Q16).
I'v tried to change the quality, but it didn't improve anything.
$img->setImageCompression(imagick::COMPRESSION_JPEG);
$img->setImageCompressionQuality(100);
Here is the results from GD, Imagick and Photoshop
I believe something's wrong with version 3.0.1. Can someone please confirm that?
Q1: Is there an alternative way to convert an image to greyscale with Imagick?
Q2: Is it possible to convert a GD resource to Imagick? So I can use imagefilter($img, IMG_FILTER_GRAYSCALE); to get the correct result and then output with Imagick.
ps: For Q2, you might suggest me to just use GD to process the image. But the problem is that imagejpeg() cannot save images with resolution preserved. and that is actually the reason I switched to Imagick.
This is my preferred way to make a B&W photo in php/imagick: $im = $im->fxImage('intensity');
That applies a function to the image, where intensity is equal to 0.299*red+0.587*green+0.114*blue.
That formula is based on how our eyes are more sensitive to different colours, and as such the difference between that and a "flat" grayscale image really is night and day.
More details here:
http://php.net/manual/en/imagick.fximage.php
http://www.imagemagick.org/script/fx.php
function ImagickToGD($imagick){
$tmpfile = tmpfile();
$imagick->writeImage($tmpfile);
return imagecreatefromstring(file_get_contents($tmpfile));
}
Note that this function does not do any cleanup (except the temp file, which PHP cleans automatically).
So, for example, your code should look like:
$img = new Imagick();
// ...
$gd = ImagickToGD($img);
unset($img); // destroy imagick
imagefilter($gd, IMG_FILTER_GRAYSCALE);
imagejpeg($gd, $target_name, 100);
imagedestroy($gd);
Also, I did not understand the part about "preserving resolution". There is nothing in these operations relating to resolution. My guess is you meant compression? If you want full quality (ie, no compression) simply use 100 as compression value (as I did).
This results in maintaining the existing quality, since opening an image of 70% quality and saving it back with 70% quality actually decreases the final quality by 49% (70% of 70%).
function GDToImagickTo($gd){
$tmpfile = tmpfile();
imagepng($tmpfile); // Png is our best image deal:
// lossless compression, transparency etc..
$imagick = new Imagick()
$imagick->readImage($tmpfile);
return $imagick;
}
Refer this website and check out the image Magick operators found here www.rubblewebs.co.uk/imagemagick/
Also go with www.fmwconcepts.com/imagemagick/ you will find some examples out here...
You can use the image class what you prefer and then use the method readImageBlob to send it to the imagick http://www.php.net/manual/en/imagick.readimageblob.php

Get orientation of iphone created image email attachment

When I use the GD image library the orientation EXIF data is missing, is it possible to get the data straight from the raw data string before I use imagecreatefromstring() to make the jpg file? The orientation data is there because when I look at the email in gmail in chrome it shows the proper orientation, but as soon as I download the image that data is lost. I also tried using exif_thumbnail to see if I could figure out the orientation from that but the thumbnail is missing too.
If I download the attachment through chrome, windows image viewer displays it as landscape, but if I upload it to flickr it is displayed portrait, what is flickr using to determine orientation?
EDIT: solved it
createimagefromstring strips out a ton of meta data from the image file, but using fwrite creates the file verbatim from the data string, so I did this
$filename = 'pic.jpg';
$r = fopen($filename,'x');
fwrite($r,$raw_data); //$raw_data is the data string of the image
fclose($r);
and voila all the exif data was there! Stupid GD library! >:(
If you're really using the GD library like you say you are, you can leverage getimagesize() to check for the image's dimensions. If the width is greater than the height of the image, you can safely assume that it was taken in landscape mode.
$params = getimagesize($image);
$width = $params[0];
$height = $params[1];
if ($width > $height) {
$mode = "landscape";
} else if ($width < $height) {
$mode = "portrait";
}

Categories