- /*
- * @(#)DQTMarkerSegment.java 1.4 03/01/23
- *
- * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
- * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- */
-
- package com.sun.imageio.plugins.jpeg;
-
- import javax.imageio.IIOException;
- import javax.imageio.metadata.IIOInvalidTreeException;
- import javax.imageio.metadata.IIOMetadataNode;
- import javax.imageio.stream.ImageOutputStream;
- import javax.imageio.plugins.jpeg.JPEGQTable;
-
- import java.io.IOException;
- import java.util.List;
- import java.util.ArrayList;
- import java.util.Iterator;
-
- import org.w3c.dom.Node;
- import org.w3c.dom.NodeList;
- import org.w3c.dom.NamedNodeMap;
-
- /**
- * A DQT (Define Quantization Table) marker segment.
- */
- class DQTMarkerSegment extends MarkerSegment {
- List tables = new ArrayList(); // Could be 1 to 4
-
- DQTMarkerSegment(float quality, boolean needTwo) {
- super(JPEG.DQT);
- tables.add(new Qtable(true, quality));
- if (needTwo) {
- tables.add(new Qtable(false, quality));
- }
- }
-
- DQTMarkerSegment(JPEGBuffer buffer) throws IOException {
- super(buffer);
- int count = length;
- while (count > 0) {
- Qtable newGuy = new Qtable(buffer);
- tables.add(newGuy);
- count -= newGuy.data.length+1;
- }
- buffer.bufAvail -= length;
- }
-
- DQTMarkerSegment(JPEGQTable[] qtables) {
- super(JPEG.DQT);
- for (int i = 0; i < qtables.length; i++) {
- tables.add(new Qtable(qtables[i], i));
- }
- }
-
- DQTMarkerSegment(Node node) throws IIOInvalidTreeException {
- super(JPEG.DQT);
- NodeList children = node.getChildNodes();
- int size = children.getLength();
- if ((size < 1) || (size > 4)) {
- throw new IIOInvalidTreeException("Invalid DQT node", node);
- }
- for (int i = 0; i < size; i++) {
- tables.add(new Qtable(children.item(i)));
- }
- }
-
- protected Object clone() {
- DQTMarkerSegment newGuy = (DQTMarkerSegment) super.clone();
- newGuy.tables = new ArrayList(tables.size());
- Iterator iter = tables.iterator();
- while (iter.hasNext()) {
- Qtable table = (Qtable) iter.next();
- newGuy.tables.add(table.clone());
- }
- return newGuy;
- }
-
- IIOMetadataNode getNativeNode() {
- IIOMetadataNode node = new IIOMetadataNode("dqt");
- for (int i= 0; i<tables.size(); i++) {
- Qtable table = (Qtable) tables.get(i);
- node.appendChild(table.getNativeNode());
- }
- return node;
- }
-
- /**
- * Writes the data for this segment to the stream in
- * valid JPEG format.
- */
- void write(ImageOutputStream ios) throws IOException {
- // We don't write DQT segments; the IJG library does.
- }
-
- void print() {
- printTag("DQT");
- System.out.println("Num tables: "
- + Integer.toString(tables.size()));
- for (int i= 0; i<tables.size(); i++) {
- Qtable table = (Qtable) tables.get(i);
- table.print();
- }
- System.out.println();
- }
-
- /**
- * Assuming the given table was generated by scaling the "standard"
- * visually lossless luminance table, extract the scale factor that
- * was used.
- */
- Qtable getChromaForLuma(Qtable luma) {
- Qtable newGuy = null;
- // Determine if the table is all the same values
- // if so, use the same table
- boolean allSame = true;
- for (int i = 1; i < luma.QTABLE_SIZE; i++) {
- if (luma.data[i] != luma.data[i-1]) {
- allSame = false;
- break;
- }
- }
- if (allSame) {
- newGuy = (Qtable) luma.clone();
- newGuy.tableID = 1;
- } else {
- // Otherwise, find the largest coefficient less than 255. This is
- // the largest value that we know did not clamp on scaling.
- int largestPos = 0;
- for (int i = 1; i < luma.QTABLE_SIZE; i++) {
- if (luma.data[i] > luma.data[largestPos]) {
- largestPos = i;
- }
- }
- // Compute the scale factor by dividing it by the value in the
- // same position from the "standard" table.
- // If the given table was not generated by scaling the standard,
- // the resulting table will still be reasonable, as it will reflect
- // a comparable scaling of chrominance frequency response of the
- // eye.
- float scaleFactor = ((float)(luma.data[largestPos]))
- / ((float)(JPEGQTable.K1Div2Luminance.getTable()[largestPos]));
- // generate a new table
- JPEGQTable jpegTable =
- JPEGQTable.K2Div2Chrominance.getScaledInstance(scaleFactor,
- true);
- newGuy = new Qtable(jpegTable, 1);
- }
- return newGuy;
- }
-
- Qtable getQtableFromNode(Node node) throws IIOInvalidTreeException {
- return new Qtable(node);
- }
-
- /**
- * A quantization table within a DQT marker segment.
- */
- class Qtable implements Cloneable {
- int elementPrecision;
- int tableID;
- final int QTABLE_SIZE = 64;
- int [] data; // 64 elements, in natural order
-
- /**
- * The zigzag-order position of the i'th element
- * of a DCT block read in natural order.
- */
- private final int [] zigzag = {
- 0, 1, 5, 6, 14, 15, 27, 28,
- 2, 4, 7, 13, 16, 26, 29, 42,
- 3, 8, 12, 17, 25, 30, 41, 43,
- 9, 11, 18, 24, 31, 40, 44, 53,
- 10, 19, 23, 32, 39, 45, 52, 54,
- 20, 22, 33, 38, 46, 51, 55, 60,
- 21, 34, 37, 47, 50, 56, 59, 61,
- 35, 36, 48, 49, 57, 58, 62, 63
- };
-
- Qtable(boolean wantLuma, float quality) {
- elementPrecision = 0;
- JPEGQTable base = null;
- if (wantLuma) {
- tableID = 0;
- base = JPEGQTable.K1Div2Luminance;
- } else {
- tableID = 1;
- base = JPEGQTable.K2Div2Chrominance;
- }
- if (quality != JPEG.DEFAULT_QUALITY) {
- quality = JPEG.convertToLinearQuality(quality);
- if (wantLuma) {
- base = JPEGQTable.K1Luminance.getScaledInstance
- (quality, true);
- } else {
- base = JPEGQTable.K2Div2Chrominance.getScaledInstance
- (quality, true);
- }
- }
- data = base.getTable();
- }
-
- Qtable(JPEGBuffer buffer) throws IIOException {
- elementPrecision = buffer.buf[buffer.bufPtr] >>> 4;
- tableID = buffer.buf[buffer.bufPtr++] & 0xf;
- if (elementPrecision != 0) {
- // IJG is compiled for 8-bits, so this shouldn't happen
- throw new IIOException ("Unsupported element precision");
- }
- data = new int [QTABLE_SIZE];
- // Read from zig-zag order to natural order
- for (int i = 0; i < QTABLE_SIZE; i++) {
- data[i] = buffer.buf[buffer.bufPtr+zigzag[i]] & 0xff;
- }
- buffer.bufPtr += QTABLE_SIZE;
- }
-
- Qtable(JPEGQTable table, int id) {
- elementPrecision = 0;
- tableID = id;
- data = table.getTable();
- }
-
- Qtable(Node node) throws IIOInvalidTreeException {
- if (node.getNodeName().equals("dqtable")) {
- NamedNodeMap attrs = node.getAttributes();
- int count = attrs.getLength();
- if ((count < 1) || (count > 2)) {
- throw new IIOInvalidTreeException
- ("dqtable node must have 1 or 2 attributes", node);
- }
- elementPrecision = 0;
- tableID = getAttributeValue(node, attrs, "qtableId", 0, 3, true);
- if (node instanceof IIOMetadataNode) {
- IIOMetadataNode ourNode = (IIOMetadataNode) node;
- JPEGQTable table = (JPEGQTable) ourNode.getUserObject();
- if (table == null) {
- throw new IIOInvalidTreeException
- ("dqtable node must have user object", node);
- }
- data = table.getTable();
- } else {
- throw new IIOInvalidTreeException
- ("dqtable node must have user object", node);
- }
- } else {
- throw new IIOInvalidTreeException
- ("Invalid node, expected dqtable", node);
- }
- }
-
- protected Object clone() {
- Qtable newGuy = null;
- try {
- newGuy = (Qtable) super.clone();
- } catch (CloneNotSupportedException e) {} // won't happen
- if (data != null) {
- newGuy.data = (int []) data.clone();
- }
- return newGuy;
- }
-
- IIOMetadataNode getNativeNode() {
- IIOMetadataNode node = new IIOMetadataNode("dqtable");
- node.setAttribute("elementPrecision",
- Integer.toString(elementPrecision));
- node.setAttribute("qtableId",
- Integer.toString(tableID));
- node.setUserObject(new JPEGQTable(data));
- return node;
- }
-
- void print() {
- System.out.println("Table id: " + Integer.toString(tableID));
- System.out.println("Element precision: "
- + Integer.toString(elementPrecision));
-
- (new JPEGQTable(data)).toString();
- /*
- for (int i = 0; i < 64; i++) {
- if (i % 8 == 0) {
- System.out.println();
- }
- System.out.print(" " + Integer.toString(data[i]));
- }
- System.out.println();
- */
- }
- }
- }
-