📄 jfifmarkersegment.java
字号:
/* * @(#)JFIFMarkerSegment.java 1.11 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.IIOException;import javax.imageio.IIOImage;import javax.imageio.ImageTypeSpecifier;import javax.imageio.ImageReader;import javax.imageio.metadata.IIOInvalidTreeException;import javax.imageio.metadata.IIOMetadataNode;import javax.imageio.metadata.IIOMetadata;import javax.imageio.stream.ImageInputStream;import javax.imageio.stream.ImageOutputStream;import javax.imageio.stream.MemoryCacheImageOutputStream;import javax.imageio.event.IIOReadProgressListener;import java.awt.Graphics;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.image.SampleModel;import java.awt.image.IndexColorModel;import java.awt.image.ComponentColorModel;import java.awt.image.BufferedImage;import java.awt.image.DataBuffer;import java.awt.image.DataBufferByte;import java.awt.image.Raster;import java.awt.image.WritableRaster;import java.io.IOException;import java.io.ByteArrayOutputStream;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 JFIF (JPEG File Interchange Format) APP0 (Application-Specific) * marker segment. Inner classes are included for JFXX extension * marker segments, for different varieties of thumbnails, and for * ICC Profile APP2 marker segments. Any of these secondary types * that occur are kept as members of a single JFIFMarkerSegment object. */class JFIFMarkerSegment extends MarkerSegment { int majorVersion; int minorVersion; int resUnits; int Xdensity; int Ydensity; int thumbWidth; int thumbHeight; JFIFThumbRGB thumb = null; // If present ArrayList extSegments = new ArrayList(); ICCMarkerSegment iccSegment = null; // optional ICC private static final int THUMB_JPEG = 0x10; private static final int THUMB_PALETTE = 0x11; private static final int THUMB_UNASSIGNED = 0x12; private static final int THUMB_RGB = 0x13; private static final int DATA_SIZE = 14; private static final int ID_SIZE = 5; private final int MAX_THUMB_WIDTH = 255; private final int MAX_THUMB_HEIGHT = 255; private final boolean debug = false; /** * Set to <code>true</code> when reading the chunks of an * ICC profile. All chunks are consolidated to create a single * "segment" containing all the chunks. This flag is a state * variable identifying whether to construct a new segment or * append to an old one. */ private boolean inICC = false; /** * A placeholder for an ICC profile marker segment under * construction. The segment is not added to the list * until all chunks have been read. */ private ICCMarkerSegment tempICCSegment = null; /** * Default constructor. Used to create a default JFIF header */ JFIFMarkerSegment() { super(JPEG.APP0); majorVersion = 1; minorVersion = 2; resUnits = JPEG.DENSITY_UNIT_ASPECT_RATIO; Xdensity = 1; Ydensity = 1; thumbWidth = 0; thumbHeight = 0; } /** * Constructs a JFIF header by reading from a stream wrapped * in a JPEGBuffer. */ JFIFMarkerSegment(JPEGBuffer buffer) throws IOException { super(buffer); buffer.bufPtr += ID_SIZE; // skip the id, we already checked it majorVersion = buffer.buf[buffer.bufPtr++]; minorVersion = buffer.buf[buffer.bufPtr++]; resUnits = buffer.buf[buffer.bufPtr++]; Xdensity = (buffer.buf[buffer.bufPtr++] & 0xff) << 8; Xdensity |= buffer.buf[buffer.bufPtr++] & 0xff; Ydensity = (buffer.buf[buffer.bufPtr++] & 0xff) << 8; Ydensity |= buffer.buf[buffer.bufPtr++] & 0xff; thumbWidth = buffer.buf[buffer.bufPtr++] & 0xff; thumbHeight = buffer.buf[buffer.bufPtr++] & 0xff; buffer.bufAvail -= DATA_SIZE; if (thumbWidth > 0) { thumb = new JFIFThumbRGB(buffer, thumbWidth, thumbHeight); } } /** * Constructs a JFIF header from a DOM Node. */ JFIFMarkerSegment(Node node) throws IIOInvalidTreeException { this(); updateFromNativeNode(node, true); } /** * Returns a deep-copy clone of this object. */ protected Object clone() { JFIFMarkerSegment newGuy = (JFIFMarkerSegment) super.clone(); if (!extSegments.isEmpty()) { // Clone the list with a deep copy newGuy.extSegments = new ArrayList(); for (Iterator iter = extSegments.iterator(); iter.hasNext();) { JFIFExtensionMarkerSegment jfxx = (JFIFExtensionMarkerSegment) iter.next(); newGuy.extSegments.add(jfxx.clone()); } } if (iccSegment != null) { newGuy.iccSegment = (ICCMarkerSegment) iccSegment.clone(); } return newGuy; } /** * Add an JFXX extension marker segment from the stream wrapped * in the JPEGBuffer to the list of extension segments. */ void addJFXX(JPEGBuffer buffer, JPEGImageReader reader) throws IOException { extSegments.add(new JFIFExtensionMarkerSegment(buffer, reader)); } /** * Adds an ICC Profile APP2 segment from the stream wrapped * in the JPEGBuffer. */ void addICC(JPEGBuffer buffer) throws IOException { if (inICC == false) { if (iccSegment != null) { throw new IIOException ("> 1 ICC APP2 Marker Segment not supported"); } tempICCSegment = new ICCMarkerSegment(buffer); if (inICC == false) { // Just one chunk iccSegment = tempICCSegment; tempICCSegment = null; } } else { if (tempICCSegment.addData(buffer) == true) { iccSegment = tempICCSegment; tempICCSegment = null; } } } /** * Add an ICC Profile APP2 segment by constructing it from * the given ICC_ColorSpace object. */ void addICC(ICC_ColorSpace cs) throws IOException { if (iccSegment != null) { throw new IIOException ("> 1 ICC APP2 Marker Segment not supported"); } iccSegment = new ICCMarkerSegment(cs); } /** * Returns a tree of DOM nodes representing this object and any * subordinate JFXX extension or ICC Profile segments. */ IIOMetadataNode getNativeNode() { IIOMetadataNode node = new IIOMetadataNode("app0JFIF"); node.setAttribute("majorVersion", Integer.toString(majorVersion)); node.setAttribute("minorVersion", Integer.toString(minorVersion)); node.setAttribute("resUnits", Integer.toString(resUnits)); node.setAttribute("Xdensity", Integer.toString(Xdensity)); node.setAttribute("Ydensity", Integer.toString(Ydensity)); node.setAttribute("thumbWidth", Integer.toString(thumbWidth)); node.setAttribute("thumbHeight", Integer.toString(thumbHeight)); if (!extSegments.isEmpty()) { IIOMetadataNode JFXXnode = new IIOMetadataNode("JFXX"); node.appendChild(JFXXnode); for (Iterator iter = extSegments.iterator(); iter.hasNext();) { JFIFExtensionMarkerSegment seg = (JFIFExtensionMarkerSegment) iter.next(); JFXXnode.appendChild(seg.getNativeNode()); } } if (iccSegment != null) { node.appendChild(iccSegment.getNativeNode()); } return node; } /** * Updates the data in this object from the given DOM Node tree. * If fromScratch is true, this object is being constructed. * Otherwise an existing object is being modified. * Throws an IIOInvalidTreeException if the tree is invalid in * any way. */ void updateFromNativeNode(Node node, boolean fromScratch) throws IIOInvalidTreeException { // none of the attributes are required NamedNodeMap attrs = node.getAttributes(); if (attrs.getLength() > 0) { int value = getAttributeValue(node, attrs, "majorVersion", 0, 255, false); majorVersion = (value != -1) ? value : majorVersion; value = getAttributeValue(node, attrs, "minorVersion", 0, 255, false); minorVersion = (value != -1) ? value : minorVersion; value = getAttributeValue(node, attrs, "resUnits", 0, 2, false); resUnits = (value != -1) ? value : resUnits; value = getAttributeValue(node, attrs, "Xdensity", 1, 65535, false); Xdensity = (value != -1) ? value : Xdensity; value = getAttributeValue(node, attrs, "Ydensity", 1, 65535, false); Ydensity = (value != -1) ? value : Ydensity; value = getAttributeValue(node, attrs, "thumbWidth", 0, 255, false); thumbWidth = (value != -1) ? value : thumbWidth; value = getAttributeValue(node, attrs, "thumbHeight", 0, 255, false); thumbHeight = (value != -1) ? value : thumbHeight; } if (node.hasChildNodes()) { NodeList children = node.getChildNodes(); int count = children.getLength(); if (count > 2) { throw new IIOInvalidTreeException ("app0JFIF node cannot have > 2 children", node); } for (int i = 0; i < count; i++) { Node child = children.item(i); String name = child.getNodeName(); if (name.equals("JFXX")) { if ((!extSegments.isEmpty()) && fromScratch) { throw new IIOInvalidTreeException ("app0JFIF node cannot have > 1 JFXX node", node); } NodeList exts = child.getChildNodes(); int extCount = exts.getLength(); for (int j = 0; j < extCount; j++) { Node ext = exts.item(j); extSegments.add(new JFIFExtensionMarkerSegment(ext)); } } if (name.equals("app2ICC")) { if ((iccSegment != null) && fromScratch) { throw new IIOInvalidTreeException ("> 1 ICC APP2 Marker Segment not supported", node); } iccSegment = new ICCMarkerSegment(child); } } } } int getThumbnailWidth(int index) { if (thumb != null) { if (index == 0) { return thumb.getWidth(); } index--; } JFIFExtensionMarkerSegment jfxx = (JFIFExtensionMarkerSegment) extSegments.get(index); return jfxx.thumb.getWidth(); } int getThumbnailHeight(int index) { if (thumb != null) { if (index == 0) { return thumb.getHeight(); } index--; } JFIFExtensionMarkerSegment jfxx = (JFIFExtensionMarkerSegment) extSegments.get(index); return jfxx.thumb.getHeight(); } BufferedImage getThumbnail(ImageInputStream iis, int index, JPEGImageReader reader) throws IOException { reader.thumbnailStarted(index); BufferedImage ret = null; if ((thumb != null) && (index == 0)) { ret = thumb.getThumbnail(iis, reader); } else { if (thumb != null) { index--; } JFIFExtensionMarkerSegment jfxx = (JFIFExtensionMarkerSegment) extSegments.get(index); ret = jfxx.thumb.getThumbnail(iis, reader); } reader.thumbnailComplete(); return ret; } /** * Writes the data for this segment to the stream in * valid JPEG format. Assumes that there will be no thumbnail. */ void write(ImageOutputStream ios, JPEGImageWriter writer) throws IOException { // No thumbnail write(ios, null, writer); } /** * Writes the data for this segment to the stream in * valid JPEG format. The length written takes the thumbnail * width and height into account. If necessary, the thumbnail * is clipped to 255 x 255 and a warning is sent to the writer * argument. Progress updates are sent to the writer argument. */ void write(ImageOutputStream ios, BufferedImage thumb, JPEGImageWriter writer) throws IOException { int thumbWidth = 0; int thumbHeight = 0; int thumbLength = 0; int [] thumbData = null; if (thumb != null) { // Clip if necessary and get the data in thumbData thumbWidth = thumb.getWidth(); thumbHeight = thumb.getHeight(); if ((thumbWidth > MAX_THUMB_WIDTH) || (thumbHeight > MAX_THUMB_HEIGHT)) { writer.warningOccurred(JPEGImageWriter.WARNING_THUMB_CLIPPED); } thumbWidth = Math.min(thumbWidth, MAX_THUMB_WIDTH); thumbHeight = Math.min(thumbHeight, MAX_THUMB_HEIGHT); thumbData = thumb.getRaster().getPixels(0, 0, thumbWidth, thumbHeight, (int []) null); thumbLength = thumbData.length; } length = DATA_SIZE + LENGTH_SIZE + thumbLength; writeTag(ios); byte [] id = {0x4A, 0x46, 0x49, 0x46, 0x00}; ios.write(id); ios.write(majorVersion); ios.write(minorVersion); ios.write(resUnits); write2bytes(ios, Xdensity); write2bytes(ios, Ydensity); ios.write(thumbWidth); ios.write(thumbHeight); if (thumbData != null) { writer.thumbnailStarted(0); writeThumbnailData(ios, thumbData, writer); writer.thumbnailComplete();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -