?? jpegdecoder.java
字號:
/* JPEGDecoder.java --
Copyright (C) 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU Classpath 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 for more details.
You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
Linking this library statically or dynamically with other modules is
making a combined work based on this library. Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.
As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module. An independent module is a module which is not derived from
or based on this library. If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
package gnu.javax.imageio.jpeg;
import java.io.IOException;
import java.nio.ByteOrder;
import javax.imageio.*;
import javax.imageio.plugins.jpeg.JPEGHuffmanTable;
import javax.imageio.plugins.jpeg.JPEGQTable;
import javax.imageio.spi.*;
import javax.imageio.metadata.*;
import javax.imageio.stream.ImageInputStream;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.awt.Point;
import java.awt.Transparency;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
public class JPEGDecoder
{
byte majorVersion;
byte minorVersion;
byte units;
short Xdensity;
short Ydensity;
byte Xthumbnail;
byte Ythumbnail;
byte[] thumbnail;
BufferedImage image;
int width;
int height;
byte marker;
/**
* This decoder expects JFIF 1.02 encoding.
*/
public static final byte MAJOR_VERSION = (byte) 1;
public static final byte MINOR_VERSION = (byte) 2;
/**
* The length of the JFIF field not including thumbnail data.
*/
public static final short JFIF_FIXED_LENGTH = 16;
/**
* The length of the JFIF extension field not including extension
* data.
*/
public static final short JFXX_FIXED_LENGTH = 8;
private JPEGImageInputStream jpegStream;
ArrayList jpegFrames = new ArrayList();
JPEGHuffmanTable[] dcTables = new JPEGHuffmanTable[4];
JPEGHuffmanTable[] acTables = new JPEGHuffmanTable[4];
JPEGQTable[] qTables = new JPEGQTable[4];
public int getHeight()
{
return height;
}
public int getWidth()
{
return width;
}
public JPEGDecoder(ImageInputStream in)
throws IOException, JPEGException
{
jpegStream = new JPEGImageInputStream(in);
jpegStream.setByteOrder(ByteOrder.LITTLE_ENDIAN);
if (jpegStream.findNextMarker() != JPEGMarker.SOI)
throw new JPEGException("Failed to find SOI marker.");
if (jpegStream.findNextMarker() != JPEGMarker.APP0)
throw new JPEGException("Failed to find APP0 marker.");
int length = jpegStream.readShort();
if (!(length >= JFIF_FIXED_LENGTH))
throw new JPEGException("Failed to find JFIF field.");
byte[] identifier = new byte[5];
jpegStream.read(identifier);
if (identifier[0] != JPEGMarker.JFIF_J
|| identifier[1] != JPEGMarker.JFIF_F
|| identifier[2] != JPEGMarker.JFIF_I
|| identifier[3] != JPEGMarker.JFIF_F
|| identifier[4] != JPEGMarker.X00)
throw new JPEGException("Failed to read JFIF identifier.");
majorVersion = jpegStream.readByte();
minorVersion = jpegStream.readByte();
if (majorVersion != MAJOR_VERSION
|| (majorVersion == MAJOR_VERSION
&& minorVersion < MINOR_VERSION))
throw new JPEGException("Unsupported JFIF version.");
units = jpegStream.readByte();
if (units > (byte) 2)
throw new JPEGException("Units field is out of range.");
Xdensity = jpegStream.readShort();
Ydensity = jpegStream.readShort();
Xthumbnail = jpegStream.readByte();
Ythumbnail = jpegStream.readByte();
// 3 * for RGB data
int thumbnailLength = 3 * Xthumbnail * Ythumbnail;
if (length > JFIF_FIXED_LENGTH
&& thumbnailLength != length - JFIF_FIXED_LENGTH)
throw new JPEGException("Invalid length, Xthumbnail"
+ " or Ythumbnail field.");
if (thumbnailLength > 0)
{
thumbnail = new byte[thumbnailLength];
if (jpegStream.read(thumbnail) != thumbnailLength)
throw new IOException("Failed to read thumbnail.");
}
}
public void decode()
throws IOException
{
System.out.println ("DECODE!!!");
// The frames in this jpeg are loaded into a list. There is
// usually just one frame except in heirarchial progression where
// there are multiple frames.
JPEGFrame frame = null;
// The restart interval defines how many MCU's we should have
// between the 8-modulo restart marker. The restart markers allow
// us to tell whether or not our decoding process is working
// correctly, also if there is corruption in the image we can
// recover with these restart intervals. (See RSTm DRI).
int resetInterval = 0;
// The JPEGDecoder constructor parses the JFIF field. At this
// point jpegStream points to the first byte after the JFIF field.
// Find the first marker after the JFIF field.
byte marker = jpegStream.findNextMarker();
// Check for a JFIF extension field directly following the JFIF
// header and advance the current marker to the next marker in the
// stream, if necessary.
decodeJFIFExtension();
// Loop through until there are no more markers to read in, at
// that point everything is loaded into the jpegFrames array and
// can be processed.
while (true)
{
switch (marker)
{
// APPn Application Reserved Information - Just throw this
// information away because we wont be using it.
case JPEGMarker.APP0:
case JPEGMarker.APP1:
case JPEGMarker.APP2:
case JPEGMarker.APP3:
case JPEGMarker.APP4:
case JPEGMarker.APP5:
case JPEGMarker.APP6:
case JPEGMarker.APP7:
case JPEGMarker.APP8:
case JPEGMarker.APP9:
case JPEGMarker.APP10:
case JPEGMarker.APP11:
case JPEGMarker.APP12:
case JPEGMarker.APP13:
case JPEGMarker.APP14:
case JPEGMarker.APP15:
jpegStream.skipBytes(jpegStream.readShort() - 2);
break;
case JPEGMarker.SOF0:
// SOFn Start of Frame Marker, Baseline DCT - This is the start
// of the frame header that defines certain variables that will
// be carried out through the rest of the encoding. Multiple
// frames are used in a heirarchiel system, however most JPEG's
// only contain a single frame.
jpegFrames.add(new JPEGFrame());
frame = (JPEGFrame) jpegFrames.get(jpegFrames.size() - 1);
// Skip the frame length.
jpegStream.readShort();
// Bits percision, either 8 or 12.
frame.setPrecision(jpegStream.readByte());
// Scan lines = to the height of the frame.
frame.setScanLines(jpegStream.readShort());
// Scan samples per line = to the width of the frame.
frame.setSamplesPerLine(jpegStream.readShort());
// Number of Color Components (or channels).
frame.setComponentCount(jpegStream.readByte());
// Set the color mode for this frame, so far only 2 color
// modes are supported.
if (frame.getComponentCount() == 1)
frame.setColorMode(JPEGFrame.JPEG_COLOR_GRAY);
else
frame.setColorMode(JPEGFrame.JPEG_COLOR_YCbCr);
// Add all of the necessary components to the frame.
for (int i = 0; i < frame.getComponentCount(); i++)
frame.addComponent(jpegStream.readByte(), jpegStream.readByte(),
jpegStream.readByte());
break;
case JPEGMarker.SOF2:
jpegFrames.add(new JPEGFrame());
frame = (JPEGFrame) jpegFrames.get(jpegFrames.size() - 1);
// Skip the frame length.
jpegStream.readShort();
// Bits percision, either 8 or 12.
frame.setPrecision(jpegStream.readByte());
// Scan lines = to the height of the frame.
frame.setScanLines(jpegStream.readShort());
// Scan samples per line = to the width of the frame.
frame.setSamplesPerLine(jpegStream.readShort());
// Number of Color Components (or channels).
frame.setComponentCount(jpegStream.readByte());
// Set the color mode for this frame, so far only 2 color
// modes are supported.
if (frame.getComponentCount() == 1)
frame.setColorMode(JPEGFrame.JPEG_COLOR_GRAY);
else
frame.setColorMode(JPEGFrame.JPEG_COLOR_YCbCr);
// Add all of the necessary components to the frame.
for (int i = 0; i < frame.getComponentCount(); i++)
frame.addComponent(jpegStream.readByte(), jpegStream.readByte(),
jpegStream.readByte());
break;
case JPEGMarker.DHT:
// DHT non-SOF Marker - Huffman Table is required for decoding
// the JPEG stream, when we receive a marker we load in first
// the table length (16 bits), the table class (4 bits), table
// identifier (4 bits), then we load in 16 bytes and each byte
// represents the count of bytes to load in for each of the 16
// bytes. We load this into an array to use later and move on 4
// huffman tables can only be used in an image.
int huffmanLength = (jpegStream.readShort() - 2);
// Keep looping until we are out of length.
int index = huffmanLength;
// Multiple tables may be defined within a DHT marker. This
// will keep reading until there are no tables left, most
// of the time there are just one tables.
while (index > 0)
{
// Read the identifier information and class
// information about the Huffman table, then read the
// 16 byte codelength in and read in the Huffman values
// and put it into table info.
byte huffmanInfo = jpegStream.readByte();
byte tableClass = (byte) (huffmanInfo >> 4);
byte huffmanIndex = (byte) (huffmanInfo & 0x0f);
short[] codeLength = new short[16];
jpegStream.readFully(codeLength, 0, codeLength.length);
int huffmanValueLen = 0;
for (int i = 0; i < 16; i++)
huffmanValueLen += codeLength[i];
index -= (huffmanValueLen + 17);
short[] huffmanVal = new short[huffmanValueLen];
for (int i = 0; i < huffmanVal.length; i++)
huffmanVal[i] = jpegStream.readByte();
// Assign DC Huffman Table.
if (tableClass == HuffmanTable.JPEG_DC_TABLE)
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -