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.5 2020/03/28 21:05:39 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  public int[] getHUFFSIZE() { return HUFFSIZE; };
52 
53  private int[] EFUFCO;
54  private int[] EFUFSI;
55 
56  public int[] getEFUFCO() { return EFUFCO; };
57  public int[] getEFUFSI() { return EFUFSI; };
58 
59  // for our redaction purposes, we need to replace AC coefficients with all zeroes (EOB), so take note of what this code is whilst expanding tables
60  private int EOBCode;
61  private int EOBCodeLength;
62 
63  public int getEOBCode() { return EOBCode; }
64  public int getEOBCodeLength() { return EOBCodeLength; }
65 
66 
67  private void expand() {
68 //System.err.println("HuffmanTable.expand(): class="+TableClass+" identifier="+HuffmanTableIdentifier);
69 
70  // list BITS(1..16) number of codes of each size ... is nHuffmanCodesOfLengthI(0..15)
71  for (int I=1; I<=16; ++I) {
72 //System.err.println("HuffmanTable.expand(): I="+I);
73  BITS[I] = nHuffmanCodesOfLengthI[I-1];
74  }
75 
76  int nCodes = countNumberOfCodes();
77  int largestValue = 0;
78  // HUFFVAL is a flat list of codes in the order read they are encoded in the DHT segment, which is already sorted into ascending order
79  {
80  HUFFVAL = new int[nCodes];
81 
82  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
83  for (int i=0; i<nHuffmanCodesOfLengthI.length; ++i) {
84  int nCodesThisLength = nHuffmanCodesOfLengthI[i];
85  if (nCodesThisLength > 0) {
86  for (int j=0; j<nCodesThisLength; ++j) {
87  HUFFVAL[J] = ValueOfHuffmanCodeIJ[i][j];
88  if (HUFFVAL[J] > largestValue) {
89  largestValue = HUFFVAL[J];
90  }
91  ++J;
92  }
93  }
94  }
95  }
96 
97  // 10918-1 C.2 Figure C.1 Generate_size_table
98  // HUFFSIZE contains a list of code lengths
99  //int LASTK = 0;
100  HUFFSIZE = new int[nCodes+1];
101  {
102  int K=0;
103  int I=1;
104  int J=1;
105  while (true) {
106  if (J > BITS[I]) {
107  ++I;
108  J=1;
109  if (I > 16) {
110  HUFFSIZE[K] = 0;
111  //LASTK = K;
112  break;
113  }
114  }
115  else {
116  HUFFSIZE[K] = I;
117  ++K;
118  ++J;
119  }
120  }
121  }
122 
123  // 10918-1 C.2 Figure C.2 Generate_code_table
124  // HUFFCODE contains a code for each size in HUFFSIZE
125  HUFFCODE = new int[nCodes+1];
126  {
127  int K=0;
128  int CODE=0;
129  int SI = HUFFSIZE[0];
130  while (true) {
131  HUFFCODE[K] = CODE;
132  ++CODE;
133  ++K;
134  if (SI != HUFFSIZE[K]) {
135  if (HUFFSIZE[K] == 0) break;
136  do {
137  CODE = CODE << 1;
138  ++SI;
139  } while (SI != HUFFSIZE[K]);
140  }
141 
142  }
143  }
144 
145  // 10918-1 C.2 Figure C.3 Order_codes (for encoding)
146  // EFUFCO contains a code for each value in HUFFVAL
147  // EFUFSI contains a size for each value in HUFFVAL
148  EFUFCO = new int[largestValue+1];
149  EFUFSI = new int[largestValue+1];
150  {
151  for (int K=0; K<HUFFVAL.length; ++K) {
152  int I = HUFFVAL[K];
153  EFUFCO[I] = HUFFCODE[K];
154  EFUFSI[I] = HUFFSIZE[K];
155 //System.err.println("HUFFVAL[K] "+HUFFVAL[K]+" EFUFCO[I] "+Integer.toBinaryString(EFUFCO[I])+" EFUFSI[I] "+Integer.toBinaryString(EFUFSI[I]));
156  }
157  }
158 
159  // 10918-1 C.2 Figure F.15 Decoder_tables generation
160  {
161  int I=0;
162  int J=0;
163  while (true) {
164  ++I;
165  if (I > 16) break;
166  if (BITS[I] == 0) {
167  MAXCODE[I] = -1;
168  }
169  else {
170  VALPTR[I] = J;
171  MINCODE[I] = HUFFCODE[J];
172  J = J + BITS[I] - 1;
173  MAXCODE[I] = HUFFCODE[J];
174  ++J;
175  }
176  }
177  }
178 
179  // walk the arrays to find the EOB code and its length
180  {
181  for (int I=1; I<=16; ++I) {
182  for (int J = VALPTR[I]; J < VALPTR[I] + BITS[I]; ++J) {
183  if (HUFFVAL[J] == 0) { // 0x00 is the EOB code (rrrrssss == 0)
184  EOBCode = HUFFCODE[J];
185  EOBCodeLength = I;
186  }
187  }
188  }
189  }
190  }
191 
192  public String toString() {
193  StringBuffer buf = new StringBuffer();
194  buf.append("Huffman Table:\n");
195  buf.append("\t TableClass = " +TableClass+"\n");
196  buf.append("\t HuffmanTableIdentifier = "+HuffmanTableIdentifier+"\n");
197  for (int i=0; i<16; ++i) {
198  buf.append("\t\t nHuffmanCodesOfLength "+i+" = "+nHuffmanCodesOfLengthI[i]+"\n");
199  for (int j=0; j<nHuffmanCodesOfLengthI[i];++j) {
200  buf.append("\t\t\t ValueOfHuffmanCode "+j+" = "+ValueOfHuffmanCodeIJ[i][j]+"\n");
201  }
202  }
203  buf.append("\t Expanded:\n");
204  for (int I=1; I<=16; ++I) {
205  buf.append("\t\t["+I+"] MINCODE="+Integer.toBinaryString(MINCODE[I])+" MAXCODE="+Integer.toBinaryString(MAXCODE[I])+""+" VALPTR="+VALPTR[I]+"\n");
206  }
207  for (int J=0; J<HUFFVAL.length; ++J) {
208  buf.append("\t\t["+J+"] HUFFVAL=0x"+Integer.toHexString(HUFFVAL[J])+"\n");
209  }
210  buf.append("\t\tEOBCode="+Integer.toBinaryString(EOBCode)+" 0x"+Integer.toHexString(EOBCode)+" (length "+EOBCodeLength+" dec)\n");
211  return buf.toString();
212  }
213 
214 }
com.pixelmed.codec.jpeg.HuffmanTable.getHUFFVAL
int[] getHUFFVAL()
Definition: HuffmanTable.java:50
com.pixelmed.codec.jpeg.HuffmanTable.getVALPTR
int[] getVALPTR()
Definition: HuffmanTable.java:49
com.pixelmed.codec.jpeg.HuffmanTable
Definition: HuffmanTable.java:10
com.pixelmed.codec.jpeg.HuffmanTable.getMAXCODE
int[] getMAXCODE()
Definition: HuffmanTable.java:48
com.pixelmed.codec.jpeg.HuffmanTable.getMINCODE
int[] getMINCODE()
Definition: HuffmanTable.java:47
com.pixelmed.codec.jpeg.HuffmanTable.getEFUFSI
int[] getEFUFSI()
Definition: HuffmanTable.java:57
com.pixelmed.codec.jpeg.HuffmanTable.getEFUFCO
int[] getEFUFCO()
Definition: HuffmanTable.java:56
com.pixelmed.codec.jpeg.HuffmanTable.HuffmanTable
HuffmanTable(int TableClass, int HuffmanTableIdentifier, int[] nHuffmanCodesOfLengthI, int[][] ValueOfHuffmanCodeIJ)
Definition: HuffmanTable.java:19
com.pixelmed.codec.jpeg.HuffmanTable.getEOBCodeLength
int getEOBCodeLength()
Definition: HuffmanTable.java:64
com.pixelmed.codec.jpeg.HuffmanTable.getEOBCode
int getEOBCode()
Definition: HuffmanTable.java:63
com.pixelmed.codec.jpeg.HuffmanTable.getHUFFSIZE
int[] getHUFFSIZE()
Definition: HuffmanTable.java:51
com.pixelmed.codec.jpeg.HuffmanTable.toString
String toString()
Definition: HuffmanTable.java:192