1. /*
  2. * @(#)DHTMarkerSegment.java 1.4 03/01/23
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package com.sun.imageio.plugins.jpeg;
  8. import javax.imageio.metadata.IIOInvalidTreeException;
  9. import javax.imageio.metadata.IIOMetadataNode;
  10. import javax.imageio.stream.ImageOutputStream;
  11. import javax.imageio.plugins.jpeg.JPEGHuffmanTable;
  12. import java.io.IOException;
  13. import java.util.List;
  14. import java.util.ArrayList;
  15. import java.util.Iterator;
  16. import org.w3c.dom.Node;
  17. import org.w3c.dom.NodeList;
  18. import org.w3c.dom.NamedNodeMap;
  19. /**
  20. * A DHT (Define Huffman Table) marker segment.
  21. */
  22. class DHTMarkerSegment extends MarkerSegment {
  23. List tables = new ArrayList();
  24. DHTMarkerSegment(boolean needFour) {
  25. super(JPEG.DHT);
  26. tables.add(new Htable(JPEGHuffmanTable.StdDCLuminance, true, 0));
  27. if (needFour) {
  28. tables.add(new Htable(JPEGHuffmanTable.StdDCChrominance, true, 1));
  29. }
  30. tables.add(new Htable(JPEGHuffmanTable.StdACLuminance, false, 0));
  31. if (needFour) {
  32. tables.add(new Htable(JPEGHuffmanTable.StdACChrominance, false, 1));
  33. }
  34. }
  35. DHTMarkerSegment(JPEGBuffer buffer) throws IOException {
  36. super(buffer);
  37. int count = length;
  38. while (count > 0) {
  39. Htable newGuy = new Htable(buffer);
  40. tables.add(newGuy);
  41. count -= 1 + 16 + newGuy.values.length;
  42. }
  43. buffer.bufAvail -= length;
  44. }
  45. DHTMarkerSegment(JPEGHuffmanTable[] dcTables,
  46. JPEGHuffmanTable[] acTables) {
  47. super(JPEG.DHT);
  48. for (int i = 0; i < dcTables.length; i++) {
  49. tables.add(new Htable(dcTables[i], true, i));
  50. }
  51. for (int i = 0; i < acTables.length; i++) {
  52. tables.add(new Htable(acTables[i], false, i));
  53. }
  54. }
  55. DHTMarkerSegment(Node node) throws IIOInvalidTreeException {
  56. super(JPEG.DHT);
  57. NodeList children = node.getChildNodes();
  58. int size = children.getLength();
  59. if ((size < 1) || (size > 4)) {
  60. throw new IIOInvalidTreeException("Invalid DHT node", node);
  61. }
  62. for (int i = 0; i < size; i++) {
  63. tables.add(new Htable(children.item(i)));
  64. }
  65. }
  66. protected Object clone() {
  67. DHTMarkerSegment newGuy = (DHTMarkerSegment) super.clone();
  68. newGuy.tables = new ArrayList(tables.size());
  69. Iterator iter = tables.iterator();
  70. while (iter.hasNext()) {
  71. Htable table = (Htable) iter.next();
  72. newGuy.tables.add(table.clone());
  73. }
  74. return newGuy;
  75. }
  76. IIOMetadataNode getNativeNode() {
  77. IIOMetadataNode node = new IIOMetadataNode("dht");
  78. for (int i= 0; i<tables.size(); i++) {
  79. Htable table = (Htable) tables.get(i);
  80. node.appendChild(table.getNativeNode());
  81. }
  82. return node;
  83. }
  84. /**
  85. * Writes the data for this segment to the stream in
  86. * valid JPEG format.
  87. */
  88. void write(ImageOutputStream ios) throws IOException {
  89. // We don't write DHT segments; the IJG library does.
  90. }
  91. void print() {
  92. printTag("DHT");
  93. System.out.println("Num tables: "
  94. + Integer.toString(tables.size()));
  95. for (int i= 0; i<tables.size(); i++) {
  96. Htable table = (Htable) tables.get(i);
  97. table.print();
  98. }
  99. System.out.println();
  100. }
  101. Htable getHtableFromNode(Node node) throws IIOInvalidTreeException {
  102. return new Htable(node);
  103. }
  104. void addHtable(JPEGHuffmanTable table, boolean isDC, int id) {
  105. tables.add(new Htable(table, isDC, id));
  106. }
  107. /**
  108. * A Huffman table within a DHT marker segment.
  109. */
  110. class Htable implements Cloneable {
  111. int tableClass; // 0 == DC, 1 == AC
  112. int tableID; // 0 - 4
  113. private static final int NUM_LENGTHS = 16;
  114. // # of codes of each length
  115. short [] numCodes = new short[NUM_LENGTHS];
  116. short [] values;
  117. Htable(JPEGBuffer buffer) {
  118. tableClass = buffer.buf[buffer.bufPtr] >>> 4;
  119. tableID = buffer.buf[buffer.bufPtr++] & 0xf;
  120. for (int i = 0; i < NUM_LENGTHS; i++) {
  121. numCodes[i] = (short) (buffer.buf[buffer.bufPtr++] & 0xff);
  122. }
  123. int numValues = 0;
  124. for (int i = 0; i < NUM_LENGTHS; i++) {
  125. numValues += numCodes[i];
  126. }
  127. values = new short[numValues];
  128. for (int i = 0; i < numValues; i++) {
  129. values[i] = (short) (buffer.buf[buffer.bufPtr++] & 0xff);
  130. }
  131. }
  132. Htable(JPEGHuffmanTable table, boolean isDC, int id) {
  133. tableClass = isDC ? 0 : 1;
  134. tableID = id;
  135. numCodes = table.getLengths();
  136. values = table.getValues();
  137. }
  138. Htable(Node node) throws IIOInvalidTreeException {
  139. if (node.getNodeName().equals("dhtable")) {
  140. NamedNodeMap attrs = node.getAttributes();
  141. int count = attrs.getLength();
  142. if (count != 2) {
  143. throw new IIOInvalidTreeException
  144. ("dhtable node must have 2 attributes", node);
  145. }
  146. tableClass = getAttributeValue(node, attrs, "class", 0, 1, true);
  147. tableID = getAttributeValue(node, attrs, "htableId", 0, 3, true);
  148. if (node instanceof IIOMetadataNode) {
  149. IIOMetadataNode ourNode = (IIOMetadataNode) node;
  150. JPEGHuffmanTable table =
  151. (JPEGHuffmanTable) ourNode.getUserObject();
  152. if (table == null) {
  153. throw new IIOInvalidTreeException
  154. ("dhtable node must have user object", node);
  155. }
  156. numCodes = table.getLengths();
  157. values = table.getValues();
  158. } else {
  159. throw new IIOInvalidTreeException
  160. ("dhtable node must have user object", node);
  161. }
  162. } else {
  163. throw new IIOInvalidTreeException
  164. ("Invalid node, expected dqtable", node);
  165. }
  166. }
  167. protected Object clone() {
  168. Htable newGuy = null;
  169. try {
  170. newGuy = (Htable) super.clone();
  171. } catch (CloneNotSupportedException e) {} // won't happen
  172. if (numCodes != null) {
  173. newGuy.numCodes = (short []) numCodes.clone();
  174. }
  175. if (values != null) {
  176. newGuy.values = (short []) values.clone();
  177. }
  178. return newGuy;
  179. }
  180. IIOMetadataNode getNativeNode() {
  181. IIOMetadataNode node = new IIOMetadataNode("dhtable");
  182. node.setAttribute("class", Integer.toString(tableClass));
  183. node.setAttribute("htableId", Integer.toString(tableID));
  184. node.setUserObject(new JPEGHuffmanTable(numCodes, values));
  185. return node;
  186. }
  187. void print() {
  188. System.out.println("Huffman Table");
  189. System.out.println("table class: "
  190. + ((tableClass == 0) ? "DC":"AC"));
  191. System.out.println("table id: " + Integer.toString(tableID));
  192. (new JPEGHuffmanTable(numCodes, values)).toString();
  193. /*
  194. System.out.print("Lengths:");
  195. for (int i=0; i<16; i++) {
  196. System.out.print(" " + Integer.toString(numCodes[i]));
  197. }
  198. int count = 0;
  199. if (values.length > 16) {
  200. System.out.println("\nFirst 16 Values:");
  201. count = 16;
  202. } else {
  203. System.out.println("\nValues:");
  204. count = values.length;
  205. }
  206. for (int i=0; i<count; i++) {
  207. System.out.println(Integer.toString(values[i]&0xff));
  208. }
  209. */
  210. }
  211. }
  212. }