hackedteam/rcs-console

View on GitHub
src/com/WindowsBitmap/WinBmpImg.as

Summary

Maintainability
Test Coverage
// ==================================================================
// Module:        WinBmpHdr.as
//
// Description:    Windows Bitmap Header class
//                 - image pixel data
//
// Author(s):    C.T. Yeung     (cty)
//
// History:
// 14Feb09        first completion of decoder                        cty
// 21Feb09        fully functional as Windows paint bmp format.
//                - no compression and no 16bpp.                    cty
//
// Copyright (c) 2009 C.T.Yeung

// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:

// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ==================================================================
package com.WindowsBitmap
{
    import flash.utils.ByteArray;
    import flash.display.BitmapData;
    import mx.controls.Alert;
    
    public class WinBmpImg
    {
        public static const RGB_QUAD:int=4;
        public static const MASK_WIDTH:int=8;
        
        public var bytes:ByteArray;
        public var bitmapData:BitmapData;
        private var fileHdr:WinBmpFileHdr;
        private var bmpHdr:WinBmpHdr;
        private var bmpPal:WinBmpPal;
        
/////////////////////////////////////////////////////////////////////
// Initialization         
        
        public function WinBmpImg()
        {
        
        }

        public function empty():void
        {
            if (bitmapData){
                bitmapData.dispose();
                bitmapData = null;
            }
        }
        
        public function isEmpty():Boolean
        {
            if (bitmapData)
                return false;
            return true;
        }
        
/////////////////////////////////////////////////////////////////////
// properties

        /**
         * Windows bitmap data is 32 bit bound per row.
         * Add padding as needed. 
         * @param pixelWidth
         * @param bitDepth
         * @return byte width, pixel row including padding
         */
        public static function byteWidth(    pixelWidth:uint, // image width in pixels
                                            bitDepth:int)     // bit depth
                                            :uint             // number of bytes (include padding)
        {
            var retVal:int;
            var r:Number = (pixelWidth * bitDepth) % 32;
            if (r) {
                retVal = pixelWidth * bitDepth / 32;
                retVal += 1;
                retVal *= 4;
                return retVal;
            }
            else
                return pixelWidth * bitDepth / 8;
        }
        
/////////////////////////////////////////////////////////////////////
// public

        /**
         * This class needs references to file header, bitmap header, palette 
         * @param fileHdr
         * @param bmpHdr
         * @param bmpPal
         */
        public function setRef(fileHdr:WinBmpFileHdr,
                               bmpHdr:WinBmpHdr,
                               bmpPal:WinBmpPal):void
        {
            this.fileHdr = fileHdr;
            this.bmpHdr = bmpHdr;
            this.bmpPal = bmpPal;
        }
        
        /**
         * Encode bitmap file (work in progress) 
         * @return 
         */        
        public function encode():Boolean            
        {
            if (!bitmapData)    return false;
            if (!bmpHdr)        return false;
            
            // set bitmapheader image dimension
            bmpHdr.lbiWidth = bitmapData.width;
            bmpHdr.lbiHeight = bitmapData.height;
            var lineWidth:uint = WinBmpImg.byteWidth(bmpHdr.lbiWidth, bmpHdr.ibiBitCount);
            bmpHdr.lbiSizeImage = lineWidth * bmpHdr.lbiHeight;
            
            // write pixel data into byte array
            bytes = new ByteArray();
            switch(bmpHdr.ibiBitCount)
            {
                case WinBmpHdr.BPP_1:
                return encode1bpp(lineWidth);
                
                case WinBmpHdr.BPP_4:
                return encode4bpp(lineWidth);
                
                case WinBmpHdr.BPP_8:
                return encode8bpp(lineWidth);
                
                case WinBmpHdr.BPP_16:
                Alert.show("Sorry, 16bpp not supported!");
                break;
                
                case WinBmpHdr.BPP_24:
                return encode24bpp(lineWidth);
            }
            return false;
        }
        
        /**
         * Decode a Windows bitmap to Flex BitmapData 
         * @param bytes
         * @return 
         */        
        public function decode( bytes:ByteArray)    
                                :Boolean            // success or failed
        {    
            if (!fileHdr)    return false;
            if (!bmpHdr)    return false;
            if (!bmpPal)    return false;
            empty();
            
            this.bytes = bytes;
            bitmapData = new BitmapData(bmpHdr.lbiWidth, bmpHdr.lbiHeight);
            
            switch(bmpHdr.ibiBitCount)
            {
                case WinBmpHdr.BPP_1:
                return decode1bpp();
                
                case WinBmpHdr.BPP_4:
                return decode4bpp();
                
                case WinBmpHdr.BPP_8:
                return decode8bpp();
                
                case WinBmpHdr.BPP_16:
                return decode16bpp();
                
                case WinBmpHdr.BPP_24:
                return decode24bpp();
            }
            return false;
        }

/////////////////////////////////////////////////////////////////////
// protected encoding
        protected function encode1bpp(lineWidth:uint):Boolean
        {
            /****work in progress *****/
            for (var y:int=bmpHdr.lbiHeight-1; y>=0; y--) {
                var eightPixels:uint = 0;
                var count:int = 0;
                for (var x:int=0; x<bmpHdr.lbiWidth; x++) {
                    var clr:uint = bitmapData.getPixel(x,y);
                    var index:uint = bmpPal.get1bppIndex(clr);
                    eightPixels += index << count;
                    count ++;
                    if(count == 8) {
                        bytes.writeByte((eightPixels))
                        eightPixels = 0;
                        count = 0;
                    }
                }
                // add padding to meet 32bit block 
                for (var i:int=x; i<lineWidth*8; i++) {
                    count ++;
                    if(count == 8) {
                        bytes.writeByte((eightPixels))
                        eightPixels = 0;
                        count = 0;
                    }
                }
            }
            return true;
        }
        
        protected function encode4bpp(lineWidth:uint):Boolean
        {
            for (var y:int=bmpHdr.lbiHeight-1; y>=0; y--) {
                var twoPixels:uint = 0;
                for (var x:int=0; x<bmpHdr.lbiWidth; x++) {
                    var clr:uint = bitmapData.getPixel(x,y);
                    var index:uint = bmpPal.getIndex(clr);
                    twoPixels += (x%2)?index:index<<4;
                    if(x%2) {
                        bytes.writeByte((twoPixels))
                        twoPixels = 0;
                    }
                }
                // add padding to meet 32bit block 
                for (var i:int=x; i<lineWidth*2; i++) {
                    if(i%2) {
                        bytes.writeByte(twoPixels)
                        twoPixels = 0;
                    }
                }
            }
            return true;
        }
        
        protected function encode8bpp(lineWidth:uint):Boolean
        {
            for (var y:int=bmpHdr.lbiHeight-1; y>=0; y--) {
                for (var x:int=0; x<bmpHdr.lbiWidth; x++) {
                    var clr:uint = bitmapData.getPixel(x,y);
                    var index:uint = bmpPal.getIndex(clr);
                    bytes.writeByte((index))
                }
                // add padding to meet 32bit block 
                for (var i:int=x; i<lineWidth; i++) {
                    bytes.writeByte(0);
                }
            }
            return true;
        }
        
        protected function encode24bpp(lineWidth:uint):Boolean
        {
            for (var y:int=bmpHdr.lbiHeight-1; y>=0; y--) {
                for (var x:int=0; x<bmpHdr.lbiWidth*3; x+=3) {
                    var clr:uint = bitmapData.getPixel(x/3,y);
                    bytes.writeByte((clr & 0xFF))
                    bytes.writeByte((clr & 0xFF00)>>(8))
                    bytes.writeByte((clr & 0xFF0000)>>(8*2))
                }
                // add padding to meet 32bit block 
                for (var i:int=x; i<lineWidth; i++) {
                    bytes.writeByte(0);
                }
            }
            return true;
        }

/////////////////////////////////////////////////////////////////////
// protected decoding
        
        protected function decode1bpp():Boolean
        {
            var offset:uint = fileHdr.lbfOffs;
            var lineWidth:uint = WinBmpImg.byteWidth(bmpHdr.lbiWidth, bmpHdr.ibiBitCount);
            var Y:int=bmpHdr.lbiHeight-1;
            
            for ( var y:int=0; y<bmpHdr.lbiHeight; y++) {
                var mask:uint = 0x80;
                for ( var x:int=0; x<bmpHdr.lbiWidth; x++) {
                    var i:uint = x/8;
                    var pixel:uint = bytes[offset+lineWidth*Y+i];
                    var palIndex:int = (pixel&mask)?1:0;
                    var clr:uint = bmpPal.palette[palIndex*4];
                    clr += bmpPal.palette[palIndex*4+1]<<(8);
                    clr += bmpPal.palette[palIndex*4+2]<<(8*2);
                    bitmapData.setPixel(x,y, clr);
                    mask = (mask>1)? mask>>1:0x80;
                }
                Y --;
            }
            return true;
        }
        
        protected function decode4bpp():Boolean
        {
            var offset:uint = fileHdr.lbfOffs;
            var lineWidth:uint = WinBmpImg.byteWidth(bmpHdr.lbiWidth, bmpHdr.ibiBitCount);
            var mask:uint;
            var pixel:uint;
            var palIndex:uint;
            var Y:int=bmpHdr.lbiHeight-1;
            
            for ( var y:int=0; y<bmpHdr.lbiHeight; y++) {
                for ( var x:int=0; x<bmpHdr.lbiWidth; x++) {
                    var i:uint = x/2;
                    pixel = bytes[offset+lineWidth*Y+i];
                    if (x%2) {
                        mask = 240;
                        palIndex = ( pixel & mask ) >> 4;                        
                    }
                    else {
                        mask = 15;
                        palIndex = ( pixel & mask );    
                    }
                    var clr:uint = bmpPal.palette[palIndex*4];
                    clr += bmpPal.palette[palIndex*4+1]<<(8);
                    clr += bmpPal.palette[palIndex*4+2]<<(8*2);
                    bitmapData.setPixel(x,y, clr);
                }
                Y --;
            }
            return true;
        }
        
        protected function decode8bpp():Boolean
        {
            var offset:uint = fileHdr.lbfOffs;
            var lineWidth:uint = WinBmpImg.byteWidth(bmpHdr.lbiWidth, bmpHdr.ibiBitCount);
            var palIndex:uint;
            
            var Y:int=bmpHdr.lbiHeight-1;
            for ( var y:int=0; y<bmpHdr.lbiHeight; y++) {
                for ( var x:int=0; x<bmpHdr.lbiWidth; x++) {
                    palIndex = bytes[offset+lineWidth*Y+x];
                    var clr:uint = bmpPal.palette[palIndex*4];
                    clr += bmpPal.palette[palIndex*4+1]<<(8);
                    clr += bmpPal.palette[palIndex*4+2]<<(8*2);
                    bitmapData.setPixel(x,y, clr);
                }
                Y --;
            }
            return true;
        }
        
        protected function decode16bpp():Boolean
        {
            Alert.show("Sorry, not supported!");
            return true;
        }
        
        protected function decode24bpp():Boolean
        {
            var offset:uint = fileHdr.lbfOffs;
            var i:uint = 0;
            var lineWidth:uint = WinBmpImg.byteWidth(bmpHdr.lbiWidth, bmpHdr.ibiBitCount);
            var Y:int = 0;
            for ( var y:int=bmpHdr.lbiHeight-1; y>=0; y--) {
                for ( var x:int=0; x<bmpHdr.lbiWidth; x++) {
                    var clr:uint = uint(bytes[offset+i]);
                        clr += uint(bytes[offset+i+1]) <<(8);
                        clr += uint(bytes[offset+i+2]) <<(8*2);
                    bitmapData.setPixel(x,y, clr);
                    i += 3;
                }
                i = Y * lineWidth;
                Y++;
            }
            return true;
        }
    }
}