View Javadoc
1   /*
2    * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package com.sun.imageio.plugins.jpeg;
27  
28  import javax.imageio.metadata.IIOInvalidTreeException;
29  import javax.imageio.metadata.IIOMetadataNode;
30  import javax.imageio.stream.ImageOutputStream;
31  import javax.imageio.plugins.jpeg.JPEGHuffmanTable;
32  
33  import java.io.IOException;
34  import java.util.List;
35  import java.util.ArrayList;
36  import java.util.Iterator;
37  
38  import org.w3c.dom.Node;
39  import org.w3c.dom.NodeList;
40  import org.w3c.dom.NamedNodeMap;
41  
42  /**
43   * A DHT (Define Huffman Table) marker segment.
44   */
45  class DHTMarkerSegment extends MarkerSegment {
46      List tables = new ArrayList();
47  
48      DHTMarkerSegment(boolean needFour) {
49          super(JPEG.DHT);
50          tables.add(new Htable(JPEGHuffmanTable.StdDCLuminance, true, 0));
51          if (needFour) {
52              tables.add(new Htable(JPEGHuffmanTable.StdDCChrominance, true, 1));
53          }
54          tables.add(new Htable(JPEGHuffmanTable.StdACLuminance, false, 0));
55          if (needFour) {
56              tables.add(new Htable(JPEGHuffmanTable.StdACChrominance, false, 1));
57          }
58      }
59  
60      DHTMarkerSegment(JPEGBuffer buffer) throws IOException {
61          super(buffer);
62          int count = length;
63          while (count > 0) {
64              Htable newGuy = new Htable(buffer);
65              tables.add(newGuy);
66              count -= 1 + 16 + newGuy.values.length;
67          }
68          buffer.bufAvail -= length;
69      }
70  
71      DHTMarkerSegment(JPEGHuffmanTable[] dcTables,
72                       JPEGHuffmanTable[] acTables) {
73          super(JPEG.DHT);
74          for (int i = 0; i < dcTables.length; i++) {
75              tables.add(new Htable(dcTables[i], true, i));
76          }
77          for (int i = 0; i < acTables.length; i++) {
78              tables.add(new Htable(acTables[i], false, i));
79          }
80      }
81  
82      DHTMarkerSegment(Node node) throws IIOInvalidTreeException {
83          super(JPEG.DHT);
84          NodeList children = node.getChildNodes();
85          int size = children.getLength();
86          if ((size < 1) || (size > 4)) {
87              throw new IIOInvalidTreeException("Invalid DHT node", node);
88          }
89          for (int i = 0; i < size; i++) {
90              tables.add(new Htable(children.item(i)));
91          }
92      }
93  
94      protected Object clone() {
95          DHTMarkerSegment newGuy = (DHTMarkerSegment) super.clone();
96          newGuy.tables = new ArrayList(tables.size());
97          Iterator iter = tables.iterator();
98          while (iter.hasNext()) {
99              Htable table = (Htable) iter.next();
100             newGuy.tables.add(table.clone());
101         }
102         return newGuy;
103     }
104 
105     IIOMetadataNode getNativeNode() {
106         IIOMetadataNode node = new IIOMetadataNode("dht");
107         for (int i= 0; i<tables.size(); i++) {
108             Htable table = (Htable) tables.get(i);
109             node.appendChild(table.getNativeNode());
110         }
111         return node;
112     }
113 
114     /**
115      * Writes the data for this segment to the stream in
116      * valid JPEG format.
117      */
118     void write(ImageOutputStream ios) throws IOException {
119         // We don't write DHT segments; the IJG library does.
120     }
121 
122     void print() {
123         printTag("DHT");
124         System.out.println("Num tables: "
125                            + Integer.toString(tables.size()));
126         for (int i= 0; i<tables.size(); i++) {
127             Htable table = (Htable) tables.get(i);
128             table.print();
129         }
130         System.out.println();
131 
132     }
133 
134     Htable getHtableFromNode(Node node) throws IIOInvalidTreeException {
135         return new Htable(node);
136     }
137 
138     void addHtable(JPEGHuffmanTable table, boolean isDC, int id) {
139         tables.add(new Htable(table, isDC, id));
140     }
141 
142     /**
143      * A Huffman table within a DHT marker segment.
144      */
145     class Htable implements Cloneable {
146         int tableClass;  // 0 == DC, 1 == AC
147         int tableID; // 0 - 4
148         private static final int NUM_LENGTHS = 16;
149         // # of codes of each length
150         short [] numCodes = new short[NUM_LENGTHS];
151         short [] values;
152 
153         Htable(JPEGBuffer buffer) {
154             tableClass = buffer.buf[buffer.bufPtr] >>> 4;
155             tableID = buffer.buf[buffer.bufPtr++] & 0xf;
156             for (int i = 0; i < NUM_LENGTHS; i++) {
157                 numCodes[i] = (short) (buffer.buf[buffer.bufPtr++] & 0xff);
158             }
159 
160             int numValues = 0;
161             for (int i = 0; i < NUM_LENGTHS; i++) {
162                 numValues += numCodes[i];
163             }
164             values = new short[numValues];
165             for (int i = 0; i < numValues; i++) {
166                 values[i] = (short) (buffer.buf[buffer.bufPtr++] & 0xff);
167             }
168         }
169 
170         Htable(JPEGHuffmanTable table, boolean isDC, int id) {
171             tableClass = isDC ? 0 : 1;
172             tableID = id;
173             numCodes = table.getLengths();
174             values = table.getValues();
175         }
176 
177         Htable(Node node) throws IIOInvalidTreeException {
178             if (node.getNodeName().equals("dhtable")) {
179                 NamedNodeMap attrs = node.getAttributes();
180                 int count = attrs.getLength();
181                 if (count != 2) {
182                     throw new IIOInvalidTreeException
183                         ("dhtable node must have 2 attributes", node);
184                 }
185                 tableClass = getAttributeValue(node, attrs, "class", 0, 1, true);
186                 tableID = getAttributeValue(node, attrs, "htableId", 0, 3, true);
187                 if (node instanceof IIOMetadataNode) {
188                     IIOMetadataNode ourNode = (IIOMetadataNode) node;
189                     JPEGHuffmanTable table =
190                         (JPEGHuffmanTable) ourNode.getUserObject();
191                     if (table == null) {
192                         throw new IIOInvalidTreeException
193                             ("dhtable node must have user object", node);
194                     }
195                     numCodes = table.getLengths();
196                     values = table.getValues();
197                 } else {
198                     throw new IIOInvalidTreeException
199                         ("dhtable node must have user object", node);
200                 }
201             } else {
202                 throw new IIOInvalidTreeException
203                     ("Invalid node, expected dqtable", node);
204             }
205 
206         }
207 
208         protected Object clone() {
209             Htable newGuy = null;
210             try {
211                 newGuy = (Htable) super.clone();
212             } catch (CloneNotSupportedException e) {} // won't happen
213             if (numCodes != null) {
214                 newGuy.numCodes = (short []) numCodes.clone();
215             }
216             if (values != null) {
217                 newGuy.values = (short []) values.clone();
218             }
219             return newGuy;
220         }
221 
222         IIOMetadataNode getNativeNode() {
223             IIOMetadataNode node = new IIOMetadataNode("dhtable");
224             node.setAttribute("class", Integer.toString(tableClass));
225             node.setAttribute("htableId", Integer.toString(tableID));
226 
227             node.setUserObject(new JPEGHuffmanTable(numCodes, values));
228 
229             return node;
230         }
231 
232 
233         void print() {
234             System.out.println("Huffman Table");
235             System.out.println("table class: "
236                                + ((tableClass == 0) ? "DC":"AC"));
237             System.out.println("table id: " + Integer.toString(tableID));
238 
239             (new JPEGHuffmanTable(numCodes, values)).toString();
240             /*
241               System.out.print("Lengths:");
242               for (int i=0; i<16; i++) {
243               System.out.print(" " + Integer.toString(numCodes[i]));
244               }
245               int count = 0;
246               if (values.length > 16) {
247               System.out.println("\nFirst 16 Values:");
248               count = 16;
249               } else {
250               System.out.println("\nValues:");
251               count = values.length;
252               }
253               for (int i=0; i<count; i++) {
254               System.out.println(Integer.toString(values[i]&0xff));
255               }
256             */
257         }
258     }
259 
260 }