1 /* 2 * Copyright (c) 2001, 2014, 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<Htable> 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 DHTMarkerSegment clone() { 95 DHTMarkerSegment newGuy = (DHTMarkerSegment) super.clone(); 96 newGuy.tables = new ArrayList<>(tables.size()); 97 Iterator<Htable> iter = tables.iterator(); 98 while (iter.hasNext()) { 99 Htable table = 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 = 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 = 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 Htable 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 = numCodes.clone(); 215 } 216 if (values != null) { 217 newGuy.values = 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 }