【转】PNG 压缩程序简述

来源:互联网 发布:博客优化 编辑:程序博客网 时间:2024/06/09 22:03

Does the type of image matter when you’re compressing it to PNG? Does it affect performance? Size? This week’s article looks into these questions to find out how each of the PNG compressors performs on three different types of images: an icon, a photo, and random noise.

The PNG compression test has grown since last week’s article to include more compressor options on the cameron314 test:

  • BitmapData.encode (PNGEncoderOptions.fastCompression=false)
  • BitmapData.encode (PNGEncoderOptions.fastCompression=true)
  • Bloddy Crypto (filter=none)
  • Bloddy Crypto (filter=sub)
  • Bloddy Crypto (filter=up)
  • Bloddy Crypto (filter=average)
  • Bloddy Crypto (filter=paeth)
  • cameron314 (compression level=uncompressed)
  • cameron314 (compression level=fast)
  • cameron314 (compression level=normal)
  • cameron314 (compression level=good)
  • as3corelib

And three image types:

  • The Flash Pro CS5 icon from previous PNG test articles
  • A random photo with the same width and height as the icon
  • Noise generated by BitmapData.noise with the same width and height as the icon

Here’s the code for the test app:

package{import com.adobe.images.PNGEncoder;import flash.utils.ByteArray;import by.blooddy.crypto.image.PNG24Encoder;import by.blooddy.crypto.image.PNGFilter;import flash.display.PNGEncoderOptions;import flash.geom.Rectangle;import flash.utils.getTimer;import flash.display.Bitmap;import flash.display.BitmapData;import flash.display.Loader;import flash.display.LoaderInfo;import flash.display.Sprite;import flash.events.Event;import flash.net.URLRequest;import flash.text.TextField; public class CompressPerformance extends Sprite{private var tf:TextField = new TextField(); public function CompressPerformance(){tf.width = stage.stageWidth;tf.height = stage.stageHeight;addChild(tf); load("Adobe_Flash_Professional_CS5_icon.png", onIconLoaded);} private function onIconLoaded(ev:Event): void{var bmd:BitmapData = ((ev.target as LoaderInfo).content as Bitmap).bitmapData;test("Icon", bmd); load("10082934002.jpg", onPhotoLoaded);} private function onPhotoLoaded(ev:Event): void{var bmd:BitmapData = ((ev.target as LoaderInfo).content as Bitmap).bitmapData;test("Photo", bmd); load("Adobe_Flash_Professional_CS5_icon.png", onIconLoadedAgain);} private function onIconLoadedAgain(ev:Event): void{var bmd:BitmapData = ((ev.target as LoaderInfo).content as Bitmap).bitmapData;bmd.noise(Math.random()*int.MAX_VALUE); test("Noise", bmd);} private function row(...cols): void{tf.appendText(cols.join(",")+"\n");} private function load(url:String, callback:Function): void{var loader:Loader = new Loader();loader.contentLoaderInfo.addEventListener(Event.COMPLETE, callback);loader.load(new URLRequest(url));} private function test(title:String, bmd:BitmapData): void{var beforeTime:int;var afterTime:int;var time:int;var rect:Rectangle = new Rectangle(0, 0, bmd.width, bmd.height);var bytes:ByteArray; row(title);row("Compressor,Time,Size");bmd.getPixel(0, 0); beforeTime = getTimer();bytes = bmd.encode(rect, new PNGEncoderOptions(false));afterTime = getTimer();time = afterTime - beforeTime;row("BitmapData.encode (fast=false)", time, bytes.length); beforeTime = getTimer();bytes = bmd.encode(rect, new PNGEncoderOptions(true));afterTime = getTimer();time = afterTime - beforeTime;row("BitmapData.encode (fast=true)", time, bytes.length); beforeTime = getTimer();bytes = PNG24Encoder.encode(bmd, PNGFilter.NONE);afterTime = getTimer();time = afterTime - beforeTime;row("Bloddy (filter=none)", time, bytes.length); beforeTime = getTimer();bytes = PNG24Encoder.encode(bmd, PNGFilter.SUB);afterTime = getTimer();time = afterTime - beforeTime;row("Bloddy (filter=sub)", time, bytes.length); beforeTime = getTimer();bytes = PNG24Encoder.encode(bmd, PNGFilter.UP);afterTime = getTimer();time = afterTime - beforeTime;row("Bloddy (filter=up)", time, bytes.length); beforeTime = getTimer();bytes = PNG24Encoder.encode(bmd, PNGFilter.AVERAGE);afterTime = getTimer();time = afterTime - beforeTime;row("Bloddy (filter=average)", time, bytes.length); beforeTime = getTimer();bytes = PNG24Encoder.encode(bmd, PNGFilter.PAETH);afterTime = getTimer();time = afterTime - beforeTime;row("Bloddy (filter=paeth)", time, bytes.length); PNGEncoder2.level = CompressionLevel.UNCOMPRESSED;beforeTime = getTimer();bytes = PNGEncoder2.encode(bmd);afterTime = getTimer();time = afterTime - beforeTime;row("cameron314 (uncompressed)", time, bytes.length); PNGEncoder2.level = CompressionLevel.FAST;beforeTime = getTimer();bytes = PNGEncoder2.encode(bmd);afterTime = getTimer();time = afterTime - beforeTime;row("cameron314 (fast)", time, bytes.length); PNGEncoder2.level = CompressionLevel.NORMAL;beforeTime = getTimer();bytes = PNGEncoder2.encode(bmd);afterTime = getTimer();time = afterTime - beforeTime;row("cameron314 (normal)", time, bytes.length); PNGEncoder2.level = CompressionLevel.GOOD;beforeTime = getTimer();bytes = PNGEncoder2.encode(bmd);afterTime = getTimer();time = afterTime - beforeTime;row("cameron314 (good)", time, bytes.length); beforeTime = getTimer();bytes = PNGEncoder.encode(bmd);afterTime = getTimer();time = afterTime - beforeTime;row("as3corelib", time, bytes.length); row();}}}

Launch the app
Download the app

I ran this test in the following environment:

  • Flex SDK (MXMLC) 4.6.0.23201, compiling in release mode (no debugging or verbose stack traces)
  • Release version of Flash Player 11.6.602.171
  • 2.3 Ghz Intel Core i7
  • Mac OS X 10.8.2

And here are the results I got:

ICON
COMPRESSORTIMESIZEBitmapData.encode (fast=false)63171969BitmapData.encode (fast=true)37138700Bloddy (filter=none)13461149Bloddy (filter=sub)46270242Bloddy (filter=up)86873608Bloddy (filter=average)46075916Bloddy (filter=paeth)58272217cameron314 (uncompressed)964474569cameron314 (fast)87606841cameron314 (normal)69115264cameron314 (good)149105291as3corelib22461092

PNG Compression Performance (icon)
PNG Compression Size (icon)
PNG Compression Size (icon, small only)

PHOTO
COMPRESSORTIMESIZEBitmapData.encode (fast=false)14111581023BitmapData.encode (fast=true)1232598418Bloddy (filter=none)1952604346Bloddy (filter=sub)11291646064Bloddy (filter=up)6741641705Bloddy (filter=average)8221669681Bloddy (filter=paeth)14111584675cameron314 (uncompressed)493356208cameron314 (fast)661761713cameron314 (normal)1231735160cameron314 (good)6551606533as3corelib4662833906

PNG Compression Performance (photo)
PNG Compression Size (photo)
PNG Compression Size (photo, small only)

NOISE
COMPRESSORTIMESIZEBitmapData.encode (fast=false)1913356458BitmapData.encode (fast=true)2253875539Bloddy (filter=none)3273837742Bloddy (filter=sub)3493838815Bloddy (filter=up)3543838150Bloddy (filter=average)3573839126Bloddy (filter=paeth)4133837929cameron314 (uncompressed)664474569cameron314 (fast)1033833976cameron314 (normal)2003827015cameron314 (good)12603827065as3corelib5373837685

PNG Compression Performance (noise)
PNG Compression Size (noise)
PNG Compression Size (noise, small only)

CONCLUSION

The results for the icon are, of course, the same as in last week’s article. For the photo, bloddy crypto continues to be fastest when using no filter, cameron314 gets slower as you turn up the compression level, and as3corelib is somewhere in the middle. On the other hand, file size no longer has huge outliers. Instead, there’s a sort of two-tier system that makes it easy to choose a compressor: simply pick the fastest one from the small file size tier. In this case that compressor is cameron314 (fast).

For random noise, performance-wise the picture is quite different compared to the icon. BitmapData.encode with fastCompression off is actually faster than when it’s on. Bloddy crypto and cameron314 take longer as you turn up the filter and compression level, respectively, and as3corelib is just generally slow. File size is almost identical regardless of compressor except for uncompressed PNGs from cameron314, so you might as well choose the second-fastest: cameron314 (fast).

The icon image from the previous articles is a good example of an image that should be compressed as a PNG. Random noise and photos are poor choices for PNG regardless of the compressor, as you can see from the 10x increase in file size with the photo. If you’re going to compress any of these with PNG, your compressor choice should change to cameron314 (fast) since it seems to be very close to the fastest at both while producing among the smallest PNG files. That’s quite a turnaround for cameron314 (fast) because it’s file sizes are so bad in the icon test that it’s not worth using.

In summary, for images that lend themselves to PNG, use bloddy crypto with no filter. For all other images, use cameron314 with the “fast” compression level.

Spot a bug? Have a question or suggestion? Post a comment!