pixelmed
HuffmanTable.java
Go to the documentation of this file.
1 /* Copyright (c) 2014, David A. Clunie DBA Pixelmed Publishing. All rights reserved. */
2 
3 package com.pixelmed.codec.jpeg;
4 
10 public class HuffmanTable {
11 
12  private static final String identString = "@(#) $Header: /userland/cvs/codec/com/pixelmed/codec/jpeg/HuffmanTable.java,v 1.4 2014/03/23 11:41:54 dclunie Exp $";
13 
14  private int TableClass;
15  private int HuffmanTableIdentifier;
16  private int[] nHuffmanCodesOfLengthI;
17  private int[][] ValueOfHuffmanCodeIJ;
18 
19  public HuffmanTable(int TableClass,int HuffmanTableIdentifier,int[] nHuffmanCodesOfLengthI,int[][] ValueOfHuffmanCodeIJ) {
20  this.TableClass = TableClass;
21  this.HuffmanTableIdentifier = HuffmanTableIdentifier;
22  this.nHuffmanCodesOfLengthI = nHuffmanCodesOfLengthI;
23  this.ValueOfHuffmanCodeIJ = ValueOfHuffmanCodeIJ;
24  expand();
25  }
26 
27  private int countNumberOfCodes() {
28  int count=0;
29  for (int i=0; i<nHuffmanCodesOfLengthI.length; ++i) {
30  count += nHuffmanCodesOfLengthI[i];
31  }
32  return count;
33  }
34 
35  // a literal implementation of 10918-1 F.2.2.3 and figure F.15
36 
37  private int[] BITS = new int[17]; // number of codes of each size for code size I 1-16 (index 0 unused)
38 
39  private int[] HUFFVAL; // array of values in same order as encoded in ValueOfHuffmanCodeIJ with dimension nCodes + 1 to account for unused 0 index
40  private int[] HUFFSIZE;
41  private int[] HUFFCODE;
42 
43  private int[] MINCODE = new int[17]; // the smallest code value for code size I 1-16 (index 0 unused)
44  private int[] MAXCODE = new int[17]; // the largest code value for code size I 1-16 (index 0 unused)
45  private int[] VALPTR = new int[17]; // index to the start of the list of values in HUFFVAL (indexed from 1 not 0)
46 
47  public int[] getMINCODE() { return MINCODE; };
48  public int[] getMAXCODE() { return MAXCODE; };
49  public int[] getVALPTR() { return VALPTR; };
50  public int[] getHUFFVAL() { return HUFFVAL; };
51 
52  // for our redaction purposes, we need to replace AC coefficients with all zeroes (EOB), so take note of this code whilst expanding tables
53  private int EOBCode;
54  private int EOBCodeLength;
55 
56  public int getEOBCode() { return EOBCode; }
57  public int getEOBCodeLength() { return EOBCodeLength; }
58 
59 
60  private void expand() {
61 //System.err.println("HuffmanTable.expand(): class="+TableClass+" identifier="+HuffmanTableIdentifier);
62 
63  // list BITS(1..16) number of codes of each size ... is nHuffmanCodesOfLengthI(0..15)
64  for (int I=1; I<=16; ++I) {
65 //System.err.println("HuffmanTable.expand(): I="+I);
66  BITS[I] = nHuffmanCodesOfLengthI[I-1];
67  }
68 
69  int nCodes = countNumberOfCodes();
70  // HUFFVAL is a flat list of codes in the order read they are encoded in the DHT segment, which is already sorted into ascending orded
71  {
72  HUFFVAL = new int[nCodes+1];
73  int J = 0; // N.B. This is one of the few tables in ISO 10918-1 that starts with an index of zero, not one; must match VALPTR values used as indices into HUFFVAL
74  for (int i=0; i<nHuffmanCodesOfLengthI.length; ++i) {
75  int nCodesThisLength = nHuffmanCodesOfLengthI[i];
76  if (nCodesThisLength > 0) {
77  for (int j=0; j<nCodesThisLength; ++j) {
78  HUFFVAL[J] = ValueOfHuffmanCodeIJ[i][j];
79  ++J;
80  }
81  }
82  }
83  }
84 
85  // 10918-1 C.2 Figure C.1 Generate_size_table
86  // HUFFSIZE contains a list of code lengths
87  //int LASTK = 0;
88  HUFFSIZE = new int[nCodes+1];
89  {
90  int K=0;
91  int I=1;
92  int J=1;
93  while (true) {
94  if (J > BITS[I]) {
95  ++I;
96  J=1;
97  if (I > 16) {
98  HUFFSIZE[K] = 0;
99  //LASTK = K;
100  break;
101  }
102  }
103  else {
104  HUFFSIZE[K] = I;
105  ++K;
106  ++J;
107  }
108  }
109  }
110 
111  // 10918-1 C.2 Figure C.2 Generate_code_table
112  // HUFFCODE contains a code for each size in HUFFSIZE
113  HUFFCODE = new int[nCodes+1];
114  {
115  int K=0;
116  int CODE=0;
117  int SI = HUFFSIZE[0];
118  while (true) {
119  HUFFCODE[K] = CODE;
120  ++CODE;
121  ++K;
122  if (SI != HUFFSIZE[K]) {
123  if (HUFFSIZE[K] == 0) break;
124  do {
125  CODE = CODE << 1;
126  ++SI;
127  } while (SI != HUFFSIZE[K]);
128  }
129 
130  }
131  }
132 
133  // 10918-1 C.2 Figure F.15 Decoder_tables generation
134  {
135  int I=0;
136  int J=0;
137  while (true) {
138  ++I;
139  if (I > 16) break;
140  if (BITS[I] == 0) {
141  MAXCODE[I] = -1;
142  }
143  else {
144  VALPTR[I] = J;
145  MINCODE[I] = HUFFCODE[J];
146  J = J + BITS[I] - 1;
147  MAXCODE[I] = HUFFCODE[J];
148  ++J;
149  }
150  }
151  }
152 
153  // walk the arrays to find the EOB code and its length
154  {
155  for (int I=1; I<=16; ++I) {
156  for (int J = VALPTR[I]; J < VALPTR[I] + BITS[I]; ++J) {
157  if (HUFFVAL[J] == 0) { // 0x00 is the EOB code (rrrrssss == 0)
158  EOBCode = HUFFCODE[J];
159  EOBCodeLength = I;
160  }
161  }
162  }
163  }
164  }
165 
166  public String toString() {
167  StringBuffer buf = new StringBuffer();
168  buf.append("Huffman Table:\n");
169  buf.append("\t TableClass = " +TableClass+"\n");
170  buf.append("\t HuffmanTableIdentifier = "+HuffmanTableIdentifier+"\n");
171  for (int i=0; i<16; ++i) {
172  buf.append("\t\t nHuffmanCodesOfLength "+i+" = "+nHuffmanCodesOfLengthI[i]+"\n");
173  for (int j=0; j<nHuffmanCodesOfLengthI[i];++j) {
174  buf.append("\t\t\t ValueOfHuffmanCode "+j+" = "+ValueOfHuffmanCodeIJ[i][j]+"\n");
175  }
176  }
177  buf.append("\t Expanded:\n");
178  for (int I=1; I<=16; ++I) {
179  buf.append("\t\t["+I+"] MINCODE="+Integer.toBinaryString(MINCODE[I])+" MAXCODE="+Integer.toBinaryString(MAXCODE[I])+""+" VALPTR="+VALPTR[I]+"\n");
180  }
181  for (int J=0; J<HUFFVAL.length; ++J) {
182  buf.append("\t\t["+J+"] HUFFVAL=0x"+Integer.toHexString(HUFFVAL[J])+"\n");
183  }
184  buf.append("\t\tEOBCode="+Integer.toBinaryString(EOBCode)+" 0x"+Integer.toHexString(EOBCode)+" (length "+EOBCodeLength+" dec)\n");
185  return buf.toString();
186  }
187 
188 }
HuffmanTable(int TableClass, int HuffmanTableIdentifier, int[] nHuffmanCodesOfLengthI, int[][] ValueOfHuffmanCodeIJ)