守望者--AIR技术交流

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

搜索
热搜: ANE FlasCC 炼金术
查看: 1262|回复: 0

[ActionScript] AS3中的PNG编码!

[复制链接]
  • TA的每日心情
    慵懒
    2016-8-19 16:03
  • 签到天数: 3 天

    [LV.2]偶尔看看I

    1

    主题

    4

    帖子

    4259

    积分

    中尉

    Rank: 7Rank: 7Rank: 7

    威望
    0
    贡献
    16
    金币
    117
    钢镚
    10
    发表于 2015-1-11 17:16:27 | 显示全部楼层 |阅读模式
    1. package cn.window.image.png

    2. {

    3. import flash.display.BitmapData;

    4. import flash.utils.ByteArray;



    5. public class PNGEncoder

    6. {

    7. /**CRC验证器*/

    8. private var crcTable:Array;


    9. /**

    10. *PNG文件格式分为PNG-24和PNG-8,

    11. * 其最大的区别是PNG-24是用24位来保存一个像素值,是真彩色,

    12. * 而PNG-8是用8位索引值来在调色盘 中索引一个颜色,

    13. * 因为一个索引值的最大上限为2的8次方既128,故调色盘中颜色数最多为128种,

    14. * 所以该文件格式又被叫做PNG-8 128仿色。PNG-24因为其图片容量过大,

    15. * 而且在Nokia和Moto等某些机型上创建图片失败和显示不正确等异常时有发生,

    16. * 有时还会严重拖慢显示速度,故并不常 用,

    17. * CoCoMo认为这些异常和平台底层的图像解压不无关系。

    18. * 不过该格式最大的优点是可以保存Alpha通道,

    19. * 同事也曾有过利用该图片格式实现Alpha 混合的先例,

    20. * 想来随着技术的发展,手机硬件平台的提升,Alpha混合一定会被广泛的应用,

    21. * 到那时该格式的最大优势才会真正发挥。


    22. *

    23. */

    24. public function PNGEncoder()

    25. {

    26. initializeCRCTable();

    27. }


    28. /**

    29. *将 BitmapData 对象的像素转换为 PNG 编码的 ByteArray 对象。

    30. * @param bitmapData BitmapData 输入对象。

    31. * @return 返回包含以 PNG 格式编码的图像数据的 ByteArray 对象。

    32. */

    33. public function encode(bitmapData:BitmapData):ByteArray

    34. {

    35. return internalEncode(bitmapData, bitmapData.width, bitmapData.height,

    36. bitmapData.transparent);

    37. }


    38. /**

    39. *将包含 32 位 ARGB(Alpha、红、绿、蓝)格式原始像素的 ByteArray 对象

    40. * 转换为新的 PNG 编码的 ByteArray 对象。

    41. * 原始的 ByteArray 将保持不变。

    42. * @param byteArray 包含原始像素的 ByteArray 输入对象。<br>

    43. *                                   此 ByteArray 应包含 4 width height 字节。<br>

    44. *                                   每个像素都由 4 个字节表示,顺序依次为 ARGB。<br>

    45. *                                   前四个字节表示图像左上角的像素。<br>

    46. *                                   接下来的四个字节表示其右侧的像素,依此类推。每一行与前一行之间没有任何填充。

    47. * @param width 输入图像的宽度(以像素为单位)。

    48. * @param height 输入图像的高度(以像素为单位)。

    49. * @param transparent 如果为 false,则将忽略 Alpha 通道信息,但是您仍必须使用 ARGB 格式以四个字节表示每个像素。

    50. * @return  返回包含以 PNG 格式编码的图像数据的 ByteArray 对象。

    51. *

    52. */

    53. public function encodeByteArray(byteArray:ByteArray, width:int, height:int,

    54. transparent:Boolean = true):ByteArray

    55. {

    56. return internalEncode(byteArray, width, height, transparent);

    57. }




    58. /**

    59. *初始化CRC验证器

    60. * <p>

    61. * CRC(cyclic redundancy check)域中的值是对Chunk Type Code域和Chunk Data域中的数据进行计算得到的。<br>

    62. * CRC具体算法定义在ISO 3309和ITU-T V.42中,其值按下面的CRC码生成多项式进行计算:<br>

    63. * 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
    64. *<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

    65. * <p>

    66. */

    67. private function initializeCRCTable():void

    68. {

    69. crcTable = [];


    70. for (var n:uint = 0; n < 256; n++)

    71. {

    72. var c:uint = n;

    73. for (var k:uint = 0; k < 8; k++)

    74. {

    75. if (c & 1)

    76. c = uint(uint(0xedb88320) ^ uint(c >>> 1));

    77. else

    78. c = uint(c >>> 1);

    79. }

    80. crcTable[n] = c;

    81. }

    82. }


    83. /**

    84. * 进行编码, source可以为BitmapData 或 a ByteArray.<br>

    85. *

    86. * <b>PNG签名</b><br>

    87. * 89 50 4e 47 0d 0a 1a 0a<br>

    88. * 其中第一个字节0x89超出了ASCII字符的范围,这是为了避免某些软件将PNG文件当做文本文件来处理<br>

    89. * 0x50 0x4e 0x47 为 PNG 的Unicode编码<br>

    90. * 0d 0a 1a 0a 这4个就不知道了<br>

    91. *

    92. * <b>PNG数据块(Chunk):</b><br>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    118. *</table><br>

    119. *

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

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

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

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

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

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

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

    127. *</table><br>

    128. *

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

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

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

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

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

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

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

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

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

    142. *<tr> <td>Interlace method</td> <td>1 byte</td> <td>隔行扫描方法:<br/>0:非隔行扫描 <br/>
    143. *1: Adam7(由Adam M. Costello开发的7遍隔行扫描方法)</td> </tr>

    144. *</table><br>

    145. */

    146. private function internalEncode(source:Object, width:int, height:int,

    147. transparent:Boolean = true):ByteArray

    148. {

    149. // The source is either a BitmapData or a ByteArray.

    150. var sourceBitmapData:BitmapData = source as BitmapData;

    151. var sourceByteArray:ByteArray = source as ByteArray;


    152. if (sourceByteArray)

    153. sourceByteArray.position = 0;


    154. // 创建二进制输出流

    155. var png:ByteArray = new ByteArray();


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

    157. png.writeUnsignedInt(0x89504E47);

    158. png.writeUnsignedInt(0x0D0A1A0A);


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

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

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

    162. var IHDR:ByteArray = new ByteArray();

    163. IHDR.writeInt(width); // 宽度

    164. IHDR.writeInt(height);//高度

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

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

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

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

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

    170. writeChunk(png, 0x49484452, IHDR);


    171. // 构建 IDAT chunk(图像数据块)

    172. var IDAT:ByteArray = new ByteArray();

    173. for (var y:int = 0; y < height; y++)

    174. {

    175. IDAT.writeByte(0); // no filter


    176. var x:int;

    177. var pixel:uint;


    178. if (!transparent)

    179. {

    180. for (x = 0; x < width; x++)

    181. {

    182. if (sourceBitmapData)

    183. pixel = sourceBitmapData.getPixel(x, y);

    184. else

    185. pixel = sourceByteArray.readUnsignedInt();


    186. IDAT.writeUnsignedInt(uint(((pixel & 0xFFFFFF) << 8) | 0xFF));

    187. }

    188. }

    189. else

    190. {

    191. for (x = 0; x < width; x++)

    192. {

    193. if (sourceBitmapData)

    194. pixel = sourceBitmapData.getPixel32(x, y);

    195. else

    196. pixel = sourceByteArray.readUnsignedInt();


    197. IDAT.writeUnsignedInt(uint(((pixel & 0xFFFFFF) << 8) |

    198. (pixel >>> 24)));

    199. }

    200. }

    201. }

    202. IDAT.compress();

    203. writeChunk(png, 0x49444154, IDAT);


    204. // 构建 IEND (图像结束数据)

    205. writeChunk(png, 0x49454E44, null);


    206. // return PNG

    207. png.position = 0;

    208. return png;

    209. }


    210. /**

    211. *  @private

    212. */

    213. private function writeChunk(png:ByteArray, type:uint, data:ByteArray):void

    214. {

    215. // Write length of data.

    216. var len:uint = 0;

    217. if (data)

    218. len = data.length;

    219. png.writeUnsignedInt(len);


    220. // Write chunk type.

    221. var typePos:uint = png.position;

    222. png.writeUnsignedInt(type);


    223. // Write data.

    224. if (data)

    225. png.writeBytes(data);


    226. // Write CRC of chunk type and data.

    227. var crcPos:uint = png.position;

    228. png.position = typePos;

    229. var crc:uint = 0xFFFFFFFF;

    230. for (var i:uint = typePos; i < crcPos; i++)

    231. {

    232. crc = uint(crcTable[(crc ^ png.readUnsignedByte()) & uint(0xFF)] ^

    233. uint(crc >>> 8));

    234. }

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

    236. png.position = crcPos;

    237. png.writeUnsignedInt(crc);

    238. }

    239. }

    240. }
    复制代码


    评分

    参与人数 1金币 +4 收起 理由
    破晓 + 4 赞一个!

    查看全部评分

    守望者AIR技术交流社区(www.airmyth.com)
    回复

    使用道具 举报

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

    本版积分规则

    
    关闭

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

    QQ|手机版|Archiver|网站地图|小黑屋|守望者 ( 京ICP备14061876号

    GMT+8, 2019-8-18 13:29 , Processed in 0.053496 second(s), 36 queries .

    守望者AIR

    守望者AIR技术交流社区

    本站成立于 2014年12月31日

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