/* * Copyright (c) 2001, 2004, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.imageio.plugins.jpeg; import javax.imageio.ImageTypeSpecifier;import javax.imageio.ImageWriteParam;import javax.imageio.IIOException;import javax.imageio.stream.ImageInputStream;import javax.imageio.stream.ImageOutputStream;import javax.imageio.metadata.IIOMetadata;import javax.imageio.metadata.IIOMetadataNode;import javax.imageio.metadata.IIOMetadataFormat;import javax.imageio.metadata.IIOMetadataFormatImpl;import javax.imageio.metadata.IIOInvalidTreeException;import javax.imageio.plugins.jpeg.JPEGQTable;import javax.imageio.plugins.jpeg.JPEGHuffmanTable;import javax.imageio.plugins.jpeg.JPEGImageWriteParam; import org.w3c.dom.Node;import org.w3c.dom.NodeList;import org.w3c.dom.NamedNodeMap; import java.util.List;import java.util.ArrayList;import java.util.Arrays;import java.util.Iterator;import java.util.ListIterator;import java.io.IOException;import java.awt.color.ICC_Profile;import java.awt.color.ICC_ColorSpace;import java.awt.color.ColorSpace;import java.awt.image.ColorModel;import java.awt.Point; /** * Metadata for the JPEG plug-in. */public class JPEGMetadata extends IIOMetadata implements Cloneable { //////// Private variables private static final boolean debug = false; /** * A copy of <code>markerSequence</code>, created the first time the * <code>markerSequence</code> is modified. This is used by reset * to restore the original state. */ private List resetSequence = null; /** * Set to <code>true</code> when reading a thumbnail stored as * JPEG. This is used to enforce the prohibition of JFIF thumbnails * containing any JFIF marker segments, and to ensure generation of * a correct native subtree during <code>getAsTree</code>. */ private boolean inThumb = false; /** * Set by the chroma node construction method to signal the * presence or absence of an alpha channel to the transparency * node construction method. Used only when constructing a * standard metadata tree. */ private boolean hasAlpha; //////// end of private variables /////// Package-access variables /** * All data is a list of <code>MarkerSegment</code> objects. * When accessing the list, use the tag to identify the particular * subclass. Any JFIF marker segment must be the first element * of the list if it is present, and any JFXX or APP2ICC marker * segments are subordinate to the JFIF marker segment. This * list is package visible so that the writer can access it. * @see #MarkerSegment */ List markerSequence = new ArrayList(); /** * Indicates whether this object represents stream or image * metadata. Package-visible so the writer can see it. */ final boolean isStream; /////// End of package-access variables /////// Constructors /** * Constructor containing code shared by other constructors. */ JPEGMetadata(boolean isStream, boolean inThumb) { super(true, // Supports standard format JPEG.nativeImageMetadataFormatName, // and a native format JPEG.nativeImageMetadataFormatClassName, null, null); // No other formats this.inThumb = inThumb; // But if we are stream metadata, adjust the variables this.isStream = isStream; if (isStream) { nativeMetadataFormatName = JPEG.nativeStreamMetadataFormatName; nativeMetadataFormatClassName = JPEG.nativeStreamMetadataFormatClassName; } } /* * Constructs a <code>JPEGMetadata</code> object by reading the * contents of an <code>ImageInputStream</code>. Has package-only * access. * * @param isStream A boolean indicating whether this object will be * stream or image metadata. * @param isThumb A boolean indicating whether this metadata object * is for an image or for a thumbnail stored as JPEG. * @param iis An <code>ImageInputStream</code> from which to read * the metadata. * @param reader The <code>JPEGImageReader</code> calling this * constructor, to which warnings should be sent. */ JPEGMetadata(boolean isStream, boolean isThumb, ImageInputStream iis, JPEGImageReader reader) throws IOException { this(isStream, isThumb); JPEGBuffer buffer = new JPEGBuffer(iis); buffer.loadBuf(0); // The first three bytes should be FF, SOI, FF if (((buffer.buf[0] & 0xff) != 0xff) || ((buffer.buf[1] & 0xff) != JPEG.SOI) || ((buffer.buf[2] & 0xff) != 0xff)) { throw new IIOException ("Image format error"); } boolean done = false; buffer.bufAvail -=2; // Next byte should be the ff before a marker buffer.bufPtr = 2; MarkerSegment newGuy = null; while (!done) { byte [] buf; int ptr; buffer.loadBuf(1); if (debug) { System.out.println("top of loop"); buffer.print(10); } buffer.scanForFF(reader); switch (buffer.buf[buffer.bufPtr] & 0xff) { case 0: if (debug) { System.out.println("Skipping 0"); } buffer.bufAvail--; buffer.bufPtr++; break; case JPEG.SOF0: case JPEG.SOF1: case JPEG.SOF2: if (isStream) { throw new IIOException ("SOF not permitted in stream metadata"); } newGuy = new SOFMarkerSegment(buffer); break; case JPEG.DQT: newGuy = new DQTMarkerSegment(buffer); break; case JPEG.DHT: newGuy = new DHTMarkerSegment(buffer); break; case JPEG.DRI: newGuy = new DRIMarkerSegment(buffer); break; case JPEG.APP0: // Either JFIF, JFXX, or unknown APP0 buffer.loadBuf(8); // tag, length, id buf = buffer.buf; ptr = buffer.bufPtr; if ((buf[ptr+3] == 'J') && (buf[ptr+4] == 'F') && (buf[ptr+5] == 'I') && (buf[ptr+6] == 'F') && (buf[ptr+7] == 0)) { if (inThumb) { reader.warningOccurred (JPEGImageReader.WARNING_NO_JFIF_IN_THUMB); // Leave newGuy null // Read a dummy to skip the segment JFIFMarkerSegment dummy = new JFIFMarkerSegment(buffer); } else if (isStream) { throw new IIOException ("JFIF not permitted in stream metadata"); } else if (markerSequence.isEmpty() == false) { throw new IIOException ("JFIF APP0 must be first marker after SOI"); } else { newGuy = new JFIFMarkerSegment(buffer); } } else if ((buf[ptr+3] == 'J') && (buf[ptr+4] == 'F') && (buf[ptr+5] == 'X') && (buf[ptr+6] == 'X') && (buf[ptr+7] == 0)) { if (isStream) { throw new IIOException ("JFXX not permitted in stream metadata"); } if (inThumb) { throw new IIOException ("JFXX markers not allowed in JFIF JPEG thumbnail"); } JFIFMarkerSegment jfif = (JFIFMarkerSegment) findMarkerSegment (JFIFMarkerSegment.class, true); if (jfif == null) { throw new IIOException ("JFXX encountered without prior JFIF!"); } jfif.addJFXX(buffer, reader); // newGuy remains null } else { newGuy = new MarkerSegment(buffer); newGuy.loadData(buffer); } break; case JPEG.APP2: // Either an ICC profile or unknown APP2 buffer.loadBuf(15); // tag, length, id if ((buffer.buf[buffer.bufPtr+3] == 'I') && (buffer.buf[buffer.bufPtr+4] == 'C') && (buffer.buf[buffer.bufPtr+5] == 'C') && (buffer.buf[buffer.bufPtr+6] == '_') && (buffer.buf[buffer.bufPtr+7] == 'P') && (buffer.buf[buffer.bufPtr+8] == 'R') && (buffer.buf[buffer.bufPtr+9] == 'O') && (buffer.buf[buffer.bufPtr+10] == 'F') && (buffer.buf[buffer.bufPtr+11] == 'I') && (buffer.buf[buffer.bufPtr+12] == 'L') && (buffer.buf[buffer.bufPtr+13] == 'E') && (buffer.buf[buffer.bufPtr+14] == 0) ) { if (isStream) { throw new IIOException ("ICC profiles not permitted in stream metadata"); } JFIFMarkerSegment jfif = (JFIFMarkerSegment) findMarkerSegment (JFIFMarkerSegment.class, true); if (jfif == null) { throw new IIOException ("ICC APP2 encountered without prior JFIF!"); } jfif.addICC(buffer); // newGuy remains null } else { newGuy = new MarkerSegment(buffer); newGuy.loadData(buffer); } break; case JPEG.APP14: // Either Adobe or unknown APP14 buffer.loadBuf(8); // tag, length, id if ((buffer.buf[buffer.bufPtr+3] == 'A') && (buffer.buf[buffer.bufPtr+4] == 'd') && (buffer.buf[buffer.bufPtr+5] == 'o') && (buffer.buf[buffer.bufPtr+6] == 'b') && (buffer.buf[buffer.bufPtr+7] == 'e')) { if (isStream) { throw new IIOException ("Adobe APP14 markers not permitted in stream metadata"); } newGuy = new AdobeMarkerSegment(buffer); } else { newGuy = new MarkerSegment(buffer); newGuy.loadData(buffer); } break; case JPEG.COM: newGuy = new COMMarkerSegment(buffer); break; case JPEG.SOS: if (isStream) { throw new IIOException ("SOS not permitted in stream metadata"); } newGuy = new SOSMarkerSegment(buffer); break; case JPEG.RST0: case JPEG.RST1: case JPEG.RST2: case JPEG.RST3: case JPEG.RST4: case JPEG.RST5: case JPEG.RST6: case JPEG.RST7: if (debug) { System.out.println("Restart Marker"); } buffer.bufPtr++; // Just skip it buffer.bufAvail--; break; case JPEG.EOI: done = true; buffer.bufPtr++; buffer.bufAvail--; break; default: newGuy = new MarkerSegment(buffer); newGuy.loadData(buffer); newGuy.unknown = true; break; } if (newGuy != null) { markerSequence.add(newGuy); if (debug) { newGuy.print(); } newGuy = null; } } // Now that we've read up to the EOI, we need to push back // whatever is left in the buffer, so that the next read // in the native code will work. buffer.pushBack(); if (!isConsistent()) { throw new IIOException("Inconsistent metadata read from stream"); } } /** * Constructs a default stream <code>JPEGMetadata</code> object appropriate * for the given write parameters. */ JPEGMetadata(ImageWriteParam param, JPEGImageWriter writer) { this(true, false); JPEGImageWriteParam jparam = null; if ((param != null) && (param instanceof JPEGImageWriteParam)) { jparam = (JPEGImageWriteParam) param; if (!jparam.areTablesSet()) { jparam = null; } } if (jparam != null) { markerSequence.add(new DQTMarkerSegment(jparam.getQTables())); markerSequence.add (new DHTMarkerSegment(jparam.getDCHuffmanTables(), jparam.getACHuffmanTables())); } else { // default tables. markerSequence.add(new DQTMarkerSegment(JPEG.getDefaultQTables())); markerSequence.add(new DHTMarkerSegment(JPEG.getDefaultHuffmanTables(true), JPEG.getDefaultHuffmanTables(false))); } // Defensive programming if (!isConsistent()) { throw new InternalError("Default stream metadata is inconsistent"); } } /** * Constructs a default image <code>JPEGMetadata</code> object appropriate * for the given image type and write parameters. */ JPEGMetadata(ImageTypeSpecifier imageType, ImageWriteParam param, JPEGImageWriter writer) { this(false, false); boolean wantJFIF = true; boolean wantAdobe = false; int transform = JPEG.ADOBE_UNKNOWN; boolean willSubsample = true; boolean wantICC = false; boolean wantProg = false; boolean wantOptimized = false; boolean wantExtended = false; boolean wantQTables = true; boolean wantHTables = true; float quality = JPEG.DEFAULT_QUALITY; byte[] componentIDs = { 1, 2, 3, 4}; int numComponents = 0; ImageTypeSpecifier destType = null; if (param != null) { destType = param.getDestinationType(); if (destType != null) { if (imageType != null) { // Ignore the destination type. writer.warningOccurred (JPEGImageWriter.WARNING_DEST_IGNORED); destType = null; } } // The only progressive mode that makes sense here is MODE_DEFAULT if (param.canWriteProgressive()) { // the param may not be one of ours, so it may return false. // If so, the following would throw an exception if (param.getProgressiveMode() == ImageWriteParam.MODE_DEFAULT) { wantProg = true; wantOptimized = true; wantHTables = false; } } if (param instanceof JPEGImageWriteParam) { JPEGImageWriteParam jparam = (JPEGImageWriteParam) param; if (jparam.areTablesSet()) { wantQTables = false; // If the param has them, metadata shouldn't wantHTables = false; if ((jparam.getDCHuffmanTables().length > 2) || (jparam.getACHuffmanTables().length > 2)) { wantExtended = true; } } // Progressive forces optimized, regardless of param setting // so consult the param re optimized only if not progressive if (!wantProg) { wantOptimized = jparam.getOptimizeHuffmanTables(); if (wantOptimized) { wantHTables = false; } } } // compression quality should determine the q tables. Note that this // will be ignored if we already decided not to create any. // Again, the param may not be one of ours, so we must check that it // supports compression settings if (param.canWriteCompressed()) { if (param.getCompressionMode() == ImageWriteParam.MODE_EXPLICIT) { quality = param.getCompressionQuality(); } } } // We are done with the param, now for the image types ColorSpace cs = null; if (destType != null) { ColorModel cm = destType.getColorModel(); numComponents = cm.getNumComponents(); boolean hasExtraComponents = (cm.getNumColorComponents() != numComponents); boolean hasAlpha = cm.hasAlpha(); cs = cm.getColorSpace(); int type = cs.getType(); switch(type) { case ColorSpace.TYPE_GRAY: willSubsample = false; if (hasExtraComponents) { // e.g. alpha wantJFIF = false; } break; case ColorSpace.TYPE_3CLR: if (cs == JPEG.JCS.getYCC()) { wantJFIF = false; componentIDs[0] = (byte) 'Y'; componentIDs[1] = (byte) 'C'; componentIDs[2] = (byte) 'c'; if (hasAlpha) { componentIDs[3] = (byte) 'A'; }Lines 1–500 of 2416. Load more
/* * Copyright (c) 2001, 2004, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.imageio.plugins.jpeg; import javax.imageio.ImageTypeSpecifier; import javax.imageio.ImageWriteParam; import javax.imageio.IIOException; import javax.imageio.stream.ImageInputStream; import javax.imageio.stream.ImageOutputStream; import javax.imageio.metadata.IIOMetadata; import javax.imageio.metadata.IIOMetadataNode; import javax.imageio.metadata.IIOMetadataFormat; import javax.imageio.metadata.IIOMetadataFormatImpl; import javax.imageio.metadata.IIOInvalidTreeException; import javax.imageio.plugins.jpeg.JPEGQTable; import javax.imageio.plugins.jpeg.JPEGHuffmanTable; import javax.imageio.plugins.jpeg.JPEGImageWriteParam; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.w3c.dom.NamedNodeMap; import java.util.List; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.ListIterator; import java.io.IOException; import java.awt.color.ICC_Profile; import java.awt.color.ICC_ColorSpace; import java.awt.color.ColorSpace; import java.awt.image.ColorModel; import java.awt.Point; /** * Metadata for the JPEG plug-in. */ public class JPEGMetadata extends IIOMetadata implements Cloneable { //////// Private variables private static final boolean debug = false; /** * A copy of <code>markerSequence</code>, created the first time the * <code>markerSequence</code> is modified. This is used by reset * to restore the original state. */ private List resetSequence = null; /** * Set to <code>true</code> when reading a thumbnail stored as * JPEG. This is used to enforce the prohibition of JFIF thumbnails * containing any JFIF marker segments, and to ensure generation of * a correct native subtree during <code>getAsTree</code>. */ private boolean inThumb = false; /** * Set by the chroma node construction method to signal the * presence or absence of an alpha channel to the transparency * node construction method. Used only when constructing a * standard metadata tree. */ private boolean hasAlpha; //////// end of private variables /////// Package-access variables /** * All data is a list of <code>MarkerSegment</code> objects. * When accessing the list, use the tag to identify the particular * subclass. Any JFIF marker segment must be the first element * of the list if it is present, and any JFXX or APP2ICC marker * segments are subordinate to the JFIF marker segment. This * list is package visible so that the writer can access it. * @see #MarkerSegment */ List markerSequence = new ArrayList(); /** * Indicates whether this object represents stream or image * metadata. Package-visible so the writer can see it. */ final boolean isStream; /////// End of package-access variables /////// Constructors /** * Constructor containing code shared by other constructors. */ JPEGMetadata(boolean isStream, boolean inThumb) { super(true, // Supports standard format JPEG.nativeImageMetadataFormatName, // and a native format JPEG.nativeImageMetadataFormatClassName, null, null); // No other formats this.inThumb = inThumb; // But if we are stream metadata, adjust the variables this.isStream = isStream; if (isStream) { nativeMetadataFormatName = JPEG.nativeStreamMetadataFormatName; nativeMetadataFormatClassName = JPEG.nativeStreamMetadataFormatClassName; } } /* * Constructs a <code>JPEGMetadata</code> object by reading the * contents of an <code>ImageInputStream</code>. Has package-only * access. * * @param isStream A boolean indicating whether this object will be * stream or image metadata. * @param isThumb A boolean indicating whether this metadata object * is for an image or for a thumbnail stored as JPEG. * @param iis An <code>ImageInputStream</code> from which to read * the metadata. * @param reader The <code>JPEGImageReader</code> calling this * constructor, to which warnings should be sent. */ JPEGMetadata(boolean isStream, boolean isThumb, ImageInputStream iis, JPEGImageReader reader) throws IOException { this(isStream, isThumb); JPEGBuffer buffer = new JPEGBuffer(iis); buffer.loadBuf(0); // The first three bytes should be FF, SOI, FF if (((buffer.buf[0] & 0xff) != 0xff) || ((buffer.buf[1] & 0xff) != JPEG.SOI) || ((buffer.buf[2] & 0xff) != 0xff)) { throw new IIOException ("Image format error"); } boolean done = false; buffer.bufAvail -=2; // Next byte should be the ff before a marker buffer.bufPtr = 2; MarkerSegment newGuy = null; while (!done) { byte [] buf; int ptr; buffer.loadBuf(1); if (debug) { System.out.println("top of loop"); buffer.print(10); } buffer.scanForFF(reader); switch (buffer.buf[buffer.bufPtr] & 0xff) { case 0: if (debug) { System.out.println("Skipping 0"); } buffer.bufAvail--; buffer.bufPtr++; break; case JPEG.SOF0: case JPEG.SOF1: case JPEG.SOF2: if (isStream) { throw new IIOException ("SOF not permitted in stream metadata"); } newGuy = new SOFMarkerSegment(buffer); break; case JPEG.DQT: newGuy = new DQTMarkerSegment(buffer); break; case JPEG.DHT: newGuy = new DHTMarkerSegment(buffer); break; case JPEG.DRI: newGuy = new DRIMarkerSegment(buffer); break; case JPEG.APP0: // Either JFIF, JFXX, or unknown APP0 buffer.loadBuf(8); // tag, length, id buf = buffer.buf; ptr = buffer.bufPtr; if ((buf[ptr+3] == 'J') && (buf[ptr+4] == 'F') && (buf[ptr+5] == 'I') && (buf[ptr+6] == 'F') && (buf[ptr+7] == 0)) { if (inThumb) { reader.warningOccurred (JPEGImageReader.WARNING_NO_JFIF_IN_THUMB); // Leave newGuy null // Read a dummy to skip the segment JFIFMarkerSegment dummy = new JFIFMarkerSegment(buffer); } else if (isStream) { throw new IIOException ("JFIF not permitted in stream metadata"); } else if (markerSequence.isEmpty() == false) { throw new IIOException ("JFIF APP0 must be first marker after SOI"); } else { newGuy = new JFIFMarkerSegment(buffer); } } else if ((buf[ptr+3] == 'J') && (buf[ptr+4] == 'F') && (buf[ptr+5] == 'X') && (buf[ptr+6] == 'X') && (buf[ptr+7] == 0)) { if (isStream) { throw new IIOException ("JFXX not permitted in stream metadata"); } if (inThumb) { throw new IIOException ("JFXX markers not allowed in JFIF JPEG thumbnail"); } JFIFMarkerSegment jfif = (JFIFMarkerSegment) findMarkerSegment (JFIFMarkerSegment.class, true); if (jfif == null) { throw new IIOException ("JFXX encountered without prior JFIF!"); } jfif.addJFXX(buffer, reader); // newGuy remains null } else { newGuy = new MarkerSegment(buffer); newGuy.loadData(buffer); } break; case JPEG.APP2: // Either an ICC profile or unknown APP2 buffer.loadBuf(15); // tag, length, id if ((buffer.buf[buffer.bufPtr+3] == 'I') && (buffer.buf[buffer.bufPtr+4] == 'C') && (buffer.buf[buffer.bufPtr+5] == 'C') && (buffer.buf[buffer.bufPtr+6] == '_') && (buffer.buf[buffer.bufPtr+7] == 'P') && (buffer.buf[buffer.bufPtr+8] == 'R') && (buffer.buf[buffer.bufPtr+9] == 'O') && (buffer.buf[buffer.bufPtr+10] == 'F') && (buffer.buf[buffer.bufPtr+11] == 'I') && (buffer.buf[buffer.bufPtr+12] == 'L') && (buffer.buf[buffer.bufPtr+13] == 'E') && (buffer.buf[buffer.bufPtr+14] == 0) ) { if (isStream) { throw new IIOException ("ICC profiles not permitted in stream metadata"); } JFIFMarkerSegment jfif = (JFIFMarkerSegment) findMarkerSegment (JFIFMarkerSegment.class, true); if (jfif == null) { throw new IIOException ("ICC APP2 encountered without prior JFIF!"); } jfif.addICC(buffer); // newGuy remains null } else { newGuy = new MarkerSegment(buffer); newGuy.loadData(buffer); } break; case JPEG.APP14: // Either Adobe or unknown APP14 buffer.loadBuf(8); // tag, length, id if ((buffer.buf[buffer.bufPtr+3] == 'A') && (buffer.buf[buffer.bufPtr+4] == 'd') && (buffer.buf[buffer.bufPtr+5] == 'o') && (buffer.buf[buffer.bufPtr+6] == 'b') && (buffer.buf[buffer.bufPtr+7] == 'e')) { if (isStream) { throw new IIOException ("Adobe APP14 markers not permitted in stream metadata"); } newGuy = new AdobeMarkerSegment(buffer); } else { newGuy = new MarkerSegment(buffer); newGuy.loadData(buffer); } break; case JPEG.COM: newGuy = new COMMarkerSegment(buffer); break; case JPEG.SOS: if (isStream) { throw new IIOException ("SOS not permitted in stream metadata"); } newGuy = new SOSMarkerSegment(buffer); break; case JPEG.RST0: case JPEG.RST1: case JPEG.RST2: case JPEG.RST3: case JPEG.RST4: case JPEG.RST5: case JPEG.RST6: case JPEG.RST7: if (debug) { System.out.println("Restart Marker"); } buffer.bufPtr++; // Just skip it buffer.bufAvail--; break; case JPEG.EOI: done = true; buffer.bufPtr++; buffer.bufAvail--; break; default: newGuy = new MarkerSegment(buffer); newGuy.loadData(buffer); newGuy.unknown = true; break; } if (newGuy != null) { markerSequence.add(newGuy); if (debug) { newGuy.print(); } newGuy = null; } } // Now that we've read up to the EOI, we need to push back // whatever is left in the buffer, so that the next read // in the native code will work. buffer.pushBack(); if (!isConsistent()) { throw new IIOException("Inconsistent metadata read from stream"); } } /** * Constructs a default stream <code>JPEGMetadata</code> object appropriate * for the given write parameters. */ JPEGMetadata(ImageWriteParam param, JPEGImageWriter writer) { this(true, false); JPEGImageWriteParam jparam = null; if ((param != null) && (param instanceof JPEGImageWriteParam)) { jparam = (JPEGImageWriteParam) param; if (!jparam.areTablesSet()) { jparam = null; } } if (jparam != null) { markerSequence.add(new DQTMarkerSegment(jparam.getQTables())); markerSequence.add (new DHTMarkerSegment(jparam.getDCHuffmanTables(), jparam.getACHuffmanTables())); } else { // default tables. markerSequence.add(new DQTMarkerSegment(JPEG.getDefaultQTables())); markerSequence.add(new DHTMarkerSegment(JPEG.getDefaultHuffmanTables(true), JPEG.getDefaultHuffmanTables(false))); } // Defensive programming if (!isConsistent()) { throw new InternalError("Default stream metadata is inconsistent"); } } /** * Constructs a default image <code>JPEGMetadata</code> object appropriate * for the given image type and write parameters. */ JPEGMetadata(ImageTypeSpecifier imageType, ImageWriteParam param, JPEGImageWriter writer) { this(false, false); boolean wantJFIF = true; boolean wantAdobe = false; int transform = JPEG.ADOBE_UNKNOWN; boolean willSubsample = true; boolean wantICC = false; boolean wantProg = false; boolean wantOptimized = false; boolean wantExtended = false; boolean wantQTables = true; boolean wantHTables = true; float quality = JPEG.DEFAULT_QUALITY; byte[] componentIDs = { 1, 2, 3, 4}; int numComponents = 0; ImageTypeSpecifier destType = null; if (param != null) { destType = param.getDestinationType(); if (destType != null) { if (imageType != null) { // Ignore the destination type. writer.warningOccurred (JPEGImageWriter.WARNING_DEST_IGNORED); destType = null; } } // The only progressive mode that makes sense here is MODE_DEFAULT if (param.canWriteProgressive()) { // the param may not be one of ours, so it may return false. // If so, the following would throw an exception if (param.getProgressiveMode() == ImageWriteParam.MODE_DEFAULT) { wantProg = true; wantOptimized = true; wantHTables = false; } } if (param instanceof JPEGImageWriteParam) { JPEGImageWriteParam jparam = (JPEGImageWriteParam) param; if (jparam.areTablesSet()) { wantQTables = false; // If the param has them, metadata shouldn't wantHTables = false; if ((jparam.getDCHuffmanTables().length > 2) || (jparam.getACHuffmanTables().length > 2)) { wantExtended = true; } } // Progressive forces optimized, regardless of param setting // so consult the param re optimized only if not progressive if (!wantProg) { wantOptimized = jparam.getOptimizeHuffmanTables(); if (wantOptimized) { wantHTables = false; } } } // compression quality should determine the q tables. Note that this // will be ignored if we already decided not to create any. // Again, the param may not be one of ours, so we must check that it // supports compression settings if (param.canWriteCompressed()) { if (param.getCompressionMode() == ImageWriteParam.MODE_EXPLICIT) { quality = param.getCompressionQuality(); } } } // We are done with the param, now for the image types ColorSpace cs = null; if (destType != null) { ColorModel cm = destType.getColorModel(); numComponents = cm.getNumComponents(); boolean hasExtraComponents = (cm.getNumColorComponents() != numComponents); boolean hasAlpha = cm.hasAlpha(); cs = cm.getColorSpace(); int type = cs.getType(); switch(type) { case ColorSpace.TYPE_GRAY: willSubsample = false; if (hasExtraComponents) { // e.g. alpha wantJFIF = false; } break; case ColorSpace.TYPE_3CLR: if (cs == JPEG.JCS.getYCC()) { wantJFIF = false; componentIDs[0] = (byte) 'Y'; componentIDs[1] = (byte) 'C'; componentIDs[2] = (byte) 'c'; if (hasAlpha) { componentIDs[3] = (byte) 'A'; }