LZWEncoder.java 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. package eu.mjdev.desktop.helpers.gif;
  2. import java.io.IOException;
  3. import java.io.OutputStream;
  4. class LZWEncoder {
  5. private static final int EOF = -1;
  6. private final int imgW;
  7. private final int imgH;
  8. private final byte[] pixAry;
  9. private final int initCodeSize;
  10. private int remaining;
  11. private int curPixel;
  12. static final int BITS = 12;
  13. static final int HSIZE = 5003;
  14. int n_bits;
  15. int maxbits = BITS;
  16. int maxcode;
  17. int maxmaxcode = 1 << BITS;
  18. int[] htab = new int[HSIZE];
  19. int[] codetab = new int[HSIZE];
  20. int hsize = HSIZE;
  21. int free_ent = 0;
  22. boolean clear_flg = false;
  23. int g_init_bits;
  24. int ClearCode;
  25. int EOFCode;
  26. int cur_accum = 0;
  27. int cur_bits = 0;
  28. int[] masks = {
  29. 0x0000,
  30. 0x0001,
  31. 0x0003,
  32. 0x0007,
  33. 0x000F,
  34. 0x001F,
  35. 0x003F,
  36. 0x007F,
  37. 0x00FF,
  38. 0x01FF,
  39. 0x03FF,
  40. 0x07FF,
  41. 0x0FFF,
  42. 0x1FFF,
  43. 0x3FFF,
  44. 0x7FFF,
  45. 0xFFFF
  46. };
  47. int a_count;
  48. byte[] accum = new byte[256];
  49. LZWEncoder(int width, int height, byte[] pixels, int color_depth) {
  50. imgW = width;
  51. imgH = height;
  52. pixAry = pixels;
  53. initCodeSize = Math.max(2, color_depth);
  54. }
  55. void char_out(byte c, OutputStream outs) throws IOException {
  56. accum[a_count++] = c;
  57. if (a_count >= 254) flush_char(outs);
  58. }
  59. void cl_block(OutputStream outs) throws IOException {
  60. cl_hash(hsize);
  61. free_ent = ClearCode + 2;
  62. clear_flg = true;
  63. output(ClearCode, outs);
  64. }
  65. void cl_hash(int hsize) {
  66. for (int i = 0; i < hsize; ++i) htab[i] = -1;
  67. }
  68. void compress(int init_bits, OutputStream outs) throws IOException {
  69. int fcode;
  70. int i /* = 0 */;
  71. int c;
  72. int ent;
  73. int disp;
  74. int hsize_reg;
  75. int hshift;
  76. g_init_bits = init_bits;
  77. clear_flg = false;
  78. n_bits = g_init_bits;
  79. maxcode = MAXCODE(n_bits);
  80. ClearCode = 1 << (init_bits - 1);
  81. EOFCode = ClearCode + 1;
  82. free_ent = ClearCode + 2;
  83. a_count = 0;
  84. ent = nextPixel();
  85. hshift = 0;
  86. for (fcode = hsize; fcode < 65536; fcode *= 2) ++hshift;
  87. hshift = 8 - hshift;
  88. hsize_reg = hsize;
  89. cl_hash(hsize_reg);
  90. output(ClearCode, outs);
  91. outer_loop:
  92. while ((c = nextPixel()) != EOF) {
  93. fcode = (c << maxbits) + ent;
  94. i = (c << hshift) ^ ent;
  95. if (htab[i] == fcode) {
  96. ent = codetab[i];
  97. continue;
  98. } else if (htab[i] >= 0) {
  99. disp = hsize_reg - i;
  100. if (i == 0)
  101. disp = 1;
  102. do {
  103. if ((i -= disp) < 0) i += hsize_reg;
  104. if (htab[i] == fcode) {
  105. ent = codetab[i];
  106. continue outer_loop;
  107. }
  108. } while (htab[i] >= 0);
  109. }
  110. output(ent, outs);
  111. ent = c;
  112. if (free_ent < maxmaxcode) {
  113. codetab[i] = free_ent++;
  114. htab[i] = fcode;
  115. } else {
  116. cl_block(outs);
  117. }
  118. }
  119. output(ent, outs);
  120. output(EOFCode, outs);
  121. }
  122. void encode(OutputStream os) throws IOException {
  123. os.write(initCodeSize);
  124. remaining = imgW * imgH;
  125. curPixel = 0;
  126. compress(initCodeSize + 1, os);
  127. os.write(0);
  128. }
  129. void flush_char(OutputStream outs) throws IOException {
  130. if (a_count > 0) {
  131. outs.write(a_count);
  132. outs.write(accum, 0, a_count);
  133. a_count = 0;
  134. }
  135. }
  136. final int MAXCODE(int n_bits) {
  137. return (1 << n_bits) - 1;
  138. }
  139. private int nextPixel() {
  140. if (remaining == 0) return EOF;
  141. --remaining;
  142. byte pix = pixAry[curPixel++];
  143. return pix & 0xff;
  144. }
  145. void output(int code, OutputStream outs) throws IOException {
  146. cur_accum &= masks[cur_bits];
  147. if (cur_bits > 0)
  148. cur_accum |= (code << cur_bits);
  149. else
  150. cur_accum = code;
  151. cur_bits += n_bits;
  152. while (cur_bits >= 8) {
  153. char_out((byte) (cur_accum & 0xff), outs);
  154. cur_accum >>= 8;
  155. cur_bits -= 8;
  156. }
  157. if (free_ent > maxcode || clear_flg) {
  158. if (clear_flg) {
  159. maxcode = MAXCODE(n_bits = g_init_bits);
  160. clear_flg = false;
  161. } else {
  162. ++n_bits;
  163. if (n_bits == maxbits)
  164. maxcode = maxmaxcode;
  165. else
  166. maxcode = MAXCODE(n_bits);
  167. }
  168. }
  169. if (code == EOFCode) {
  170. while (cur_bits > 0) {
  171. char_out((byte) (cur_accum & 0xff), outs);
  172. cur_accum >>= 8;
  173. cur_bits -= 8;
  174. }
  175. flush_char(outs);
  176. }
  177. }
  178. }