PNGSizeExtractor

ActionScript, Air, Flash, Flex Add comments

I was trying to read the dimensions of some very large image files today when I bumped into the Flash Player 10 limitations regarding maximum image sizes. (More info about this is available here.) Since an image file that is too big will not be shown correctly, there is no use in uploading and using it. I wanted to provide detailed feedback about the image dimensions and how they exceeded the allowed sizes, but that was not possible unfortunately since the width and height properties of the loaded image would remain 0. (I posted a question on StackOverflow about this issue here.)

The JPGSizeExtractor class by Antti Kupila enables you to read the width and height of a JPG by reading the image's bytecode. Since we also need to support PNG files, I thought I'd create a simple PNGSizeExtractor myself.

Here's the code:

Actionscript:
  1. package com.herrodius.utils {
  2.    
  3.     import flash.utils.ByteArray;
  4.  
  5.     /**
  6.      * Reads the width and height from a PNG image.
  7.      *
  8.      * http://en.wikipedia.org/wiki/Portable_Network_Graphics
  9.      * http://www.libpng.org/pub/png/spec/1.2/png-1.2-pdg.html
  10.      *
  11.      * @author Christophe Herreman
  12.      */
  13.     public class PNGSizeExtractor {
  14.  
  15.         private static const SIGNATURE_BYTES:Array = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A];
  16.  
  17.         private static const CHUNK_TYPE_SIZE:uint = 4;
  18.  
  19.         // --------------------------------------------------------------------
  20.         //
  21.         // Constructor
  22.         //
  23.         // --------------------------------------------------------------------
  24.  
  25.         public function PNGSizeExtractor(byteArray:ByteArray) {
  26.             decode(byteArray);
  27.         }
  28.  
  29.         // --------------------------------------------------------------------
  30.         //
  31.         // Public Properties
  32.         //
  33.         // --------------------------------------------------------------------
  34.  
  35.         // ----------------------------
  36.         // width
  37.         // ----------------------------
  38.  
  39.         private var _width:uint;
  40.  
  41.         public function get width():uint {
  42.             return _width;
  43.         }
  44.  
  45.         // ----------------------------
  46.         // height
  47.         // ----------------------------
  48.  
  49.         private var _height:uint;
  50.  
  51.         public function get height():uint {
  52.             return _height;
  53.         }
  54.  
  55.         // --------------------------------------------------------------------
  56.         //
  57.         // Private Methods
  58.         //
  59.         // --------------------------------------------------------------------
  60.  
  61.         private function decode(data:ByteArray):void {
  62.             readSignature(data);
  63.             readIHDR(data);
  64.         }
  65.  
  66.         private function readSignature(data:ByteArray):void {
  67.             for (var i:uint = 0; i<SIGNATURE_BYTES.length; i++) {
  68.                 if (data.readUnsignedByte() != SIGNATURE_BYTES[i]) {
  69.                     throw new Error("File is not a PNG file.");
  70.                 }
  71.             }
  72.         }
  73.  
  74.         private function readIHDR(data:ByteArray):void {
  75.             var size:uint = data.readUnsignedInt();
  76.             var type:String = data.readUTFBytes(CHUNK_TYPE_SIZE);
  77.             _width = data.readUnsignedInt();
  78.             _height = data.readUnsignedInt();
  79.         }
  80.        
  81.     }
  82. }

And here's how to use it. (byteArray is the data of the loaded PNG):

Actionscript:
  1. var pngDecoder:PNGSizeExtractor = new PNGSizeExtractor(byteArray);
  2. trace(pngDecoder.width, pngDecoder.height);

And here is a small sample application that loads the file locally:

Actionscript:
  1. <?xml version="1.0"?>
  2. <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" horizontalAlign="left">
  3.  
  4.     <mx:Script>
  5.         <![CDATA[
  6.         import com.herrodius.utils.PNGSizeExtractor;
  7.  
  8.         import mx.controls.Alert;
  9.  
  10.         private var _fileReference:FileReference;
  11.  
  12.         private function browseButton_clickHandler(event:MouseEvent):void {
  13.             _fileReference = new FileReference();
  14.             _fileReference.addEventListener(Event.SELECT, fileReference_selectHandler);
  15.             _fileReference.addEventListener(Event.COMPLETE, fileReference_completeHandler);
  16.             _fileReference.browse();
  17.         }
  18.  
  19.         private function fileReference_selectHandler(event:Event):void {
  20.             _fileReference.load();
  21.         }
  22.  
  23.         private function fileReference_completeHandler(event:Event):void {
  24.             fileNameTextInput.text = _fileReference.name;
  25.  
  26.             try {
  27.                 var pngDecoder:PNGSizeExtractor = new PNGSizeExtractor(_fileReference.data);
  28.                 textArea.text = "Width: " + pngDecoder.width + "\n";
  29.                 textArea.text += "Height: " + pngDecoder.height;
  30.             } catch (e:Error) {
  31.                 Alert.show(e.message, "Error decoding image");
  32.             }
  33.         }
  34.  
  35.         ]]>
  36.     </mx:Script>
  37.  
  38.     <mx:Label text="Browse for a PNG file." fontWeight="bold"/>
  39.  
  40.     <mx:HBox width="100%">
  41.         <mx:TextInput id="fileNameTextInput" width="100%" editable="false"/>
  42.         <mx:Button id="browseButton" label="..." click="browseButton_clickHandler(event)"/>
  43.     </mx:HBox>
  44.  
  45.     <mx:TextArea id="textArea" width="100%" height="100%"/>
  46.  
  47. </mx:Application>


Add to Bloglines - Digg This! - del.icio.us - Stumble It! - Twit This! - Technorati links - Share on Facebook - Feedburner
 

3 Responses to “PNGSizeExtractor”

  1. jpwrunyan Says:

    This is great. Thank you. You have saved me the trouble of having to learn .png format myself.

  2. Eli Tehutzil Says:

    I am misplaced, I get an error using it

    var my_loader:Loader = new Loader();
    my_loader.load(new URLRequest(“image.png”));
    my_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageLoaded);
    var pngDecoder:PNGSizeExtractor = new PNGSizeExtractor(my_loader);
    trace(pngDecoder.width, pngDecoder.height);

    I thank you so much in advance, I´ve been all around the blog. Blessings!!!

  3. inghamc Says:

    I don’t see a license statement about your source – is it public domain, BSD, …?

    Thanks!

Leave a Reply

WP Theme & Icons by N.Design Studio
Entries RSS Comments RSS Log in