PngEncoder.cs
上传用户:huazai0421
上传日期:2008-05-30
资源大小:405k
文件大小:7k
源码类别:

SilverLight

开发平台:

C#

  1. using System;
  2. using System.IO;
  3. namespace Silverlight.Samples
  4. {
  5. /// <summary>
  6. /// PngEncoder class courtesy of Joe Stegman and opmized by Nikola:
  7. /// http://blogs.msdn.com/nikola/archive/2009/03/04/silverlight-super-fast-dymanic-image-generation-code-revisited.aspx
  8. /// </summary>
  9. public class PngEncoder
  10. {
  11. private const int _MAXBLOCK = 0xFFFF;
  12. private static byte[] _HEADER = { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A };
  13. private static byte[] _IHDR = { (byte)'I', (byte)'H', (byte)'D', (byte)'R' };
  14. private static byte[] _GAMA = { (byte)'g', (byte)'A', (byte)'M', (byte)'A' };
  15. private static byte[] _IDAT = { (byte)'I', (byte)'D', (byte)'A', (byte)'T' };
  16. private static byte[] _IEND = { (byte)'I', (byte)'E', (byte)'N', (byte)'D' };
  17. public PngEncoder(int width, int height)
  18. {
  19. PrepareBuffer(width, height);
  20. }
  21. public Stream GetImageStream()
  22. {
  23. MemoryStream ms = new MemoryStream();
  24. ms.Write(_buffer, 0, _buffer.Length);
  25. ms.Seek(0, SeekOrigin.Begin);
  26. return ms;
  27. }
  28. public void SetPixelSlow(int col, int row, byte red, byte green, byte blue, byte alpha)
  29. {
  30. int start = _rowLength * row + col * 4 + 1;
  31. int blockNum = start / _blockSize;
  32. start += ((blockNum + 1) * 5);
  33. start += _dataStart;
  34. _buffer[start] = red;
  35. _buffer[start + 1] = green;
  36. _buffer[start + 2] = blue;
  37. _buffer[start + 3] = alpha;
  38. }
  39. public void SetPixelAtRowStart(int col, int rowStart, byte red, byte green, byte blue, byte alpha)
  40. {
  41. int start = rowStart + (col << 2);
  42. _buffer[start] = red;
  43. _buffer[start + 1] = green;
  44. _buffer[start + 2] = blue;
  45. _buffer[start + 3] = alpha;
  46. }
  47. public int GetRowStart(int row)
  48. {
  49. int start = _rowLength * row + 1;
  50. int blockNum = start / _blockSize;
  51. start += ((blockNum + 1) * 5);
  52. start += _dataStart;
  53. return start;
  54. }
  55. byte[] _buffer;
  56. int _rowLength;
  57. int _blockSize;
  58. int _dataStart;
  59. private void PrepareBuffer(int width, int height)
  60. {
  61. uint widthLength = (uint)(width * 4) + 1;
  62. _rowLength = (int)widthLength;
  63. uint dcSize = widthLength * (uint)height;
  64. uint rowsPerBlock = _MAXBLOCK / widthLength;
  65. uint blockSize = rowsPerBlock * widthLength;
  66. _blockSize = (int)blockSize;
  67. uint blockCount;
  68. ushort length;
  69. uint remainder = dcSize;
  70. if ((dcSize % blockSize) == 0)
  71. {
  72. blockCount = dcSize / blockSize;
  73. }
  74. else
  75. {
  76. blockCount = (dcSize / blockSize) + 1;
  77. }
  78. uint totalSize = 51 + (dcSize + 12 + 4 + blockCount * 5) + 12; // header, (data), end
  79. _buffer = new byte[totalSize];
  80. int currIndex = 0;
  81. // ********************************
  82. // ******* write png header ******* 
  83. _HEADER.CopyTo(_buffer, (int)currIndex);
  84. currIndex += _HEADER.Length;
  85. // ********************************
  86. // ******* Write IHDR ******* 
  87. //  Width:              4 bytes
  88. //  Height:             4 bytes
  89. //  Bit depth:          1 byte
  90. //  Color type:         1 byte
  91. //  Compression method: 1 byte
  92. //  Filter method:      1 byte
  93. //  Interlace method:   1 byte
  94. byte[] size;
  95. size = BitConverter.GetBytes((uint)13); // sizeof(data(IHDR))
  96. _buffer[currIndex] = size[3]; currIndex++;
  97. _buffer[currIndex] = size[2]; currIndex++;
  98. _buffer[currIndex] = size[1]; currIndex++;
  99. _buffer[currIndex] = size[0]; currIndex++;
  100. // "IHDR"
  101. _IHDR.CopyTo(_buffer, (int)currIndex);
  102. currIndex += _IHDR.Length;
  103. size = BitConverter.GetBytes(width);
  104. _buffer[currIndex] = size[3]; currIndex++;
  105. _buffer[currIndex] = size[2]; currIndex++;
  106. _buffer[currIndex] = size[1]; currIndex++;
  107. _buffer[currIndex] = size[0]; currIndex++;
  108. size = BitConverter.GetBytes(height);
  109. _buffer[currIndex] = size[3]; currIndex++;
  110. _buffer[currIndex] = size[2]; currIndex++;
  111. _buffer[currIndex] = size[1]; currIndex++;
  112. _buffer[currIndex] = size[0]; currIndex++;
  113. _buffer[currIndex] = 8; currIndex++; // 8 bits
  114. _buffer[currIndex] = 6; currIndex++; // RGBA format
  115. currIndex += 3; // skip to end of IHDR
  116. currIndex += 4; // skip CRC, assume 0
  117. // ********************************
  118. // ******* Write gAMA chunk ******* 
  119. size = BitConverter.GetBytes((uint)4); // sizeof(data(gAMA))
  120. _buffer[currIndex] = size[3]; currIndex++;
  121. _buffer[currIndex] = size[2]; currIndex++;
  122. _buffer[currIndex] = size[1]; currIndex++;
  123. _buffer[currIndex] = size[0]; currIndex++;
  124. // "GAMA"
  125. _GAMA.CopyTo(_buffer, (int)currIndex);
  126. currIndex += _GAMA.Length;
  127. // Set gamma = 1
  128. size = BitConverter.GetBytes(1 * 100000);
  129. _buffer[currIndex] = size[3]; currIndex++;
  130. _buffer[currIndex] = size[2]; currIndex++;
  131. _buffer[currIndex] = size[1]; currIndex++;
  132. _buffer[currIndex] = size[0]; currIndex++;
  133. currIndex += 4; // skip CRC, assume 0
  134. // ***************************************
  135. // ******* Write IDAT (data) chunk ******* 
  136. size = BitConverter.GetBytes(dcSize + 2 + 4 + blockCount * 5); // image data size + 2 bytes for compression header + 4 bytes for adler checksum + blocks overhead
  137. _buffer[currIndex] = size[3]; currIndex++;
  138. _buffer[currIndex] = size[2]; currIndex++;
  139. _buffer[currIndex] = size[1]; currIndex++;
  140. _buffer[currIndex] = size[0]; currIndex++;
  141. // "IDAT"
  142. _IDAT.CopyTo(_buffer, (int)currIndex);
  143. currIndex += _IDAT.Length;
  144. // write compression header
  145. _buffer[currIndex] = 0x78; currIndex++;
  146. _buffer[currIndex] = 0xDA; currIndex++;
  147. _dataStart = currIndex;
  148. // write image data
  149. //currIndex += (int)dcSize; // !!!
  150. for (uint blocks = 0; blocks < blockCount; blocks++)
  151. {
  152. // Write LEN
  153. length = (ushort)((remainder < blockSize) ? remainder : blockSize);
  154. if (length == remainder)
  155. {
  156. _buffer[currIndex] = 1;
  157. }
  158. else
  159. {
  160. _buffer[currIndex] = 0;
  161. }
  162. currIndex++;
  163. size = BitConverter.GetBytes(length);
  164. _buffer[currIndex] = size[0]; currIndex++;
  165. _buffer[currIndex] = size[1]; currIndex++;
  166. // Write one's compliment of LEN
  167. size = BitConverter.GetBytes((ushort)~length);
  168. _buffer[currIndex] = size[0]; currIndex++;
  169. _buffer[currIndex] = size[1]; currIndex++;
  170. // Write blocks
  171. //for (int i = currIndex; i < currIndex + length; i++)
  172. //{
  173. //    _buffer[i] = 200;
  174. //}
  175. currIndex += length;
  176. // Next block
  177. remainder -= blockSize;
  178. }
  179. currIndex += 4; // skip adler32 checksum, assume 0
  180. currIndex += 4; // skip CRC, assume 0
  181. // ********************************
  182. // ******* Write IEND chunk ******* 
  183. currIndex += 4; // sizeof(data(IEND)) is 0
  184. // "IEND"
  185. _IEND.CopyTo(_buffer, (int)currIndex);
  186. currIndex += _IEND.Length;
  187. _buffer[currIndex] = 81; currIndex++; // CRC
  188. _buffer[currIndex] = 189; currIndex++; // CRC
  189. _buffer[currIndex] = 159; currIndex++; // CRC
  190. _buffer[currIndex] = 125; currIndex++; // CRC
  191. }
  192. }
  193. }