AS3 PNG encoder: faster, better

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.

Download it here.


17 Comments for 'AS3 PNG encoder: faster, better'

  1.  
    Paulius Uza
    12/5/2006 | 9:38 pm
     

    Great! Thanks, really cool update.

  2.  
    12/6/2006 | 1:35 am
     

    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.

  3.  
    12/6/2006 | 11:23 am
     

    Nice one Patrick ;)

  4.  
    12/6/2006 | 12:14 pm
     

    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)

  5.  
    Anonymous
    12/6/2006 | 7:11 pm
     

    What happens when you make these ‘int’ instead of ‘uint’?

            var r1:uint;
            var g1:uint;
            var b1:uint;
            var a1:uint;
    
            var r2:uint;
            var g2:uint;
            var b2:uint;
            var a2:uint;
    
            var r3:uint;
            var g3:uint;
            var b3:uint;
            var a3:uint;
    
  6.  
    12/16/2006 | 4:31 pm
     

    This may be a stupid Q, but will this work in the Flash 9 Alpha, or is it just for FlexBuilder!??

  7.  
    12/20/2006 | 1:24 am
     

    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!

  8.  
    1/6/2007 | 12:42 am
     

    Prompted by your suggestion, we’re looking into this, for Fauxto, right now. Duly appreciated.

  9.  
    3/7/2007 | 4:32 pm
     

    […] 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. […]

  10.  
    8/30/2007 | 8:46 am
     

    Great plugin may be… Or not?

  11.  
    Mike
    11/20/2007 | 12:42 pm
     

    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.

  12.  
    casey
    11/26/2007 | 10:24 am
     

    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.

  13.  
    casey
    11/26/2007 | 10:28 am
     

    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:

        var metaObject:Object = {a: "foo", b: "bar"};
        var _PNG:ByteArray = PNGEnc.encode(bitMD, 0, metaObject);
    
  14.  
    roy
    11/27/2007 | 2:04 pm
     

    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

  15.  
    12/7/2007 | 8:29 am
     

    ı didnt find this program

  16.  
    2/17/2008 | 2:44 pm
     

    thank you.

  17.  
    2/27/2008 | 12:55 pm
     

    thank you

Leave a comment




Your e-mail address is never displayed. If you run into issues with SpamKarma blocking you, email me at $patrick->5etdemi(com)


RSS feed for comments on this post | TrackBack URI