Behzad Blog
Behzad Blog

Reputation: 1

decrease size of pictures in php

I need a php class or API that can decrease size of a picture without decreasing the scale or quality of the picture, like the “fileminimizer suite” software.

Upvotes: 0

Views: 717

Answers (1)

LSerni
LSerni

Reputation: 57453

Decreasing the file size of a picture isn't at all trivial.

The JPEG format is lossy and already quite optimized; you can do something with it, but it requires adjustments that may be considered "quality loss". Basically, you want to reduce high frequency noise. ImageMagick (and its PHP wrapper) may be a good choice. You can also drop some redundant or useless APPn blocks (Exif metadata and such) and shave a couple of kilobytes at most.

EDIT: for example the site you mention employs a similar technique. I checked just two images:

http://www.image-compressor.com/images/gallery/429724_36675180.jpg
http://www.image-compressor.com/images/gallery/429724_36675180_bestquality.jpg

Estimate of quality factor for the second image is equivalent to 87, and the original file contains 60 Kb of APP data which is useless for viewing. I say this, because using the jpegtran utility (part of JPEG tools)

jpegtran -copy none -outfile 429724_36675180_stripped.jpg 429724_36675180.jpg

gives me a file which is pixel-identical, and size decreased from 221624 to 166123 bytes. This is what I meant with "Exif and other APPn chunk stripping". 'Without decreasing quality' in this case means 'no pixel gets touched in any way, period', and yet jpegtran yields a 60 Kb saving.

If touching some pixels in an almost imperceptible way, no one is likely to notice is acceptable, then much more becomes possible.

My wild-ass guess based on a quick and dirty frequency analysis is that www.image-compressor software uses a "perceived quality metric" based on local variance and PSNR, and zeroes on a "good" recompression factor through either bisection or Newton convergence (quality factors below 60 aren't really useful, and between 60 and 99 the quality vs size curve is suitable for Newton-Raphson).

This result is what I was talking about when I said, 'requires adjustments that may be considered "quality loss"'. If this is acceptable you can for example give the command,

djpeg -dct float < 429724_36675180.jpg \
| cjpeg -optimize -dct float -maxmemory 4096 -quality 89 \
  -outfile 429724_36675180_remade.jpg

and lo and behold, with APPn data stripped and quality dialed down to 89, we come out with a file that is 35820 bytes in size against the www.image-compressor one which is 36082 (your mileage may vary due to quirks in the implementation of JPEG library). The distortions introduced from djpeg/cjpeg are on par with those of image-compressor (PSNR 45.4279 versus 45.8822 as reported by ImageMagick).

So to sum it up, if you want to have something similar to www-im-comp, you can install JPEG tools (probably something like /apt-get install jpegtools/ - check your Linux distro; but the tools exist on Windows and MacOS also) run

shell_exec("djpeg -dct float < $INPUTFILE "
          ."| cjpeg -optimize -dct float -maxmemory 4096 -quality $QUALITY "
          ."-outfile $OUTPUTFILE");

and then use Imagick to verify the difference between INPUT and OUTPUT:

http://www.php.net/manual/en/imagick.compareimagechannels.php

(or you can use ImageMagick's compare utility through shell_exec). I expect you to obtain very similar results to those of image-compressor.

===

For the PNG format you can do a bit better with several utilities which reorder information and get you a pixel-by-pixel identical, but smaller, image. Savings may range from nothing to 15% depending on how sub-optimal the image is. Look at PNGCRUSH, PngOPT, PNG-Gauntlet, etc. .

These utilities can also reduce the palette size removing unneeded colors.

Then you can remove some visually irrelevant sources of high entropy in the image itself, thereby increasing compressibility. Several "spot remover" algorhythms may be used, and again ImageMagick is your friend. I did that with a C processing core in a PHP extension once, but parameter tuning was a real gold-plated bitch, and I expect ImageMagick to be too. Trim too little and you gain nothing - trim too much and you're left with a flat, posterized image.

I'm afraid there is no general-purpose, already-made class to do this, though. You will need to pilot ImageMagick's APIs or shell_exec some utility like pngout.

EDIT: for completeness, to GIF much the same concepts apply as for PNG. Actually, you're almost always better off using PNG than GIF, except for really small files where GIF87a offers less overhead. But if such byte-picking is needed, then I'd look into "spriting" my webpage graphics: the HTTP and roundtrip overhead that can be obtained this way will trump whatever can conceivably be gained by using small GIF87a files.

Upvotes: 1

Related Questions