LZWEncoder.cs
上传用户:lqb116
上传日期:2014-04-04
资源大小:2712k
文件大小:8k
源码类别:

P2P编程

开发平台:

C#

  1. using System;
  2. using System.IO;
  3. namespace LanMsg.Gif.Components
  4. {
  5. public class LZWEncoder 
  6. {
  7. private static readonly int EOF = -1;
  8. private int imgW, imgH;
  9. private byte[] pixAry;
  10. private int initCodeSize;
  11. private int remaining;
  12. private int curPixel;
  13. // GIFCOMPR.C       - GIF Image compression routines
  14. //
  15. // Lempel-Ziv compression based on 'compress'.  GIF modifications by
  16. // David Rowley (mgardi@watdcsu.waterloo.edu)
  17. // General DEFINEs
  18. static readonly int BITS = 12;
  19. static readonly int HSIZE = 5003; // 80% occupancy
  20. // GIF Image compression - modified 'compress'
  21. //
  22. // Based on: compress.c - File compression ala IEEE Computer, June 1984.
  23. //
  24. // By Authors:  Spencer W. Thomas      (decvax!harpo!utah-cs!utah-gr!thomas)
  25. //              Jim McKie              (decvax!mcvax!jim)
  26. //              Steve Davies           (decvax!vax135!petsd!peora!srd)
  27. //              Ken Turkowski          (decvax!decwrl!turtlevax!ken)
  28. //              James A. Woods         (decvax!ihnp4!ames!jaw)
  29. //              Joe Orost              (decvax!vax135!petsd!joe)
  30. int n_bits; // number of bits/code
  31. int maxbits = BITS; // user settable max # bits/code
  32. int maxcode; // maximum code, given n_bits
  33. int maxmaxcode = 1 << BITS; // should NEVER generate this code
  34. int[] htab = new int[HSIZE];
  35. int[] codetab = new int[HSIZE];
  36. int hsize = HSIZE; // for dynamic table sizing
  37. int free_ent = 0; // first unused entry
  38. // block compression parameters -- after all codes are used up,
  39. // and compression rate changes, start over.
  40. bool clear_flg = false;
  41. // Algorithm:  use open addressing double hashing (no chaining) on the
  42. // prefix code / next character combination.  We do a variant of Knuth's
  43. // algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
  44. // secondary probe.  Here, the modular division first probe is gives way
  45. // to a faster exclusive-or manipulation.  Also do block compression with
  46. // an adaptive reset, whereby the code table is cleared when the compression
  47. // ratio decreases, but after the table fills.  The variable-length output
  48. // codes are re-sized at this point, and a special CLEAR code is generated
  49. // for the decompressor.  Late addition:  construct the table according to
  50. // file size for noticeable speed improvement on small files.  Please direct
  51. // questions about this implementation to ames!jaw.
  52. int g_init_bits;
  53. int ClearCode;
  54. int EOFCode;
  55. // output
  56. //
  57. // Output the given code.
  58. // Inputs:
  59. //      code:   A n_bits-bit integer.  If == -1, then EOF.  This assumes
  60. //              that n_bits =< wordsize - 1.
  61. // Outputs:
  62. //      Outputs code to the file.
  63. // Assumptions:
  64. //      Chars are 8 bits long.
  65. // Algorithm:
  66. //      Maintain a BITS character long buffer (so that 8 codes will
  67. // fit in it exactly).  Use the VAX insv instruction to insert each
  68. // code in turn.  When the buffer fills up empty it and start over.
  69. int cur_accum = 0;
  70. int cur_bits = 0;
  71. int [] masks =
  72. {
  73. 0x0000,
  74. 0x0001,
  75. 0x0003,
  76. 0x0007,
  77. 0x000F,
  78. 0x001F,
  79. 0x003F,
  80. 0x007F,
  81. 0x00FF,
  82. 0x01FF,
  83. 0x03FF,
  84. 0x07FF,
  85. 0x0FFF,
  86. 0x1FFF,
  87. 0x3FFF,
  88. 0x7FFF,
  89. 0xFFFF };
  90. // Number of characters so far in this 'packet'
  91. int a_count;
  92. // Define the storage for the packet accumulator
  93. byte[] accum = new byte[256];
  94. //----------------------------------------------------------------------------
  95. public LZWEncoder(int width, int height, byte[] pixels, int color_depth) 
  96. {
  97. imgW = width;
  98. imgH = height;
  99. pixAry = pixels;
  100. initCodeSize = Math.Max(2, color_depth);
  101. }
  102. // Add a character to the end of the current packet, and if it is 254
  103. // characters, flush the packet to disk.
  104. void Add(byte c, Stream outs)
  105. {
  106. accum[a_count++] = c;
  107. if (a_count >= 254)
  108. Flush(outs);
  109. }
  110. // Clear out the hash table
  111. // table clear for block compress
  112. void ClearTable(Stream outs)
  113. {
  114. ResetCodeTable(hsize);
  115. free_ent = ClearCode + 2;
  116. clear_flg = true;
  117. Output(ClearCode, outs);
  118. }
  119. // reset code table
  120. void ResetCodeTable(int hsize) 
  121. {
  122. for (int i = 0; i < hsize; ++i)
  123. htab[i] = -1;
  124. }
  125. void Compress(int init_bits, Stream outs)
  126. {
  127. int fcode;
  128. int i /* = 0 */;
  129. int c;
  130. int ent;
  131. int disp;
  132. int hsize_reg;
  133. int hshift;
  134. // Set up the globals:  g_init_bits - initial number of bits
  135. g_init_bits = init_bits;
  136. // Set up the necessary values
  137. clear_flg = false;
  138. n_bits = g_init_bits;
  139. maxcode = MaxCode(n_bits);
  140. ClearCode = 1 << (init_bits - 1);
  141. EOFCode = ClearCode + 1;
  142. free_ent = ClearCode + 2;
  143. a_count = 0; // clear packet
  144. ent = NextPixel();
  145. hshift = 0;
  146. for (fcode = hsize; fcode < 65536; fcode *= 2)
  147. ++hshift;
  148. hshift = 8 - hshift; // set hash code range bound
  149. hsize_reg = hsize;
  150. ResetCodeTable(hsize_reg); // clear hash table
  151. Output(ClearCode, outs);
  152. outer_loop : while ((c = NextPixel()) != EOF) 
  153.  {
  154.  fcode = (c << maxbits) + ent;
  155.  i = (c << hshift) ^ ent; // xor hashing
  156.  if (htab[i] == fcode) 
  157.  {
  158.  ent = codetab[i];
  159.  continue;
  160.  } 
  161.  else if (htab[i] >= 0) // non-empty slot
  162.  {
  163.  disp = hsize_reg - i; // secondary hash (after G. Knott)
  164.  if (i == 0)
  165.  disp = 1;
  166.  do 
  167.  {
  168.  if ((i -= disp) < 0)
  169.  i += hsize_reg;
  170.  if (htab[i] == fcode) 
  171.  {
  172.  ent = codetab[i];
  173.  goto outer_loop;
  174.  }
  175.  } while (htab[i] >= 0);
  176.  }
  177.   Output(ent, outs);
  178.  ent = c;
  179.  if (free_ent < maxmaxcode) 
  180.  {
  181.  codetab[i] = free_ent++; // code -> hashtable
  182.  htab[i] = fcode;
  183.  } 
  184.  else
  185.   ClearTable(outs);
  186.  }
  187. // Put out the final code.
  188. Output(ent, outs);
  189. Output(EOFCode, outs);
  190. }
  191. //----------------------------------------------------------------------------
  192. public void Encode( Stream os)
  193. {
  194. os.WriteByte( Convert.ToByte( initCodeSize) ); // write "initial code size" byte
  195. remaining = imgW * imgH; // reset navigation variables
  196. curPixel = 0;
  197. Compress(initCodeSize + 1, os); // compress and write the pixel data
  198. os.WriteByte(0); // write block terminator
  199. }
  200. // Flush the packet to disk, and reset the accumulator
  201. void Flush(Stream outs)
  202. {
  203. if (a_count > 0) 
  204. {
  205. outs.WriteByte( Convert.ToByte( a_count ));
  206. outs.Write(accum, 0, a_count);
  207. a_count = 0;
  208. }
  209. }
  210. int MaxCode(int n_bits) 
  211. {
  212. return (1 << n_bits) - 1;
  213. }
  214. //----------------------------------------------------------------------------
  215. // Return the next pixel from the image
  216. //----------------------------------------------------------------------------
  217. private int NextPixel() 
  218. {
  219. if (remaining == 0)
  220. return EOF;
  221. --remaining;
  222. int temp = curPixel + 1;
  223. if ( temp < pixAry.GetUpperBound( 0 ))
  224. {
  225. byte pix = pixAry[curPixel++];
  226. return pix & 0xff;
  227. }
  228. return 0xff;
  229. }
  230. void Output(int code, Stream outs)
  231. {
  232. cur_accum &= masks[cur_bits];
  233. if (cur_bits > 0)
  234. cur_accum |= (code << cur_bits);
  235. else
  236. cur_accum = code;
  237. cur_bits += n_bits;
  238. while (cur_bits >= 8) 
  239. {
  240. Add((byte) (cur_accum & 0xff), outs);
  241. cur_accum >>= 8;
  242. cur_bits -= 8;
  243. }
  244. // If the next entry is going to be too big for the code size,
  245. // then increase it, if possible.
  246. if (free_ent > maxcode || clear_flg) 
  247. {
  248. if (clear_flg) 
  249. {
  250. maxcode = MaxCode(n_bits = g_init_bits);
  251. clear_flg = false;
  252. else 
  253. {
  254. ++n_bits;
  255. if (n_bits == maxbits)
  256. maxcode = maxmaxcode;
  257. else
  258. maxcode = MaxCode(n_bits);
  259. }
  260. }
  261. if (code == EOFCode) 
  262. {
  263. // At EOF, write the rest of the buffer.
  264. while (cur_bits > 0) 
  265. {
  266. Add((byte) (cur_accum & 0xff), outs);
  267. cur_accum >>= 8;
  268. cur_bits -= 8;
  269. }
  270. Flush(outs);
  271. }
  272. }
  273. }
  274. }