Image file size differences between Imagemagick and GD library - php

I have been doing some tests and found out that Imagemagick creates larger file sized images compared to GD library.
I have tried using thumbnailImage method and also resizeImage method (with different filters) of Imagemagick for creating an image of max dimension 1024x680 jpeg with JPEG compression and quality 80 and at 72 pixels per inch resolution and am also using stripImage method to remove unneeded meta data. The file size created by Imagemagick is always in the range of 700KB to 800KB depending upon various filters. On the other hand GD library produces an image of size 1024x680 which is only 41KB in size.
Can anyone please explain the difference in file sizes. I opened up the 2 files in Photo shop and checked to see any differences but could not find any (DPI, color profile, 8 bit channel etc), but still cant explain the difference in file sizes.

$srgbPath = "pathTosrgbColorProfile";
$srgb = file_get_contents($srgbPath);
$image->profileImage('icc', $srgb);
$image->stripImage();
$image->setImageResolution(72,72);
$image->setImageUnits(1);
$image->setInterlaceScheme(Imagick::INTERLACE_JPEG);
$image->setImageCompression(imagick::COMPRESSION_JPEG);
$image->setImageCompressionQuality(80);
$image->setColorspace(imagick::COLORSPACE_SRGB);
$image->resizeImage($thumb_width,$thumb_nheight,imagick::FILTER_CATROM,1);
$image->writeImage($destination);
The size went down by 40KB giving an output of 711KB which is still pretty big. The Hi-res original file I am testing on is a jpeg of size 3008x2000 (4.2MB).
Edit:
I think I figured it out, the method setCompression() does it for the Object and not the image, instead I used setImageCompression() and setImageCompressionQuality() and now the size has reduced to 100KB.. All good now!

Maybe the Quality settings of GD and ImageMagick aren't easily comparable, 80% in one does not mean the same as 80% in the other. I found the following note in an article form Smashing Magazine:
It turns out that JPEG quality scales are not defined in a specification or standard, and they are not uniform across encoders. A quality of 60 in Photoshop might be the same as a quality of 40 in one program, quality B+ in another and quality fantastico in a third. In my tests, I found that Photoshop’s 60 is closest to -quality 82 in ImageMagick.
So you may pay more attention on quality when comparing the different result files. Maybe the colors differ or the gd image has more artifacts.

The differnce seems rather large; when I did some tests a couple of years ago the file size of IM was about 5x the size of GD.
It would be interesting to see your actual code used.
I am at work at the moment but have a photo resized to 592 x 592 and the filesize is 50.3KB I know it is not the same size as yours but it was saved at quality 100
You can run this and see what IM says about the output files:
convert image -verbose -identify
EDIT:
You must be doing something wrong I have just run a test and the results are below - For some reason the thumbnail size is the same as the resize size! Maybe a bug.
Original file size: 4700 x 3178 2.31MB
-resize dimensions = 1021 x 680 186kb
-thumbnail dimensions = 1021 x 680 186kb
GD dimensions = 1024 x 682 100kb
$original = 'IMG_4979_1.CR2';
// Convert to jpg as GD will not work with CR2 files
exec("convert $original image.jpg");
$image = "image.jpg";
exec("convert $image -resize 1024x680 output1.jpg");
exec("convert $image -thumbnail 1024x680 -strip output2.jpg");
// Set the path to the image to resize
$input_image = 'image.jpg';
// Get the size of the original image into an array
$size = getimagesize( $input_image );
// Set the new width of the image
$thumb_width = "1024";
// Calculate the height of the new image to keep the aspect ratio
$thumb_height = ( int )(( $thumb_width/$size[0] )*$size[1] );
// Create a new true color image in the memory
$thumbnail = ImageCreateTrueColor( $thumb_width, $thumb_height );
// Create a new image from file
$src_img = ImageCreateFromJPEG( $input_image );
// Create the resized image
ImageCopyResampled( $thumbnail, $src_img, 0, 0, 0, 0, $thumb_width, $thumb_height, $size[0], $size[1] );
// Save the image as resized.jpg
ImageJPEG( $thumbnail, "output3.jpg" );
// Clear the memory of the tempory image
ImageDestroy( $thumbnail );

Related

How to make thumbnails using Imagick::resizeImage appear sharper - PHP?

I am using Imagick::resizeImage to create a thumbnail PNG image of each page of a pdf file. However, the image I am getting back is really blurry. How can I make it a little sharper? Any pointers would be really appreciated.
I have tried adjusting the 'blur' paramter of Imagick::resizeImage between 0.1 - 1, without success.
$pdfPage = '1Mpublic.pdf[0]';
$im = new imagick($pdfPage);
$im->setImageFormat('png');
// Resize thumbnail image
$imgHeight = $im -> getImageHeight();
$imgWidth = $im -> getImageWidth();
$desiredWidth = 200;
$desiredHeight = resizedImageHeight($imgWidth, $imgHeight, $desiredWidth);
$im -> setResolution(1500, 1500);
$im -> resizeImage($desiredWidth, $desiredHeight, imagick::STYLE_NORMAL, 0.1);
/* Resize image */
function resizedImageHeight($imgWidth, $imgHeight, $desiredImgWidth){
$quoient = $imgWidth/$imgHeight;
$height = $desiredImgWidth/$quoient;
return $height;
}
original pdf link:
https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4905263/pdf/ksgt-06-04-1091539.pdf
Rather than rendering and then resizing the raster, it might be better to render the PDF to the right number of pixels in the first place. It'll be faster, and you can be sure that the amount of sharpness is correct for the content.
For example:
$ time convert -density 50 ksgt-06-04-1091539.pdf[0] x2.png
real 0m0.325s
user 0m0.299s
sys 0m0.024s
Makes:
The -density 50 makes a page about the same number of pixels across as your sample, 425.
In imagick you could do it like this (as #fmw42's excellent answer already says):
#!/usr/bin/env php
<?php
$target_width = 400;
# get natural size, calculate density we need for target width
$im = new imagick();
$im->pingImage($argv[1]);
$geo = $im->getImageGeometry();
$natural_width = $geo['width'];
$density = 72.0 * $target_width / $natural_width;
# load at correct resolution for target_width
$im = new imagick();
$im->setResolution($density, $density);
$im->readImage($argv[1]);
# and write back
$im->writeImage($argv[2]);
Doing both the ping and the read is a little slow in imagick, unfortunately:
$ time ./pdfthumb.php ksgt-06-04-1091539.pdf x.png
real 0m2.773s
user 0m2.737s
sys 0m0.036s
It's not imagick, but vipsthumbnail can do the ping and read in one operation:
$ time vipsthumbnail ksgt-06-04-1091539.pdf -s 400x -o x2.png
real 0m0.064s
user 0m0.064s
sys 0m0.011s
It might be worth considering if speed is important. libvips has a php binding so you can call it directly, but if you do that you'll run into awful licensing problems because it uses the GPL library poppler for PDF rendering, sigh. ImageMagick uses GhostScript and shells out to that for the same reason.
Unfortunately, I do not know Imagick that well. But in Imagemagick command line, I would do what is sometimes called supersampling. That is use a large density to read the PDF, then resize down by the inverse scale factor.
For example, nominal density is 72 dpi. I would read the input PDF at 4*72=288 dpi. Then after rasterizing, I would resize by 1/4=25% or for a larger result by something larger than 25%, say 50%. Here is your first page done both ways:
convert -density 288 ksgt-06-04-1091539.pdf[0] -resize 25% result1.png
convert -density 288 ksgt-06-04-1091539.pdf[0] -resize 50% result2.png
In Imagick, the key is something like:
$imagick = new Imagick();
$imagick->setImageResolution(288, 288);
$imagick->readImage('myfile.pdf');

php copy image increases file size

I am using php to resize and crop images. However the cropped image file is greater than ( much greater in some cases) than the original file. I even tried without cropping (copying the original image) but the resulting size is more than the original image.
$ImageName = '/IMAGES/testImage.jpg';
//Download the Image File
$base_url = 'https://image.jimcdn.com/app/cms/image/transf/none/path/sa6549607c78f5c11/image/ia62ed3191fcc424f/version/1457278719/athens-european-best-destinations.jpg';
$image_size = getimagesize($base_url);
$image_width = $image_size[0];
$image_height = $image_size[1];
$src_image = imagecreatefromjpeg($base_url);
//Copy Image Object To File
imagejpeg($src_image, $ImageName, 100);
Technically, the quality rate of the conversion is not derivable from
the jpeg data, it just tells the converter which tradeoff to make
between size and quality.
Some converters store it in the EXIF data of the JPEG header though,
so if that is still present you can use it with exif_read_data on it,
and see if the compression information is returned.
Source
try to reduce quality and set 80 for example. Quality will be still ok, it's even higher then default quality which should be 75 if you set nothing.
So, put like this:
imagejpeg($src_image, $ImageName, 80);
I think you can try this ImageCopyResampled in this case if you want to keep every pixel like original image. It's slower but better than imagejpeg.
And about quality of image using imagejpeg the quaility property refers to how much jpeg compression you want to apply to the saved or created output image.
0% quality means maximum compression and 100% quality means minimum compression.
The more compression you apply, the smaller the output filesize will be relative to the original uncompressed filesize.
Just exclude the image quality parameter:
imagejpeg($src_image, $ImageName);
GD will automatically create a smaller image for you

My php image server using Imagick produces much larger png8 files after cropping / scaling down

I'm trying to set up a simple PHP image server to allow me to add just large file for each of my images and then scale and crop them as needed. For my test file I start with a png8 exported via "save for web" from illustrator of size 2400 x 1200, which has a filesize of 21.6KB.
When I use Imagick's cropThumbnailImage function to reduce it to 600 x 600 the resulting file is 62.1KB (three times the size for a substantially smaller image). A 600 x 600 crop of the same image saved from illustrator clocks in at about 8.2KB. I can accept a modest file size increase for the added convenience, but an ~8x increase is just too much.
When saving the file I make sure to force the output to png8 so it doesn't default to a lossless png format, but other than that I'm clueless as to how to resolve it.
Here is my processing code:
//create working image
$image = new Imagick( $this->orig_file );
// Set Compression
$image->setImageCompressionQuality( 9 );
//scale image to height
$image->cropThumbnailImage ( $this->w, $this->h );
// strip extra data
$image->stripImage();
// save file
$image->writeImage( 'png8:'.$this->output_file );
Here are my test files:
Original Full scale image outputted by illustrator.
Cropped 600 x 600 image generated by imagick.
[EDIT: As per Mark's suggestion below I added the following changes]
// replacing cropThumbnailImage with:
$image->resizeImage(0, $this->h, imagick::FILTER_TRIANGLE, 1);
// crop
$start = ($image->getImageWidth() / 2) - ($this->w / 2);
$image->cropimage($this->w, $this->h, $start, 0);
// reduce colors to 20
$image->quantizeImage($this->q, 1, 0, true, false); // using 20 as $this->q
The end result goes from 62.1KB to 50.4KB, better but still over double the size of the fullsized image, and many times larger that the illustrator save for web version at that size.
600x600 image reduced to 20 colors and resized not thumbnailed
Your original image has 33 colours and weighs in at 22kB.
If you resize like this (albeit at the command line):
convert jabba.png -resize 600x600 -strip png8:result.png
the output file will be 6.6kB.
If you resize like I suggested with -scale:
convert jabba.png -scale 600x600 -strip png8:result.png
the output file will be 5.0kB.
If you retain -quality 9 in there, you will end up with > 25kB.

image resizing in PHP

While i was doing some image processing, i found out that GD and Imagick in PHP does not resize image to color pixel identical level, which in most cases, were not needed.
Now in case, i need a image from whatever dimension to scale to 256*256
To make sure the TEST results are consistent, i used a 256*256 image and resize it to it's own size.
what i've attempted:
imagecopyresized($new, $img, 0, 0, $x, 0, $width, $height, $w, $h); //256 , 256
and
$compression_type = imagick::COMPRESSION_NO;
$images_ima = new Imagick($image_path); //$image_path = path to image...
$images_ima->setImageCompression($compression_type);
$images_ima->setImageCompressionQuality(100);
$images_ima->sampleImage($X_SIZE,$Y_SIZE); // 256 ,256
$images_ima->writeImages($dest_path, true); //destination path
none of them worked, if i compare the output with the original image, it will look something like this:
it looks like the functions i've used are resampling the image since the variations in the RGB value between both image are small
i can achieve pixel to pixel identical resizing from 256*256 to 256*256 in photoshop, OSX preview, and even Pixelformer.
i was wondering how can that be done i PHP?
Since your image format (jpeg - assumed from 100 quality setting) is a lossy format you won't get a lossless throughput this way as you're recompressing the image.
You should try to detect image dimensions and use the original image if the dimensions are already correct.
When you don't change the dimensions (original dimensions = dimensions after resizing) in Photoshop or OSX preview they won't recompress the image, that's why you won't see any change.

How to resize image size

How to reduce image sizes in Linux. I have used ImageMagick for this. But it is not working well for gif images. I have used it as:
To resize image
exec("convert $original -resize " . $width . 'x' . $height . ' ' . $destination);
To reduce image size
exec("convert $original -quality 80% $new_img");
Please let me know if you have any way to reduce image size. This code works well for jpg, but not works well for gif images.
Appreciate your help.
Quoting from the Imagemagick manual:
-quality value
JPEG/MIFF/PNG compression level.
That means that using the quality level will only work on the aforementioned image types, which do not include GIF.
For GIF's your easiest option is to use the -colors command to reduce the number of colors used in your image. The quality of the result depends very much on what your initial image contains, I have seen cases where a reduction from 256 to 16 colors did not cause significant quality loss, and others where a reduction to 128 colors rendered the image unusable. You'll have to experiment.
A last remark: you could transform your GIF to PNG format and use the -quality command on the resulting image. Quality on PNG's however is a bit of a misnomer:
For the MNG and PNG image formats, the quality value sets the zlib compression
level (quality / 10) and filter-type (quality % 10). The default PNG "quality"
is 75, which means compression level 7 with adaptive PNG filtering, unless the
image has a color map, in which case it means compression level 7 with no PNG
filtering.
So don't be surprised if the size reduction is less on PNG's than on JPG', it only improves compression of the lossless PNG image.
To reduce GIF images in size, you can try converting them to PNG or to reduce the color depth. The color depth is the number of colors used in the image. Less colors means a smaller image size.
So you can use GD
http://ua.php.net/manual/en/function.imagecopyresampled.php
<
?php
// The file
$filename = 'test.jpg';
// Set a maximum height and width
$width = 200;
$height = 200;
// Content type
header('Content-Type: image/jpeg');
// Get new dimensions
list($width_orig, $height_orig) = getimagesize($filename);
$ratio_orig = $width_orig/$height_orig;
if ($width/$height > $ratio_orig) {
$width = $height*$ratio_orig;
} else {
$height = $width/$ratio_orig;
}
// Resample
$image_p = imagecreatetruecolor($width, $height);
$image = imagecreatefromjpeg($filename);
imagecopyresampled($image_p, $image, 0, 0, 0, 0, $width, $height, $width_orig, $height_orig);
// Output
imagejpeg($image_p, null, 100);
?>
The following works well for JPEG images and likely works for other image formats. The given density (300) is pretty high and suitable for keeping text readable, so adjust for your situation.
convert input-file -density 300 -quality 50% output-file

Categories