11RIA 闪客社区 - 最赞 Animate Flash 论坛

搜索
查看: 2541|回复: 1
上一主题 下一主题

[★ AS3 类库] AS3中的PNG编码!(PNGEncoder)

[复制链接] TA的其它主题
发表于 2018-12-11 23:41:58 | 显示全部楼层 |阅读模式

【游客模式】——注册会员,加入11RIA 闪客社区吧!一起见证Flash的再次辉煌……

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
本帖最后由 风雨AS3 于 2018-12-11 23:44 编辑

转载:守望者--AIR技术交流
网址:http://www.airmyth.com/thread-816-1-1.html



[Actionscript3] 纯文本查看 复制代码
package cn.window.image.png
{
    import flash.display.BitmapData;
    
    import flash.utils.ByteArray;
    
    
    public class PNGEncoder
    {
        /** CRC验证器 */
        private var crcTable : Array;
        
        
        /**
         *PNG文件格式分为PNG-24和PNG-8,
         * 其最大的区别是PNG-24是用24位来保存一个像素值,是真彩色,
         * 而PNG-8是用8位索引值来在调色盘 中索引一个颜色,
         * 因为一个索引值的最大上限为2的8次方既128,故调色盘中颜色数最多为128种,
         * 所以该文件格式又被叫做PNG-8 128仿色。PNG-24因为其图片容量过大,
         * 而且在Nokia和Moto等某些机型上创建图片失败和显示不正确等异常时有发生,
         * 有时还会严重拖慢显示速度,故并不常 用,
         * CoCoMo认为这些异常和平台底层的图像解压不无关系。
         * 不过该格式最大的优点是可以保存Alpha通道,
         * 同事也曾有过利用该图片格式实现Alpha 混合的先例,
         * 想来随着技术的发展,手机硬件平台的提升,Alpha混合一定会被广泛的应用,
         * 到那时该格式的最大优势才会真正发挥。
 
         */
        public function PNGEncoder ()
        {
            initializeCRCTable();
        }
        
        /**
         *将 BitmapData 对象的像素转换为 PNG 编码的 ByteArray 对象。 
         * @param bitmapData BitmapData 输入对象。
         * @return 返回包含以 PNG 格式编码的图像数据的 ByteArray 对象。
         */
        public function encode ( bitmapData:BitmapData ) : ByteArray
        {

            return internalEncode(bitmapData, bitmapData.width, bitmapData.height, bitmapData.transparent);
        }
        
        /**
         *将包含 32 位 ARGB(Alpha、红、绿、蓝)格式原始像素的 ByteArray 对象
         * 转换为新的 PNG 编码的 ByteArray 对象。
         * 原始的 ByteArray 将保持不变。 
         * @param byteArray 包含原始像素的 ByteArray 输入对象。<br>
         *                                   此 ByteArray 应包含 4 width height 字节。<br>
         *                                   每个像素都由 4 个字节表示,顺序依次为 ARGB。<br>
         *                                   前四个字节表示图像左上角的像素。<br>
         *                                   接下来的四个字节表示其右侧的像素,依此类推。每一行与前一行之间没有任何填充。
         * @param width 输入图像的宽度(以像素为单位)。
         * @param height 输入图像的高度(以像素为单位)。
         * @param transparent 如果为 false,则将忽略 Alpha 通道信息,但是您仍必须使用 ARGB 格式以四个字节表示每个像素。
         * @return  返回包含以 PNG 格式编码的图像数据的 ByteArray 对象。
         */
        public function encodeByteArray ( byteArray:ByteArray, width:int, height:int, transparent:Boolean = true ) : ByteArray
        {
            return internalEncode( byteArray, width, height, transparent );
        }
        
        /**
         *初始化CRC验证器 
         * <p>
         * CRC(cyclic redundancy check)域中的值是对Chunk Type Code域和Chunk Data域中的数据进行计算得到的。<br>
         * CRC具体算法定义在ISO 3309和ITU-T V.42中,其值按下面的CRC码生成多项式进行计算:<br>
         * x<sup>32</sup>+x<sup>26</sup>+x<sup>23</sup>+x<sup>22</sup>+x<sup>16</sup>+x<sup>12</sup>+x
         *<sup>11</sup>+x<sup>10</sup>+x<sup>8</sup>+x<sup>7</sup>+x<sup>5</sup>+x<sup>4</sup>+x<sup>2</sup>+x+1
         * <p>
         */
        private function initializeCRCTable () : void
        {
            crcTable = [];
            
            for ( var n:uint = 0; n < 256; n++ )
            {
                var c:uint = n;
                for ( var k:uint = 0; k < 8; k++)
                {
                    if (c & 1)
                    {
                        c = uint(uint(0xedb88320) ^ uint(c >>> 1));
                    }
                    else
                    {
                        c = uint(c >>> 1);
                    }
                }
                crcTable[n] = c;
            }
        }
        
        /**
         * 进行编码, source可以为BitmapData 或 a ByteArray.<br>
         * <b>PNG签名</b><br>
         * 89 50 4e 47 0d 0a 1a 0a<br>
         * 其中第一个字节0x89超出了ASCII字符的范围,这是为了避免某些软件将PNG文件当做文本文件来处理<br>
         * 0x50 0x4e 0x47 为 PNG 的Unicode编码<br>
         * 0d 0a 1a 0a 这4个就不知道了<br>
         * <b>PNG数据块(Chunk):</b><br>
        
         *<table align="center" bgcolor="#eeeeee" border="0">

         *<tr><td colspan="5"><div align="center"><strong>PNG文件格式中的数据块</strong></div></td></tr>

         *<tr><td><div align="center"><b>数据块符号</b></div></td><td><div align="center"><b>数据块名称</b></div></td>
         *<td><div align="center"><b>多数据块</b></div></td><td><div align="center"><b>可选否</b></div></td>
         *<td><div align="center"><b>位置限制</b></div></td></tr>

         *<tr><td>IHDR</td><td>文件头数据块</td><td>否</td><td>否</td><td>第一块</td></tr>

         *<tr><td>cHRM</td><td>基色和白色点数据块</td><td>否</td><td>是</td><td>在PLTE和IDAT之前</td></tr>

         *<tr><td>gAMA</td><td>图像γ数据块</td><td>否</td><td>是</td><td>在PLTE和IDAT之前</td></tr>

         *<tr><td>sBIT</td><td>样本有效位数据块</td><td>否</td><td>是</td><td>在PLTE和IDAT之前</td></tr>

         *<tr><td>PLTE</td><td>调色板数据块</td><td>否</td><td>是</td><td>在IDAT之前</td></tr>

         *<tr><td>bKGD</td><td>背景颜色数据块</td><td>否</td><td>是</td><td>在PLTE之后IDAT之前</td></tr>

         *<tr><td>hIST</td><td>图像直方图数据块</td><td>否</td><td>是</td><td>在PLTE之后IDAT之前</td></tr>

         *<tr><td>tRNS</td><td>图像透明数据块</td><td>否</td><td>是</td><td>在PLTE之后IDAT之前</td></tr>

         *<tr><td>oFFs</td><td>(专用公共数据块)</td><td>否</td><td>是</td><td>在IDAT之前</td></tr>

         *<tr><td>pHYs</td><td>物理像素尺寸数据块</td><td>否</td><td>是</td><td>在IDAT之前</td></tr>

         *<tr><td>sCAL</td><td>(专用公共数据块)</td><td>否</td><td>是</td><td>在IDAT之前</td></tr>

         *<tr><td>IDAT</td><td>图像数据块</td><td>是</td><td>否</td><td>与其他IDAT连续</td></tr>

         *<tr><td>tIME</td><td>图像最后修改时间数据块</td><td>否</td><td>是</td><td>无限制</td></tr>

         *<tr><td>tEXt</td><td>文本信息数据块</td><td>是</td><td>是</td><td>无限制</td></tr>

         *<tr><td>zTXt</td><td>压缩文本数据块</td><td>是</td><td>是</td><td>无限制</td></tr>

         *<tr><td>fRAc</td><td>(专用公共数据块)</td><td>是</td><td>是</td><td>无限制</td></tr>

         *<tr><td>gIFg</td><td>(专用公共数据块)</td><td>是</td><td>是</td><td>无限制</td></tr>

         *<tr><td>gIFt</td><td>(专用公共数据块)</td><td>是</td><td>是</td><td class="text">无限制</td></tr>

         *<tr><td>gIFx</td><td>(专用公共数据块)</td><td>是</td><td>是</td><td>无限制</td></tr>

         *<tr><td>IEND</td><td>图像结束数据</td><td>否</td><td>否</td><td>最后一个数据块</td></tr>

         *</table><br>

         * 

         * <b>数据块结构</b><br>

         *<table align="center" bgcolor="#eeeeee" border="0">

         *<tr><td><b>名称</b></td><td><b>字节数</b></td><td><b>说明</b></td></tr>

         *<tr><td>Length (长度)</td><td>4字节</td><td>指定数据块中数据域的长度,其长度不超过(2<sup>31</sup>-1)字节</td></tr>

         *<tr><td>Chunk Type Code (数据块类型码)</td><td>4字节</td><td>数据块类型码由ASCII字母(A-Z和a-z)组成</td></tr>

         *<tr><td>Chunk Data (数据块数据)</td><td>可变长度</td><td>存储按照Chunk Type Code指定的数据</td></tr>

         *<tr><td>CRC (循环冗余检测)</td><td>4字节</td><td>存储用来检测是否有错误的循环冗余码</td></tr>

         *</table><br>

         * 

         * <b>IHDR 数据结构:</b><br>

         * <table align="center" bgcolor="#eeeeee" border="0">

         *<tr> <td><div align="center"><b>域的名称</b></div></td> <td><div align="center"><b>字节数</b></div></td>
         *<td><div align="center"><b>说明</b></div></td> </tr>

         *<tr><td>Width</td> <td>4 bytes</td> <td>图像宽度,以像素为单位</td> </tr>

         *<tr> <td>Height</td> <td>4 bytes</td> <td>图像高度,以像素为单位</td> </tr>

         *<tr> <td>Bit depth</td> <td>1 byte</td> <td>图像深度: <br />索引彩色图像:1,2,4或8 <br/>
         *灰度图像:1,2,4,8或16 <br/>真彩色图像:8或16</td> </tr>

         *<tr> <td>ColorType</td> <td>1 byte</td> <td>颜色类型:<br/>0:灰度图像, 1,2,4,8或16 <br/>
         *2:真彩色图像,8或16 <br/>3:索引彩色图像,1,2,4或8 <br/>
         *4:带α通道数据的灰度图像,8或16 <br/>6:带α通道数据的真彩色图像,8或16</td> </tr>

         *<tr> <td>Compression method</td> <td>1 byte</td> <td>压缩方法(LZ77派生算法)</td> </tr>

         *<tr> <td>Filter method</td> <td>1 byte</td> <td>滤波器方法</td> </tr>

         *<tr> <td>Interlace method</td> <td>1 byte</td> <td>隔行扫描方法:<br/>0:非隔行扫描 <br/>
         
         *1: Adam7(由Adam M. Costello开发的7遍隔行扫描方法)</td> </tr>
         
         *</table><br>
         */
        private function internalEncode ( source:Object, width:int, height:int, transparent:Boolean = true ) : ByteArray
        {
            // The source is either a BitmapData or a ByteArray.
            var sourceBitmapData: BitmapData = source as BitmapData;

            var sourceByteArray: ByteArray = source as ByteArray;

            if ( sourceByteArray)
            {
                sourceByteArray.position = 0;
            }

            // 创建二进制输出流
            var png: ByteArray = new ByteArray();


            // 写入PNG签名(PNG文件的标志)89 50 4e 47 0d 0a 1a 0a
            png.writeUnsignedInt( 0x89504E47 );

            png.writeUnsignedInt( 0x0D0A1A0A);

            // 创建 IHDR(文件头数据块) 它包含有PNG文件中存储的图像数据的基本信息,

            //并要作为第一个数据块出现在PNG数据流中,而且一个PNG数据流中只能有一个文件头数据块。

            //文件头数据块由13字节组成,结构见注释

            var IHDR: ByteArray = new ByteArray();

            IHDR.writeInt(width); // 宽度

            IHDR.writeInt(height); //高度

            IHDR.writeByte(8); // bit depth per channel(图像深度) 

            IHDR.writeByte(6); // color type: RGBA(颜色类型)

            IHDR.writeByte(0); // compression method(压缩方法 --- LZ77派生算法)

            IHDR.writeByte(0); // filter method(滤波器方法)

            IHDR.writeByte(0); // interlace method (隔行扫描方法) 

            writeChunk(png, 0x49484452, IHDR);

            // 构建 IDAT chunk(图像数据块)
            var IDAT: ByteArray = new ByteArray();

            for ( var y: int = 0; y < height; y++ )
            {
                IDAT.writeByte(0); // no filter

                var x: int;

                var pixel: uint;

                if ( !transparent )
                {
                    for ( x = 0; x < width; x++ )
                    {
                        if (sourceBitmapData)
                        {
                            pixel = sourceBitmapData.getPixel(x, y);
                        }
                        else
                        {
                            pixel = sourceByteArray.readUnsignedInt();
                        }

                        IDAT.writeUnsignedInt(uint(((pixel & 0xFFFFFF) << 8) | 0xFF));
                    }
                }
                else
                {
                    for ( x = 0; x < width; x++ )
                    {

                        if ( sourceBitmapData)
                        {
                            pixel = sourceBitmapData.getPixel32(x, y);
                        }
                        else
                        {
                            pixel = sourceByteArray.readUnsignedInt();
                        }

                        IDAT.writeUnsignedInt(uint(((pixel & 0xFFFFFF) << 8) | (pixel >>> 24)));
                    }
                }
            }

            IDAT.compress();

            writeChunk(png, 0x49444154, IDAT);

            // 构建 IEND (图像结束数据)
            writeChunk(png, 0x49454E44, null);

            // return PNG
            png.position = 0;

            return png;
        }

        /**
         *  @private
         */
        private function writeChunk ( png: ByteArray, type: uint, data: ByteArray): void
        {
            // Write length of data.
            var len: uint = 0;

            if ( data )
            {
                len = data.length;
            }
            png.writeUnsignedInt(len);


            // Write chunk type.

            var typePos: uint = png.position;

            png.writeUnsignedInt(type);


            // Write data.

            if ( data )
            {
                png.writeBytes(data);
            }

            // Write CRC of chunk type and data.

            var crcPos: uint = png.position;

            png.position = typePos;

            var crc: uint = 0xFFFFFFFF;

            for ( var i:uint = typePos; i < crcPos; i++ )
            {
                crc = uint(crcTable[(crc ^ png.readUnsignedByte()) & uint(0xFF)] ^ uint(crc >>> 8));
            }

            crc = uint(crc ^ uint(0xFFFFFFFF));

            png.position = crcPos;

            png.writeUnsignedInt(crc);
        }
        
        
        
        
    }
}


发表于 2020-5-8 19:40:13 | 显示全部楼层
先赞再看
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

站长推荐 上一条 /1 下一条

感谢所有支持论坛的朋友:下面展示最新的5位赞助和充值的朋友……更多赞助和充值朋友的信息,请查看:永远的感谢名单

SGlW(66139)、 anghuo(841)、 whdsyes(255)、 longxia(60904)、 囫囵吞澡(58054)

下面展示总排行榜的前3名(T1-T3)和今年排行榜的前3名的朋友(C1-C3)……更多信息,请查看:总排行榜今年排行榜

T1. fhqu1462(969)、 T2. lwlpluto(14232)、 T3. 1367926921(962)  |  C1. anghuo(147)、 C2. fdisker(27945)、 C3. 囫囵吞澡(58054)



快速回复 返回顶部 返回列表