Posted on Tuesday 5 December 2006
I’ve modified Tinic Uro’s PNGEnc class to make it a bit faster and get lower file sizes.
The first modification is to the non-transparent encoding algorithm which I have modified to use getPixels instead of getPixel. The reason Tinic was using getPixel is that getPixels returns pixels in the ARGB format and PNGs use RGBA, and thus getPixel was used to make the transition at a pixel level. Since in the case of non-transparent bitmaps all the alpha bytes are set to 0xff, there is also the possibility of simply getting a single scan line, deleting the first byte, and appending 0xff at the end (wrapping). This gives a modest speed boost on the order of 1 ms per 2000 pixels, so that the total process takes between 20% and 30% less time depending on data. The new bottleneck then is the CRC algorithm in writeChunk so if you have experience with that please do take a stab at it.
The second modification is the addition of support for scanline filter type “sub”. Although PNG is lossless there are a certain amount (4) of scanline lossless filters you can apply before compression which may enhance the compressibility of the data. The “sub” filter is the simplest one and encodes bytes as the difference between adjacent pixels on a scan line. This can improve the compression ratio if the image has gradients in it, but can decrease it if the image has unicolored shapes and sharp edges. As a sample data source I used a google maps street map and satellite view of Montreal at 800×500. In the case of the street map the data went from 62 to 80 KBs. In the case of the satellite view it went from 756 to 585 KBs. As for the encoding time, it’s about twice as much as the no filter mode. I am almost certain however that it is possible to rewrite the function so that no pixel level manipulation will be done, instead doing the “calculation” using the difference blend mode beforehand (please take a stab at it if you know what I’m talking about). I may take on the 3 other scanline filters if it’s something people are interested.



Great! Thanks, really cool update.
First and foremost - good job on the improvements! As somebody who’s currently involved on a image processing heavy Flex application, I can appreciate how these little tweaks make all the difference. What I’m seeing now though is a fragmentation of the source. It’d be great if somebody (hint) took the lead on putting this up on RIAForge.
Nice one Patrick ;)
The PNG compressor (along with the JPEG one) is one of the main things which is pushing me over to AS3. I’m still pretty happy with AS2 for most things, but this is something I could really use in a couple places (where I am currently using custom compression, which is much slower, and much worse compression ratio)
What happens when you make these ‘int’ instead of ‘uint’?
This may be a stupid Q, but will this work in the Flash 9 Alpha, or is it just for FlexBuilder!??
Excellent work on the AFMPHP 1.9,
If anyone is interest, I have made a small simple example on how to connect using only actionscript 3 on my blog at http://flashorbit.com/?page_id=53 hope it is of any help!
Prompted by your suggestion, we’re looking into this, for Fauxto, right now. Duly appreciated.
[…] Looks like the PNGEncoder in AS3 coreLib might get a major speed-boost. Mike Chambers posted about a new build of the library taking place soon. One of the standing feature requests is to include Patrick Mineault’s changes to the PNGEncoder. This is swell news, as Patricks’s changes make for a massive performance boost. […]
Great plugin may be… Or not?
Most PNG viewers ignore the CRC value. If you are sending this to a server you can re-encode it on the server side. Combining these two enhancements improves performance by a factor of 10.
V-nice!
Has anyone had any luck saving out a PNG with transparency? I have been unsuccessfull with this new and improved version regardless of the settings used for the type argument, though the old vs worked fine.
casey -
Also, I have been playing with the Meta Object parm…but see no meta data in the resultant image.
My implementation is as follows:
if you want transparent bitmaps.
when printing a sprite onto a BitmapData Object
first you need to set that BitmapData to transparent
bitmapData.fillRect(new Rectangle(0,0,bitmapData.width,bitmapData.height),0×00000000);
its default init is non transparent white
ı didnt find this program
thank you.
thank you