守望者--AIR技术交流

标题: AS3中的PNG编码! [打印本页]

作者: 水玲珑    时间: 2015-1-11 17:16
标题: AS3中的PNG编码!
  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. }
复制代码







欢迎光临 守望者--AIR技术交流 (http://www.airmyth.com/)