📄 jpegmetadata.java
字号:
/* * @(#)JPEGMetadata.java 1.30 07/11/26 * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */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; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -