ports/java/openjdk6/files/icedtea/jpegclasses.patch
Jung-uk Kim 176e27746b - Update to build 23.
- Import more complete JPEG class support and turn on ICEDTEA option by
default. [1]
- Remove obsolete WEB option.  Note the functionality is now moved to a new
port java/icedtea-web, which depends on ICEDTEA option of this port.

Obtained from:	IcedTea project [1]
2011-07-11 20:58:58 +00:00

2667 lines
99 KiB
Diff

--- jdk/src/share/classes/com/sun/image/codec/jpeg/ImageFormatException.java 1969-12-31 19:00:00.000000000 -0500
+++ jdk/src/share/classes/com/sun/image/codec/jpeg/ImageFormatException.java 2011-07-07 09:19:34.000000000 -0400
@@ -0,0 +1,51 @@
+/* ImageFormatException.java
+ * Copyright (C) 2007 Matthew Flaschen
+ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * This file is part of IcedTea
+ *
+ * IcedTea 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.
+ *
+ * IcedTea 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 com.sun.image.codec.jpeg;
+
+public class ImageFormatException extends RuntimeException {
+
+ public ImageFormatException() {
+ super();
+ }
+
+ public ImageFormatException(String s) {
+ super(s);
+ }
+}
--- jdk/src/share/classes/com/sun/image/codec/jpeg/JPEGCodec.java 1969-12-31 19:00:00.000000000 -0500
+++ jdk/src/share/classes/com/sun/image/codec/jpeg/JPEGCodec.java 2011-07-07 09:19:34.000000000 -0400
@@ -0,0 +1,193 @@
+/* JPEGCodec.java --
+ * Copyright (C) 2007 Free Software Foundation, Inc.
+ * Copyright (C) 2007 Matthew Flaschen
+ *
+ * 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 com.sun.image.codec.jpeg;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.awt.color.ColorSpace;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.Raster;
+
+import sun.awt.image.codec.JPEGImageDecoderImpl;
+import sun.awt.image.codec.JPEGImageEncoderImpl;
+import sun.awt.image.codec.JPEGParam;
+
+/**
+ * This class is a factory for implementations of the JPEG Image
+ * Decoder/Encoder.
+ */
+public class JPEGCodec {
+
+ private JPEGCodec() {}
+
+ /**
+ * This creates an instance of a JPEGImageDecoder that can be used to decode
+ * JPEG Data streams.
+ *
+ * @param src
+ * @return
+ */
+ public static JPEGImageDecoder createJPEGDecoder(InputStream src) {
+ return new JPEGImageDecoderImpl(src);
+ }
+
+ /**
+ * This creates an instance of a JPEGImageDecoder that can be used to decode
+ * JPEG Data streams.
+ *
+ * @param src
+ * @param jdp
+ * @return
+ */
+ public static JPEGImageDecoder createJPEGDecoder(InputStream src,
+ JPEGDecodeParam jdp) {
+ return new JPEGImageDecoderImpl(src, jdp);
+ }
+
+ /**
+ * This creates an instance of a JPEGImageEncoder that can be used to encode
+ * image data as JPEG Data streams.
+ *
+ * @param os
+ * @return
+ */
+ public static JPEGImageEncoder createJPEGEncoder(OutputStream os) {
+ return new JPEGImageEncoderImpl(os);
+ }
+
+ /**
+ * This creates an instance of a JPEGImageEncoder that can be used to encode
+ * image data as JPEG Data streams.
+ *
+ * @param dest
+ * @param jep
+ * @return
+ */
+ public static JPEGImageEncoder createJPEGEncoder(OutputStream dest,
+ JPEGEncodeParam jep) {
+ return new JPEGImageEncoderImpl(dest, jep);
+ }
+
+ /**
+ * This is a factory method for creating JPEGEncodeParam objects.
+ *
+ * @param bi
+ * @return
+ */
+ public static JPEGEncodeParam getDefaultJPEGEncodeParam(BufferedImage bi) {
+ return getDefaultJPEGEncodeParam(bi.getRaster(),
+ getDefaultColorID(bi.getColorModel()));
+ }
+
+ /**
+ * This is a factory method for creating JPEGEncodeParam objects.
+ *
+ * @param numBands
+ * @param colorID
+ * @return
+ */
+ public static JPEGEncodeParam getDefaultJPEGEncodeParam(int numBands,
+ int colorID) {
+ return new JPEGParam(colorID, numBands);
+ }
+
+ /**
+ * This is a factory method for creating a JPEGEncodeParam from a
+ * JPEGDecodeParam.
+ *
+ * @param jdp
+ * @return
+ */
+ public static JPEGEncodeParam getDefaultJPEGEncodeParam(JPEGDecodeParam jdp) {
+ return new JPEGParam(jdp);
+ }
+
+ /**
+ * This is a factory method for creating JPEGEncodeParam objects.
+ *
+ * @param ras
+ * @param colorID
+ * @return
+ */
+ public static JPEGEncodeParam getDefaultJPEGEncodeParam(Raster ras,
+ int colorID) {
+ return getDefaultJPEGEncodeParam(ras.getNumBands(), colorID);
+ }
+
+ private static int getDefaultColorID(ColorModel cm) {
+ ColorSpace cs = cm.getColorSpace();
+ int type = cs.getType();
+ int id = -1;
+ switch (type) {
+ case ColorSpace.TYPE_GRAY:
+ id = JPEGEncodeParam.COLOR_ID_GRAY;
+ break;
+
+ case ColorSpace.TYPE_RGB:
+ id = cm.hasAlpha() ? JPEGEncodeParam.COLOR_ID_RGBA
+ : JPEGEncodeParam.COLOR_ID_RGB;
+
+ case ColorSpace.TYPE_YCbCr:
+ try {
+ if (cs == ColorSpace.getInstance(ColorSpace.CS_PYCC)) {
+ id = cm.hasAlpha() ? JPEGEncodeParam.COLOR_ID_PYCCA
+ : JPEGEncodeParam.COLOR_ID_PYCC;
+ }
+ } catch (IllegalArgumentException e) {
+ /* We know it isn't PYCC type, nothing to handle */
+ }
+ if (id == -1) {
+ id = cm.hasAlpha() ? JPEGEncodeParam.COLOR_ID_YCbCrA
+ : JPEGEncodeParam.COLOR_ID_YCbCr;
+ }
+ break;
+
+ case ColorSpace.TYPE_CMYK:
+ id = JPEGEncodeParam.COLOR_ID_CMYK;
+ break;
+
+ default:
+ id = JPEGEncodeParam.COLOR_ID_UNKNOWN;
+ }
+
+ return id;
+ }
+}
--- jdk/src/share/classes/com/sun/image/codec/jpeg/JPEGDecodeParam.java 1969-12-31 19:00:00.000000000 -0500
+++ jdk/src/share/classes/com/sun/image/codec/jpeg/JPEGDecodeParam.java 2011-07-07 09:19:34.000000000 -0400
@@ -0,0 +1,390 @@
+/* JPEGImageDecoder.java --
+ * Copyright (C) 2007 Free Software Foundation, Inc.
+ * Copyright (C) 2007 Matthew Flaschen
+ *
+ * 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 com.sun.image.codec.jpeg;
+
+/**
+ * <p>
+ * JPEGDecodeParam encapsulates tables and options necessary to control decoding
+ * JPEG data streams. Parameters are either set explicitly by the application
+ * for encoding, or read from the JPEG header for decoding. In the case of
+ * decoding abbreviated data streams the application may need to set some/all of
+ * the values it's self.
+ * </p>
+ * <p>
+ * When working with BufferedImages (@see JPEGImageDecoder.decodeBufferedImage),
+ * the codec will attempt to generate an appropriate ColorModel for the JPEG
+ * COLOR_ID. This is not always possible (example mappings are listed below) .
+ * In cases where unsupported conversions are required, or unknown encoded
+ * COLOR_ID's are in use, the user must request the data as a Raster and perform
+ * the transformations themselves. When decoding into a raster (@see
+ * JPEGImageDecoder.decodeRaster) no ColorSpace adjustments are made. Note: The
+ * color ids described herein are simply enumerated values that influence data
+ * processing by the JPEG codec. JPEG compression is by definition color blind.
+ * These values are used as hints when decompressing JPEG data. Of particular
+ * interest is the default conversion from YCbCr to sRGB when decoding buffered
+ * Images.
+ * </p>
+ * <p>
+ * Note: because JPEG is mostly color-blind color fidelity can not be
+ * guaranteed. This will hopefully be rectified in the near future by the wide
+ * spread inclusion of ICC-profiles in the JPEG data stream (as a special
+ * marker). The following is an example of the conversions that take place. This
+ * is only a guide to the types of conversions that are allowed. This list is
+ * likely to change in the future so it is strongly recommended that you check
+ * for thrown ImageFormatExceptions and check the actual ColorModel associated
+ * with the BufferedImage returned rather than make assumptions.
+ * </p>
+ * DECODING:
+ *
+ * <pre>
+ * JPEG (Encoded) Color ID BufferedImage ColorSpace
+ * ======================= ========================
+ * COLOR_ID_UNKNOWN ** Invalid **
+ * COLOR_ID_GRAY CS_GRAY
+ * COLOR_ID_RGB CS_sRGB
+ * COLOR_ID_YCbCr CS_sRGB
+ * COLOR_ID_CMYK ** Invalid **
+ * COLOR_ID_PYCC CS_PYCC
+ * COLOR_ID_RGBA CS_sRGB (w/ alpha)
+ * COLOR_ID_YCbCrA CS_sRGB (w/ alpha)
+ * COLOR_ID_RGBA_INVERTED ** Invalid **
+ * COLOR_ID_YCbCrA_INVERTED ** Invalid **
+ * COLOR_ID_PYCCA CS_PYCC (w/ alpha)
+ * COLOR_ID_YCCK ** Invalid **
+ * </pre>
+ * <p>
+ * If the user needs better control over conversion, the user must request the
+ * data as a Raster and handle the conversion of the image data themselves. When
+ * decoding JFIF files the encoded COLOR_ID will always be one of:
+ * COLOR_ID_UNKNOWN, COLOR_ID_GRAY, COLOR_ID_RGB, COLOR_ID_YCbCr, COLOR_ID_CMYK,
+ * or COLOR_ID_YCCK
+ * </p>
+ * <p>
+ * Note that the classes in the com.sun.image.codec.jpeg package are not part of
+ * the core Java APIs. They are a part of Sun's JDK and JRE distributions.
+ * Although other licensees may choose to distribute these classes, developers
+ * cannot depend on their availability in non-Sun implementations. We expect
+ * that equivalent functionality will eventually be available in a core API or
+ * standard extension.
+ * </p>
+ */
+public interface JPEGDecodeParam extends Cloneable {
+
+ /** APP0 marker - JFIF info */
+ public static final int APP0_MARKER = 0xE0;
+ /** APP1 marker */
+ public static final int APP1_MARKER = 0xE1;
+ /** APP2 marker */
+ public static final int APP2_MARKER = 0xE2;
+ /** APP3 marker */
+ public static final int APP3_MARKER = 0xE3;
+ /** APP4 marker */
+ public static final int APP4_MARKER = 0xE4;
+ /** APP5 marker */
+ public static final int APP5_MARKER = 0xE5;
+ /** APP6 marker */
+ public static final int APP6_MARKER = 0xE6;
+ /** APP7 marker */
+ public static final int APP7_MARKER = 0xE7;
+ /** APP8 marker */
+ public static final int APP8_MARKER = 0xE8;
+ /** APP9 marker */
+ public static final int APP9_MARKER = 0xE9;
+ /** APPA marker */
+ public static final int APPA_MARKER = 0xEA;
+ /** APPB marker */
+ public static final int APPB_MARKER = 0xEB;
+ /** APPC marker */
+ public static final int APPC_MARKER = 0xEC;
+ /** APPD marker */
+ public static final int APPD_MARKER = 0xED;
+ /** APPE marker - Adobe info */
+ public static final int APPE_MARKER = 0xEE;
+ /** APPF marker */
+ public static final int APPF_MARKER = 0xEF;
+ /** Adobe marker indicates presence/need for Adobe marker. */
+ public static final int COMMENT_MARKER = 0XFE;
+
+ /* Color ID values */
+ public static final int COLOR_ID_UNKNOWN = 0;
+ public static final int COLOR_ID_GRAY = 1;
+ public static final int COLOR_ID_RGB = 2;
+ public static final int COLOR_ID_YCbCr = 3;
+ public static final int COLOR_ID_CMYK = 4;
+ public static final int COLOR_ID_PYCC = 5;
+ public static final int COLOR_ID_RGBA = 6;
+ public static final int COLOR_ID_YCbCrA = 7;
+ public static final int COLOR_ID_RGBA_INVERTED = 8;
+ public static final int COLOR_ID_YCbCrA_INVERTED = 9;
+ public static final int COLOR_ID_PYCCA = 10;
+ public static final int COLOR_ID_YCCK = 11;
+ public static final int NUM_COLOR_ID = 12;
+
+ /** Number of allowed Huffman and Quantization Tables */
+ public static final int NUM_TABLES = 4;
+
+ /** The X and Y units simply indicate the aspect ratio of the pixels. */
+ public static final int DENSITY_UNIT_ASPECT_RATIO = 0;
+ /** Pixel density is in pixels per inch. */
+ public static final int DENSITY_UNIT_DOTS_INCH = 1;
+ /** Pixel density is in pixels per centimeter. */
+ public static final int DENSITY_UNIT_DOTS_CM = 2;
+ /** The max known value for DENSITY_UNIT */
+ public static final int NUM_DENSITY_UNIT = 3;
+
+ public Object clone();
+
+ /**
+ * Get the image width.
+ *
+ * @return int the width of the image data in pixels.
+ */
+ public int getWidth();
+
+ /**
+ * Get the image height.
+ *
+ * @return The height of the image data in pixels.
+ */
+ public int getHeight();
+
+ /**
+ * Return the Horizontal subsampling factor for requested Component. The
+ * Subsample factor is the number of input pixels that contribute to each
+ * output pixel. This is distinct from the way the JPEG to each output
+ * pixel. This is distinct from the way the JPEG standard defines this
+ * quantity, because fractional subsampling factors are not allowed.
+ *
+ * @param component
+ * The component of the encoded image to return the subsampling
+ * factor for.
+ * @return The subsample factor.
+ */
+ public int getHorizontalSubsampling(int component);
+
+ /**
+ * Return the Vertical subsampling factor for requested Component. The
+ * Subsample factor is the number of input pixels that contribute to each
+ * output pixel. This is distinct from the way the JPEG to each output
+ * pixel. This is distinct from the way the JPEG standard defines this
+ * quantity, because fractional subsampling factors are not allowed.
+ *
+ * @param component
+ * The component of the encoded image to return the subsampling
+ * factor for.
+ * @return The subsample factor.
+ */
+ public int getVerticalSubsampling(int component);
+
+ /**
+ * Returns the coefficient quantization tables or NULL if not defined.
+ * tableNum must range in value from 0 - 3.
+ *
+ * @param tableNum
+ * the index of the table to be returned.
+ * @return Quantization table stored at index tableNum.
+ */
+ public JPEGQTable getQTable(int tableNum);
+
+ /**
+ * Returns the Quantization table for the requested component.
+ *
+ * @param component
+ * the image component of interest.
+ * @return Quantization table associated with component
+ */
+ public JPEGQTable getQTableForComponent(int component);
+
+ /**
+ * Returns the DC Huffman coding table requested or null if not defined
+ *
+ * @param tableNum
+ * the index of the table to be returned.
+ * @return Huffman table stored at index tableNum.
+ */
+ public JPEGHuffmanTable getDCHuffmanTable(int tableNum);
+
+ /**
+ * Returns the DC Huffman coding table for the requested component.
+ *
+ * @param component
+ * the image component of interest.
+ * @return Huffman table associated with component
+ */
+ public JPEGHuffmanTable getDCHuffmanTableForComponent(int component);
+
+ /**
+ * Returns the AC Huffman coding table requested or null if not defined
+ *
+ * @param tableNum
+ * the index of the table to be returned.
+ * @return Huffman table stored at index tableNum.
+ */
+ public JPEGHuffmanTable getACHuffmanTable(int tableNum);
+
+ /**
+ * Returns the AC Huffman coding table for the requested component.
+ *
+ * @param component
+ * the image component of interest.
+ * @return Huffman table associated with component
+ */
+ public JPEGHuffmanTable getACHuffmanTableForComponent(int component);
+
+ /**
+ * Get the number of the DC Huffman table that will be used for a particular
+ * component.
+ *
+ * @param component
+ * The Component of interest.
+ * @return The table number of the DC Huffman table for component.
+ */
+ public int getDCHuffmanComponentMapping(int component);
+
+ /**
+ * Get the number of the AC Huffman table that will be used for a particular
+ * component.
+ *
+ * @param component
+ * The Component of interest.
+ * @return The table number of the AC Huffman table for component.
+ */
+ public int getACHuffmanComponentMapping(int component);
+
+ /**
+ * Get the number of the quantization table that will be used for a
+ * particular component.
+ *
+ * @param component
+ * The Component of interest.
+ * @return The table number of the Quantization table for component.
+ */
+ public int getQTableComponentMapping(int component);
+
+ /**
+ * Returns true if the image information in the ParamBlock is currently
+ * valid. This indicates if image data was read from the stream for decoding
+ * and weather image data should be written when encoding.
+ */
+ public boolean isImageInfoValid();
+
+ /**
+ * Returns true if the tables in the ParamBlock are currently valid. This
+ * indicates that tables were read from the stream for decoding. When
+ * encoding this indicates whether tables should be written to the stream.
+ */
+ public boolean isTableInfoValid();
+
+ /**
+ * Returns true if at least one instance of the marker is present in the
+ * Parameter object. For encoding returns true if there is at least one
+ * instance of the marker to be written.
+ *
+ * @param marker
+ * The marker of interest.
+ */
+ public boolean getMarker(int marker);
+
+ /**
+ * Returns a 'byte[][]' associated with the requested marker in the
+ * parameter object. Each entry in the 'byte[][]' is the data associated
+ * with one instance of the marker (each marker can theoretically appear any
+ * number of times in a stream).
+ *
+ * @param marker
+ * The marker of interest.
+ * @return The 'byte[][]' for this marker or null if none available.
+ */
+ public byte[][] getMarkerData(int marker);
+
+ /**
+ * Returns the JPEG Encoded color id. This is generally speaking only used
+ * if you are decoding into Rasters. Note that when decoding into a Raster
+ * no color conversion is performed.
+ *
+ * @return The value of the JPEG encoded data's color id.
+ */
+ public int getEncodedColorID();
+
+ /**
+ * Returns the number of components for the current encoding COLOR_ID.
+ *
+ * @return the number of Components
+ */
+ public int getNumComponents();
+
+ /**
+ * Get the MCUs per restart marker.
+ *
+ * @return The number of MCUs between restart markers.
+ */
+ public int getRestartInterval();
+
+ /**
+ * Get the code for pixel size units This value is copied from the APP0
+ * marker. It isn't used by the JPEG codec. If the APP0 marker wasn't
+ * present then you can not rely on this value.
+ *
+ * @return Value indicating the density unit one of the DENSITY_UNIT_*
+ * constants.
+ */
+ public int getDensityUnit();
+
+ /**
+ * Get the horizontal pixel density This value is copied from the APP0
+ * marker. It isn't used by the JPEG code. If the APP0 marker wasn't present
+ * then you can not rely on this value.
+ *
+ * @return The horizontal pixel density, in units described by
+ * @see #getDensityUnit()
+ */
+ public int getXDensity();
+
+ /**
+ * Get the vertical pixel density This value is copied into the APP0 marker.
+ * It isn't used by the JPEG code. If the APP0 marker wasn't present then
+ * you can not rely on this value.
+ *
+ * @return The vertical pixel density, in units described by
+ * @see #getDensityUnit()
+ */
+ public int getYDensity();
+
+}
--- jdk/src/share/classes/com/sun/image/codec/jpeg/JPEGEncodeParam.java 1969-12-31 19:00:00.000000000 -0500
+++ jdk/src/share/classes/com/sun/image/codec/jpeg/JPEGEncodeParam.java 2011-07-07 09:19:34.000000000 -0400
@@ -0,0 +1,307 @@
+/* JPEGEncodeParam.java --
+ Copyright (C) 2007 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 com.sun.image.codec.jpeg;
+
+/**
+ * <p>
+ * JPEGEncodeParam encapsulates tables and options necessary to control encoding
+ * of JPEG data streams. Parameters are either set explicitly by the application
+ * for encoding, or read from another JPEG header.
+ * </p>
+ * <p>
+ * When working with BufferedImages, the codec will attempt to match the encoded
+ * JPEG COLOR_ID with the ColorModel in the BufferedImage. This is not always
+ * possible (the default mappings are listed below). In cases where unsupported
+ * conversions are required (or odd image colorspaces are in use) the user must
+ * either convert the image data to a known ColorSpace or encode the data from a
+ * raster. When encoding rasters no colorspace adjustments are made, so the user
+ * must do any conversions required to get to the encoded COLOR_ID. The COLOR_ID
+ * for the encoded images is used to control the JPEG codec's inital values for
+ * Huffman and Quantization Tables as well as subsampling factors. It is also
+ * used to determine what color conversion should be performed to obtain the
+ * best encoding.
+ * </p>
+ * <p>
+ * Note: The color ids described herein are simply enumerated values that
+ * influence data processing by the JPEG codec. JPEG compression is, by
+ * definition, color blind. These values are used as hints when compressing JPEG
+ * data. Through these values the JPEG codec can perform some default rotation
+ * of data into spaces that will aid in getting better compression ratios.
+ * </p>
+ * <p>
+ * Example behavior is described below. Since these mappings are likely to
+ * change in the future it is strongly recommended that you make use of the @see
+ * JPEGImageEncoder.getDefaultParamBlock calls and check the encodedColorID for
+ * your particular BufferedImage. In extreme cases is may be necessary for the
+ * user to convert the image to the desired colorspace, and encode it from a
+ * Raster. In this case the API programmer must specify the colorID of the data
+ * in the Raster and no color conversion will take place.
+ * </p>
+ *
+ * ENCODING:
+ *
+ * <pre>
+ * BufferedImage Type/Instance JPEG (Encoded) Color ID
+ * =========================== =======================
+ * TYPE_GRAY COLOR_ID_GRAYSCALE
+ * TYPE_RGB COLOR_ID_YCbCr
+ * TYPE_YCbCr COLOR_ID_YCbCr
+ * TYPE_YCbCr/CS_PYCC COLOR_ID_PYCC
+ * TYPE_CMYK COLOR_ID_CMYK
+ * TYPE_RGB (w/ alpha) COLOR_ID_YCbCrA
+ * TYPE_YCbCr (w/ alpha) COLOR_ID_YCbCrA
+ * TYPE_YCbCr/CS_PYCC (w/ alpha) COLOR_ID_PYCCA
+ * ** Any Other ** COLOR_ID_UNKNOWN
+ * </pre>
+ * <p>
+ * When the user wants more control than the BufferedImage conversions provide,
+ * the user must encode the data from a Raster. In this case the data undergoes
+ * no color conversion at all. It is the user's responsibility to perform the
+ * desired conversions. If you intend to write a JFIF image (by including the
+ * APP0_MARKER) the encoded COLOR_ID must be one of: COLOR_ID_UNKNOWN,
+ * COLOR_ID_GRAYSCALE, COLOR_ID_YCbCr, or COLOR_ID_CMYK. In all other instances
+ * an ImageformatException will be thrown.
+ * </p>
+ * <p>
+ * IMPORTANT: an Alpha RGB BufferedImage will not map to a valid JFIF stream,
+ * you must strip off the alpha prior to encoding if you want a JFIF file. If
+ * the APP0 marker is set and you do not strip off the Alpha, an
+ * ImageFormatException will be thrown.
+ * </p>
+ * <p>
+ * Note that the classes in the com.sun.image.codec.jpeg package are not part of
+ * the core Java APIs. They are a part of Sun's JDK and JRE distributions.
+ * Although other licensees may choose to distribute these classes, developers
+ * cannot depend on their availability in non-Sun implementations. We expect
+ * that equivalent functionality will eventually be available in a core API or
+ * standard extension.
+ * </p>
+ */
+public interface JPEGEncodeParam extends JPEGDecodeParam {
+
+ /**
+ * Set the horizontal subsample factor for the given component. Note that
+ * the subsample factor is the number of input pixels that contribute to
+ * each output pixel (usually 2 for YCC).
+ *
+ * @param component
+ * The component being specified.
+ * @param subsample
+ * The subsampling factor being specified.
+ */
+ public void setHorizontalSubsampling(int component, int subsample);
+
+ /**
+ * Set the vertical subsample factor for the given component. Note that the
+ * subsample factor is the number of input pixels that contribute to each
+ * output pixel (usually 2 for YCC).
+ *
+ * @param component
+ * The component being specified.
+ * @param subsample
+ * The subsampling factor being specified.
+ */
+ public void setVerticalSubsampling(int component, int subsample);
+
+ /**
+ * Sets the coefficient quantization tables at index passed. tableNum must
+ * range in value from 0 - 3.
+ *
+ * @param qtable
+ * that will be used.
+ * @param tableNum
+ * the index of the table to be set.
+ */
+ public void setQTable(int tableNum, JPEGQTable qTable);
+
+ /**
+ * Sets the DC Huffman coding table at index to the table provided.
+ *
+ * @param huffTable
+ * JPEGHuffmanTable that will be assigned to index tableNum.
+ * @param tableNum
+ * - the index of the table to be set.
+ * @exception IllegalArgumentException
+ * - thrown if the tableNum is out of range. Index must range
+ * in value from 0 - 3.
+ */
+ public void setDCHuffmanTable(int tableNum, JPEGHuffmanTable huffTable);
+
+ /**
+ * Sets the AC Huffman coding table at index to the table provided.
+ *
+ * @param huffTable
+ * JPEGHuffmanTable that will be assigned to index tableNum.
+ * @param tableNum
+ * - the index of the table to be set.
+ * @exception IllegalArgumentException
+ * - thrown if the tableNum is out of range. Index must range
+ * in value from 0 - 3.
+ */
+ public void setACHuffmanTable(int tableNum, JPEGHuffmanTable huffTable);
+
+ /**
+ * Sets the mapping between a component and it's DC Huffman Table.
+ *
+ * @param component
+ * The component to set the mapping for
+ * @param table
+ * The DC Huffman table to use for component
+ */
+ public void setDCHuffmanComponentMapping(int component, int table);
+
+ /**
+ * Sets the mapping between a component and it's AC Huffman Table.
+ *
+ * @param component
+ * The component to set the mapping for
+ * @param table
+ * The AC Huffman table to use for component
+ */
+ public void setACHuffmanComponentMapping(int component, int table);
+
+ /**
+ * Sets the mapping between a component and it's Quantization Table.
+ *
+ * @param component
+ * The component to set the mapping for
+ * @param table
+ * The Quantization Table to use for component
+ */
+ public void setQTableComponentMapping(int component, int table);
+
+ /**
+ * Set the flag indicating the validity of the table information in the
+ * ParamBlock. This is used to indicate if tables should be included when
+ * encoding.
+ */
+ public void setImageInfoValid(boolean flag);
+
+ /**
+ * Set the flag indicating the validity of the image information in the
+ * ParamBlock. This is used to indicates if image data should be written
+ * when encoding.
+ */
+ public void setTableInfoValid(boolean flag);
+
+ /**
+ * Sets the marker data to be written to the output data stream. This
+ * removes any existing marker data in the JPEParm object. This can be used
+ * to remove the default APP0 marker by calling it with data set to null.
+ *
+ * @param marker
+ * The marker to set the data for.
+ * @param data
+ * the new set of data to be written.
+ */
+ public void setMarkerData(int marker, byte[][] data);
+
+ /**
+ * Appends 'data' to the array of byte[] associated with marker. This will
+ * result in additional instance of the marker being written (one for each
+ * byte[] in the array.).
+ *
+ * @param marker
+ * The marker to add and instance of.
+ * @param data
+ * the data to be written.
+ */
+ public void addMarkerData(int marker, byte[] data);
+
+ /**
+ * Set the MCUs per restart, or 0 for no restart markers.
+ *
+ * @param restartInterval
+ * number MCUs per restart marker.
+ */
+ public void setRestartInterval(int restartInterval);
+
+ /**
+ * Set the pixel size units This value is copied into the APP0 marker (if
+ * that marker is written). This value isn't used by the JPEG code.
+ *
+ * @param unit
+ * One of the DENSITY_UNIT_* values.
+ */
+ public void setDensityUnit(int unit);
+
+ /**
+ * Set the horizontal pixel density. This value is written into the APP0
+ * marker. It isn't used by the JPEG code.
+ *
+ * @param density
+ * the horizontal pixel density, in units described by @see
+ * JPEGParam.getDensityUnit.
+ */
+ public void setXDensity(int density);
+
+ /**
+ * Set the vertical pixel density. This value is copied into the JFIF APP0
+ * marker. It isn't used by the JPEG code.
+ *
+ * @param density
+ * The vertical pixel density, in units described by @see
+ * JPEGParam.getDensityUnit.
+ */
+ public void setYDensity(int density);
+
+ /**
+ * This creates new Quantization tables that replace the currently installed
+ * Quantization tables. It also updates the Component QTable mapping to the
+ * default for the current encoded COLOR_ID.
+ *
+ * The Created Quantization table varies from very high compression, very
+ * low quality, (0.0) to low compression, very high quality (1.0) based on
+ * the quality parameter.
+ *
+ * At a quality level of 1.0 the table will be all 1's which will lead to no
+ * loss of data due to quantization (however chrominance subsampling, if
+ * used, and roundoff error in the DCT will still degrade the image some
+ * what).
+ *
+ * This is a linear manipulation of the standard chrominance Q-Table.
+ *
+ * Some guidelines: 0.75 high quality 0.5 medium quality 0.25 low quality
+ *
+ * @param quality
+ * 0.0-1.0 setting of desired quality level.
+ * @param forceBaseline
+ * force baseline quantization table
+ */
+ public void setQuality(float quality, boolean forceBaseline);
+}
--- jdk/src/share/classes/com/sun/image/codec/jpeg/JPEGHuffmanTable.java 1969-12-31 19:00:00.000000000 -0500
+++ jdk/src/share/classes/com/sun/image/codec/jpeg/JPEGHuffmanTable.java 2011-07-07 09:19:34.000000000 -0400
@@ -0,0 +1,129 @@
+/* JPEGHuffmanTable.java -- Huffman table implementation for JPEG.
+Copyright (C) 2011 Red Hat
+
+This program 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 of the License, or
+(at your option) any later version.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+package com.sun.image.codec.jpeg;
+
+/**
+ * A class to encapsulate a JPEG Huffman table.
+ */
+public class JPEGHuffmanTable {
+
+ /**
+ * The standard DC luminance Huffman table.
+ */
+ public static final JPEGHuffmanTable StdDCLuminance;
+
+ /**
+ * The standard DC chrominance Huffman table.
+ */
+ public static final JPEGHuffmanTable StdDCChrominance;
+
+ /**
+ * The standard AC luminance Huffman table.
+ */
+ public static final JPEGHuffmanTable StdACLuminance;
+
+ /**
+ * The standard AC chrominance Huffman table.
+ */
+ public static final JPEGHuffmanTable StdACChrominance;
+
+ private short[] lengths;
+
+ private short[] symbols;
+
+ static {
+ javax.imageio.plugins.jpeg.JPEGHuffmanTable temp;
+
+ temp = javax.imageio.plugins.jpeg.JPEGHuffmanTable.StdDCLuminance;
+ StdDCLuminance = new JPEGHuffmanTable(temp.getLengths(),
+ temp.getValues());
+
+ temp = javax.imageio.plugins.jpeg.JPEGHuffmanTable.StdDCChrominance;
+ StdDCChrominance = new JPEGHuffmanTable(temp.getLengths(),
+ temp.getValues());
+
+ temp = javax.imageio.plugins.jpeg.JPEGHuffmanTable.StdACLuminance;
+ StdACLuminance = new JPEGHuffmanTable(temp.getLengths(),
+ temp.getValues());
+
+ temp = javax.imageio.plugins.jpeg.JPEGHuffmanTable.StdACChrominance;
+ StdACChrominance = new JPEGHuffmanTable(temp.getLengths(),
+ temp.getValues());
+ }
+
+ /**
+ * Creates a Huffman table and initializes it. The input arrays are copied.
+ * The arrays must describe a possible Huffman table. For example, 3 codes
+ * cannot be expressed with a single bit.
+ *
+ * @param lengths
+ * an array of {@code short}s where <code>lengths[k]</code> is
+ * equal to the number of values with corresponding codes of
+ * length <code>k + 1</code> bits.
+ * @param values
+ * an array of shorts containing the values in order of
+ * increasing code length.
+ * @throws IllegalArgumentException
+ * if <code>lengths</code> or <code>values</code> are null, the
+ * length of <code>lengths</code> is greater than 16, the length
+ * of <code>values</code> is greater than 256, if any value in
+ * <code>lengths</code> or <code>values</code> is less than
+ * zero, or if the arrays do not describe a valid Huffman table.
+ */
+ public JPEGHuffmanTable(short lengths[], short symbols[]) {
+ if (lengths == null)
+ throw new IllegalArgumentException("lengths array can not be null.");
+ if (symbols == null)
+ throw new IllegalArgumentException("symbols array can not be null.");
+ if (lengths.length > 17)
+ throw new IllegalArgumentException("lengths array can not be longer than 17.");
+ if (symbols.length > 256)
+ throw new IllegalArgumentException("symbols array can not be longer than 256.");
+ for (int a = 0; a < lengths.length; ++a)
+ if (lengths[a] < 0)
+ throw new IllegalArgumentException("length " + a + " is smaller than zero.");
+ for (int a = 0; a < symbols.length; ++a)
+ if (symbols[a] < 0)
+ throw new IllegalArgumentException("symbol " + a + " is smaller than zero.");
+ this.lengths = lengths;
+ this.symbols = symbols;
+ }
+
+ /**
+ * Return an array containing the number of symbols for each length in
+ * the Huffman table.
+ *
+ * @return A short array where length[a] is equal to the number of symbols
+ * in the Huffman table of length a. The first element (length[0])
+ * is unused.
+ */
+ public short[] getLengths() {
+ return lengths;
+ }
+
+ /**
+ * Return an array containing the Huffman symbols arranged by increasing
+ * length. To make use of this array you must refer to the lengths array.
+ *
+ * @return A short array of Huffman symbols
+ */
+ public short[] getSymbols() {
+ return symbols;
+ }
+}
--- jdk/src/share/classes/com/sun/image/codec/jpeg/JPEGImageDecoder.java 1969-12-31 19:00:00.000000000 -0500
+++ jdk/src/share/classes/com/sun/image/codec/jpeg/JPEGImageDecoder.java 2011-07-07 09:19:34.000000000 -0400
@@ -0,0 +1,102 @@
+/* JPEGImageDecoder.java --
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Copyright (C) 2007 Matthew Flaschen
+
+ 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 com.sun.image.codec.jpeg;
+
+import java.awt.image.BufferedImage;
+import java.awt.image.Raster;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+public interface JPEGImageDecoder {
+
+ /**
+ * Decodes the current JPEG data stream. The result of decoding this
+ * InputStream is a BufferedImage the ColorModel associated with this
+ * BufferedImage is determined based on the encoded COLOR_ID of the
+ * JPEGDecodeParam object. For a tables only stream this will return null.
+ *
+ * @return BufferedImage containing the image data.
+ * @throws ImageFormatException
+ * If irregularities in the JPEG stream or an unknown condition
+ * is encountered.
+ * @throws IOException
+ */
+ public BufferedImage decodeAsBufferedImage() throws IOException,
+ ImageFormatException;
+
+ /**
+ * Decode the JPEG stream that was passed as part of construction. The JPEG
+ * decompression will be performed according to the current settings of the
+ * JPEGDecodeParam object. For a tables only stream this will return null.
+ *
+ * @return Raster containg the image data. Colorspace and other pertinent
+ * information can be obtained from the JPEGDecodeParam object.
+ * @throws ImageFormatException
+ * If irregularities in the JPEG stream or an unknown condition
+ * is encountered.
+ * @throws IOException
+ */
+ public Raster decodeAsRaster() throws IOException, ImageFormatException;
+
+ /**
+ * Get the input stream that decoding will occur from.
+ *
+ * @return The stream that the decoder is currently associated with.
+ */
+ public InputStream getInputStream();
+
+ /**
+ * Returns the JPEGDecodeParam object that resulted from the most recent
+ * decoding event.
+ *
+ * @return
+ */
+ public JPEGDecodeParam getJPEGDecodeParam();
+
+ /**
+ * Sets the JPEGDecodeParam object used to determine the features of the
+ * decompression performed on the JPEG encoded data. This is usually only
+ * needed for decoding abbreviated JPEG data streams.
+ *
+ * @param jdp
+ * JPEGDecodeParam object
+ */
+ public void setJPEGDecodeParam(JPEGDecodeParam jdp);
+}
--- jdk/src/share/classes/com/sun/image/codec/jpeg/JPEGImageEncoder.java 1969-12-31 19:00:00.000000000 -0500
+++ jdk/src/share/classes/com/sun/image/codec/jpeg/JPEGImageEncoder.java 2011-07-07 09:19:34.000000000 -0400
@@ -0,0 +1,208 @@
+/* JPEGImageEncoder.java --
+ Copyright (C) 2007 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 com.sun.image.codec.jpeg;
+
+import java.io.OutputStream;
+import java.io.IOException;
+
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.Raster;
+
+public interface JPEGImageEncoder {
+ /**
+ * This is a factory method for creating JPEGEncodeParam objects. The
+ * returned object will do a credible job of encoding the given
+ * BufferedImage.
+ *
+ * @param bi
+ * @return
+ * @throws ImageFormatException
+ */
+ public JPEGEncodeParam getDefaultJPEGEncodeParam(BufferedImage bi)
+ throws ImageFormatException;
+
+ /**
+ * This is a factory method for creating JPEGEncodeParam objects. It is the
+ * users responsibility to match the colorID with the given number of bands,
+ * which should match the data being encoded. Failure to do so may lead to
+ * poor compression and/or poor image quality. If you don't understand much
+ * about JPEG it is strongly recommended that you stick to the BufferedImage
+ * interface.
+ *
+ * @param numBands
+ * the number of bands that will be encoded (max of four).
+ * @param colorID
+ * the COLOR_ID for the encoded data. This is used to set
+ * reasonable defaults in the parameter object. This must match
+ * the number of bands given.
+ * @return
+ * @throws ImageFormatException
+ */
+ public JPEGEncodeParam getDefaultJPEGEncodeParam(int numBands, int colorID)
+ throws ImageFormatException;
+
+ /**
+ * This is a factory method for creating a JPEGEncodeParam from a
+ * JPEGDecodeParam. This will return a new JPEGEncodeParam object that is
+ * initialized from the JPEGDecodeParam object. All major pieces of
+ * information will be initialized from the DecodeParam (Markers, Tables,
+ * mappings).
+ *
+ * @param d
+ * The JPEGDecodeParam object to copy.
+ * @return
+ * @throws ImageFormatException
+ */
+ public JPEGEncodeParam getDefaultJPEGEncodeParam(JPEGDecodeParam d)
+ throws ImageFormatException;
+
+ /**
+ * This is a factory method for creating JPEGEncodeParam objects. It is the
+ * users responsiblity to match the colorID with the data contained in the
+ * Raster. Failure to do so may lead to either poor compression or poor
+ * image quality. If you don't understand much about JPEG it is strongly
+ * reccomended that you stick to the BufferedImage interfaces.
+ *
+ * @param ras
+ * @param colorID
+ * @return
+ * @throws ImageFormatException
+ */
+ public JPEGEncodeParam getDefaultJPEGEncodeParam(Raster ras, int colorID)
+ throws ImageFormatException;
+
+ public JPEGEncodeParam getJPEGEncodeParam() throws ImageFormatException;
+
+ /**
+ * Set the JPEGEncodeParam object that is to be used for future encoding
+ * operations. 'p' is copied so changes will not be tracked, unless you call
+ * this method again.
+ *
+ * @param p
+ * The JPEGEncodeParam object to use for future encodings.
+ */
+ public void setJPEGEncodeParam(JPEGEncodeParam p);
+
+ /**
+ * Return the stream the Encoder is current associated with.
+ *
+ * @return
+ */
+ public OutputStream getOutputStream();
+
+ /**
+ * Encode a BufferedImage as a JPEG data stream. Note, some color
+ * conversions may takes place. The jep's encoded COLOR_ID should match the
+ * value returned by getDefaultColorID when given the BufferedImage's
+ * ColorModel. This call also sets the current JPEGEncodeParam object. The
+ * given JPEGEncodeParam object will be used for this and future encodings.
+ * If p is null then a new JPEGEncodeParam object will be created by calling
+ * getDefaultJPEGEncodeParam with bi.
+ *
+ * @param bi
+ * The BufferedImage to encode.
+ * @param p
+ * The JPEGEncodeParam object used to control the encoding.
+ * @throws IOException
+ * @throws ImageFormatException
+ */
+ public void encode(BufferedImage bi, JPEGEncodeParam p) throws IOException,
+ ImageFormatException;
+
+ /**
+ * Encode a Raster as a JPEG data stream. Note that no color conversion
+ * takes place. It is required that you match the Raster to the encoded
+ * COLOR_ID contained in the current JPEGEncodeParam object. If no
+ * JPEGEncodeParam object has been provided yet a new JPEGEncodeParam object
+ * will be created by calling getDefaultJPEGEncodeParam with ras and
+ * COLOR_ID_UNKNOWN.
+ *
+ * @param ras
+ * The Raster to encode.
+ * @throws IOException
+ * @throws ImageFormatException
+ */
+ public void encode(Raster ras) throws IOException, ImageFormatException;
+
+ /**
+ * Encode a BufferedImage as a JPEG data stream. Note, some color
+ * conversions may takes place. The current JPEGEncodeParam's encoded
+ * COLOR_ID should match the value returned by getDefaultColorID when given
+ * the BufferedImage's ColorModel. If no JPEGEncodeParam object has been
+ * provided yet a default one will be created by calling
+ * getDefaultJPEGEncodeParam with bi.
+ *
+ * @param bi
+ * The BufferedImage to encode.
+ * @throws IOException
+ * @throws ImageFormatException
+ */
+ public void encode(BufferedImage bi) throws IOException,
+ ImageFormatException;
+
+ /**
+ * Encode a Raster as a JPEG data stream. Note that no color conversion
+ * takes place. It is required that you match the Raster to the encoded
+ * COLOR_ID contained in the JPEGEncodeParam object. If p is null a new
+ * JPEGEncodeParam object will be created by calling
+ * getDefaultJPEGEncodeParam with ras and COLOR_ID_UNKNOWN.
+ *
+ * @param ras
+ * The Raster to encode.
+ * @param p
+ * The JPEGEncodeParam object used to control the encoding.
+ * @throws IOException
+ * @throws ImageFormatException
+ */
+ public void encode(Raster ras, JPEGEncodeParam p) throws IOException,
+ ImageFormatException;
+
+ /**
+ * Returns the 'default' encoded COLOR_ID for a given ColorModel. This
+ * method is not needed in the simple case of encoding Buffered Images (the
+ * library will figure things out for you). It can be useful for encoding
+ * Rasters. To determine what needs to be done to the image prior to
+ * encoding.
+ *
+ * @param cm
+ * The ColorModel to map to an jpeg encoded COLOR_ID.
+ * @return
+ */
+ public int getDefaultColorId(ColorModel cm);
+}
--- jdk/src/share/classes/com/sun/image/codec/jpeg/JPEGQTable.java 1969-12-31 19:00:00.000000000 -0500
+++ jdk/src/share/classes/com/sun/image/codec/jpeg/JPEGQTable.java 2011-07-07 09:19:34.000000000 -0400
@@ -0,0 +1,118 @@
+/* JPEGQTable.java --
+ Copyright (C) 2011 Red Hat
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Copyright (C) 2007 Matthew Flaschen
+
+ 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 com.sun.image.codec.jpeg;
+
+import java.util.Arrays;
+
+/**
+ * Class to encapsulate the JPEG quantization tables.
+ *
+ * Note: The tables K1Luminance, K1Div2Luminance, K2Chrominance,
+ * K2Div2Chrominance is an instance of the superclass.
+ *
+ * @author Andrew Su (asu@redhat.com)
+ *
+ */
+public class JPEGQTable {
+
+ /**
+ * Luminance quantization table (in zig-zag order).
+ */
+ public static final JPEGQTable StdLuminance;
+
+ /**
+ * Chromninance quantization table (in zig-zag order).
+ */
+ public static final JPEGQTable StdChrominance;
+
+ static {
+ /* table for luminance values in zig-zag order */
+ int[] table1 = { 16, 11, 12, 14, 12, 10, 16, 14, 13, 14, 18, 17, 16,
+ 19, 24, 40, 26, 24, 22, 22, 24, 49, 35, 37, 29, 40, 58, 51, 61,
+ 60, 57, 51, 56, 55, 64, 72, 92, 78, 64, 68, 87, 69, 55, 56, 80,
+ 109, 81, 87, 95, 98, 103, 104, 103, 62, 77, 113, 121, 112, 100,
+ 120, 92, 101, 103, 99 };
+
+ StdLuminance = new JPEGQTable(table1);
+
+ /* table for chrominance values in zig-zag order */
+ int[] table2 = { 17, 18, 18, 24, 21, 24, 47, 26, 26, 47, 99, 66, 56,
+ 66, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99 };
+ StdChrominance = new JPEGQTable(table2);
+ }
+
+ private int[] table;
+
+ /**
+ * Constructs an quantization table from the array that was passed. The
+ * coefficients must be in zig-zag order. The array must be of length 64.
+ * The table will be copied.
+ *
+ * @param table
+ * the quantization table, as an int array.
+ * @throws IllegalArgumentException
+ * if table is null or table.length is not equal to 64.
+ */
+ public JPEGQTable(int[] table) {
+ /* Table must be 8x8 thus 64 entries */
+ if (table == null || table.length != 64) {
+ throw new IllegalArgumentException("Not a valid table.");
+ }
+ this.table = Arrays.copyOf(table, table.length);
+ }
+
+ public int[] getTable() {
+ return Arrays.copyOf(table, table.length);
+ }
+
+ public JPEGQTable getScaledInstance(float scaleFactor, boolean forceBaseline) {
+ int limit = (forceBaseline) ? 255 : 32767;
+ int[] newTable = new int[table.length];
+ for (int i = 0; i < table.length; i++) {
+ int newValue = Math.round(table[i] * scaleFactor);
+ newTable[i] = (newValue < 1) ? 1 : (newValue > limit) ? limit : newValue;
+ }
+ return new JPEGQTable(newTable);
+ }
+
+}
--- jdk/src/share/classes/com/sun/image/codec/jpeg/TruncatedFileException.java 1969-12-31 19:00:00.000000000 -0500
+++ jdk/src/share/classes/com/sun/image/codec/jpeg/TruncatedFileException.java 2011-07-07 09:19:34.000000000 -0400
@@ -0,0 +1,92 @@
+/* TruncatedFileException.java
+ Copyright (C) 2007 Matthew Flaschen
+ Copyright (C) 2011 Red Hat, Inc.
+
+ This file is part of IcedTea
+
+ IcedTea 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.
+
+ IcedTea 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 com.sun.image.codec.jpeg;
+
+import java.awt.image.BufferedImage;
+import java.awt.image.Raster;
+
+public class TruncatedFileException extends RuntimeException {
+
+ private final BufferedImage bufferedImage;
+
+ private final Raster raster;
+
+ /**
+ * Creates a new exception with the specified {@link BufferedImage}
+ * containing the partially read image data.
+ *
+ * @param bufferedImage the partially decoded image (may be null).
+ */
+ public TruncatedFileException(BufferedImage bufferedImage) {
+ this.bufferedImage = bufferedImage;
+ this.raster = null;
+ }
+
+ /**
+ * Creates a new exception with the specified {@link Raster}
+ * containing the partially read image data.
+ *
+ * @param raster the partially decoded image (may be null).
+ */
+ public TruncatedFileException(Raster raster) {
+ this.raster = raster;
+ this.bufferedImage = null;
+ }
+
+ /**
+ * Returns the partially read data as a {@link BufferedImage}
+ * if available, or {@code null} if not.
+ *
+ * @return the partially read data.
+ */
+ public BufferedImage getBufferedImage() {
+ return bufferedImage;
+ }
+
+ /**
+ * Returns the partially read data as a {@link Raster}
+ * if available, or {@code null} if not.
+ *
+ * @return the partially read data.
+ */
+ public Raster getRaster() {
+ return raster;
+ }
+
+}
--- jdk/src/share/classes/sun/awt/image/codec/JPEGImageDecoderImpl.java 1969-12-31 19:00:00.000000000 -0500
+++ jdk/src/share/classes/sun/awt/image/codec/JPEGImageDecoderImpl.java 2011-07-07 09:19:34.000000000 -0400
@@ -0,0 +1,108 @@
+/* JPEGImageDecoderImpl.java -- JPEG decoder implementation
+Copyright (C) 2011 Red Hat
+
+This program 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 of the License, or
+(at your option) any later version.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package sun.awt.image.codec;
+
+import java.awt.image.BufferedImage;
+import java.awt.image.Raster;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Iterator;
+
+import javax.imageio.ImageIO;
+import javax.imageio.ImageReader;
+import javax.imageio.plugins.jpeg.JPEGHuffmanTable;
+import javax.imageio.plugins.jpeg.JPEGImageReadParam;
+import javax.imageio.plugins.jpeg.JPEGQTable;
+import javax.imageio.stream.MemoryCacheImageInputStream;
+
+import com.sun.image.codec.jpeg.ImageFormatException;
+import com.sun.image.codec.jpeg.JPEGDecodeParam;
+import com.sun.image.codec.jpeg.JPEGImageDecoder;
+import com.sun.imageio.plugins.jpeg.JPEGImageReader;
+
+/**
+ * This class provides the implementation for a JPEG decoder.
+ */
+public class JPEGImageDecoderImpl implements JPEGImageDecoder {
+ private static final String JPGMime = "image/jpeg";
+
+ private JPEGImageReader JPGReader;
+ private InputStream in;
+ private JPEGDecodeParam param;
+
+ public JPEGImageDecoderImpl(InputStream in) {
+ this(in, null);
+ }
+
+ public JPEGImageDecoderImpl(InputStream in, JPEGDecodeParam param) {
+ this.in = in;
+ setJPEGDecodeParam(param);
+
+ Iterator<ImageReader> JPGReaderIter = ImageIO
+ .getImageReadersByMIMEType(JPGMime);
+ if (JPGReaderIter.hasNext()) {
+ JPGReader = (JPEGImageReader) JPGReaderIter.next();
+ }
+
+ JPGReader.setInput(new MemoryCacheImageInputStream(in));
+ }
+
+ public BufferedImage decodeAsBufferedImage() throws IOException,
+ ImageFormatException {
+ JPEGImageReadParam irp = null;
+
+ if (param != null) {
+ // We should do more than this, but it's a start.
+ JPEGQTable[] qTables = new JPEGQTable[4];
+ JPEGHuffmanTable[] DCHuffmanTables = new JPEGHuffmanTable[4];
+ JPEGHuffmanTable[] ACHuffmanTables = new JPEGHuffmanTable[4];
+
+ for (int i = 0; i < 4; i++) {
+ qTables[i] = new JPEGQTable(param.getQTable(i).getTable());
+ com.sun.image.codec.jpeg.JPEGHuffmanTable dcHuffman = param.getDCHuffmanTable(i);
+ com.sun.image.codec.jpeg.JPEGHuffmanTable acHuffman = param.getACHuffmanTable(i);
+ DCHuffmanTables[i] = new JPEGHuffmanTable(dcHuffman.getLengths(),
+ dcHuffman.getSymbols());
+ ACHuffmanTables[i] = new JPEGHuffmanTable(acHuffman.getLengths(),
+ dcHuffman.getSymbols());
+ }
+
+ irp = new JPEGImageReadParam();
+ irp.setDecodeTables(qTables, DCHuffmanTables, ACHuffmanTables);
+ }
+
+ return JPGReader.read(0, irp);
+ }
+
+ public Raster decodeAsRaster() throws IOException, ImageFormatException {
+ return JPGReader.readRaster(0, null);
+ }
+
+ public InputStream getInputStream() {
+ return in;
+ }
+
+ public JPEGDecodeParam getJPEGDecodeParam() {
+ if (param == null) return null;
+ return (JPEGDecodeParam) param.clone();
+ }
+
+ public void setJPEGDecodeParam(JPEGDecodeParam jdp) {
+ param = jdp;
+ }
+}
--- jdk/src/share/classes/sun/awt/image/codec/JPEGImageEncoderImpl.java 1969-12-31 19:00:00.000000000 -0500
+++ jdk/src/share/classes/sun/awt/image/codec/JPEGImageEncoderImpl.java 2011-07-07 09:19:34.000000000 -0400
@@ -0,0 +1,183 @@
+/* JPEGImageEncoder.java -- JPEG encoder implementation
+Copyright (C) 2011 Red Hat
+
+This program 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 of the License, or
+(at your option) any later version.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package sun.awt.image.codec;
+
+import java.awt.color.ColorSpace;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.Raster;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import javax.imageio.IIOImage;
+import javax.imageio.ImageIO;
+import javax.imageio.ImageWriteParam;
+import javax.imageio.ImageWriter;
+import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
+import javax.imageio.stream.MemoryCacheImageOutputStream;
+
+import com.sun.image.codec.jpeg.ImageFormatException;
+import com.sun.image.codec.jpeg.JPEGCodec;
+import com.sun.image.codec.jpeg.JPEGDecodeParam;
+import com.sun.image.codec.jpeg.JPEGEncodeParam;
+import com.sun.image.codec.jpeg.JPEGImageEncoder;
+import com.sun.imageio.plugins.jpeg.JPEG;
+
+/**
+ * This class provides the implementation for encoding JPEG images.
+ *
+ */
+public class JPEGImageEncoderImpl implements JPEGImageEncoder {
+ private static final String JPGMime = "image/jpeg";
+
+ private ImageWriter JPGWriter;
+ private JPEGEncodeParam param;
+ private OutputStream out;
+
+ public JPEGImageEncoderImpl(OutputStream os) {
+ this(os, null);
+ }
+
+ public JPEGImageEncoderImpl(OutputStream out, JPEGEncodeParam newParam) {
+ this.out = out;
+ setJPEGEncodeParam(newParam);
+
+ Iterator<ImageWriter> JPGWriterIter = ImageIO
+ .getImageWritersByMIMEType(JPGMime);
+ if (JPGWriterIter.hasNext()) {
+ JPGWriter = JPGWriterIter.next();
+ }
+
+ JPGWriter.setOutput(new MemoryCacheImageOutputStream(out));
+ }
+
+ public JPEGEncodeParam getDefaultJPEGEncodeParam(BufferedImage bi)
+ throws ImageFormatException {
+ return JPEGCodec.getDefaultJPEGEncodeParam(bi);
+ }
+
+ public JPEGEncodeParam getDefaultJPEGEncodeParam(int numBands, int colorID)
+ throws ImageFormatException {
+ return JPEGCodec.getDefaultJPEGEncodeParam(numBands, colorID);
+ }
+
+ public JPEGEncodeParam getDefaultJPEGEncodeParam(JPEGDecodeParam d)
+ throws ImageFormatException {
+ return JPEGCodec.getDefaultJPEGEncodeParam(d);
+ }
+
+ public JPEGEncodeParam getDefaultJPEGEncodeParam(Raster ras, int colorID)
+ throws ImageFormatException {
+ return JPEGCodec.getDefaultJPEGEncodeParam(ras, colorID);
+ }
+
+ public JPEGEncodeParam getJPEGEncodeParam() throws ImageFormatException {
+ if (param == null)
+ return null;
+ return (JPEGEncodeParam) param.clone();
+ }
+
+ public void setJPEGEncodeParam(JPEGEncodeParam p) {
+ param = p;
+ }
+
+ public OutputStream getOutputStream() {
+ return out;
+ }
+
+ private void encode(IIOImage img) throws IOException, ImageFormatException {
+ if (JPGWriter == null)
+ throw new ImageFormatException(
+ "JPEG writer code not implemented in ImageIO");
+
+ JPEGImageWriteParam jiwp = new JPEGImageWriteParam(null);
+ ;
+ jiwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
+ if (param != null && param instanceof JPEGParam) {
+ JPEGParam jp = (JPEGParam) param;
+ jiwp.setCompressionQuality(jp.getQuality());
+ } else {
+ jiwp.setCompressionQuality(JPEG.DEFAULT_QUALITY);
+ }
+
+ JPGWriter.write(null, img, jiwp);
+ }
+
+ public void encode(BufferedImage bi, JPEGEncodeParam writeParam)
+ throws IOException, ImageFormatException {
+ setJPEGEncodeParam(writeParam);
+ encode(new IIOImage(bi, new ArrayList<BufferedImage>(), null));
+ }
+
+ public void encode(Raster rs, JPEGEncodeParam writeParam)
+ throws IOException, ImageFormatException {
+ setJPEGEncodeParam(writeParam);
+ encode(new IIOImage(rs, new ArrayList<BufferedImage>(), null));
+ }
+
+ public void encode(BufferedImage bi) throws IOException,
+ ImageFormatException {
+ encode(bi, null);
+ }
+
+ public void encode(Raster rs) throws IOException, ImageFormatException {
+ encode(rs, null);
+ }
+
+ @Override
+ public int getDefaultColorId(ColorModel cm) {
+ ColorSpace cs = cm.getColorSpace();
+ int type = cs.getType();
+ int id = -1;
+ switch (type) {
+ case ColorSpace.TYPE_GRAY:
+ id = JPEGEncodeParam.COLOR_ID_GRAY;
+ break;
+
+ case ColorSpace.TYPE_RGB:
+ id = cm.hasAlpha() ? JPEGEncodeParam.COLOR_ID_RGBA
+ : JPEGEncodeParam.COLOR_ID_RGB;
+
+ case ColorSpace.TYPE_YCbCr:
+ try {
+ if (cs == ColorSpace.getInstance(ColorSpace.CS_PYCC)) {
+ id = cm.hasAlpha() ? JPEGEncodeParam.COLOR_ID_PYCCA
+ : JPEGEncodeParam.COLOR_ID_PYCC;
+ }
+ } catch (IllegalArgumentException e) {
+ /* We know it isn't PYCC type, nothing to handle */
+ }
+ if (id == -1) {
+ id = cm.hasAlpha() ? JPEGEncodeParam.COLOR_ID_YCbCrA
+ : JPEGEncodeParam.COLOR_ID_YCbCr;
+ }
+ break;
+
+ case ColorSpace.TYPE_CMYK:
+ id = JPEGEncodeParam.COLOR_ID_CMYK;
+ break;
+
+ default:
+ id = JPEGEncodeParam.COLOR_ID_UNKNOWN;
+ }
+
+ return id;
+ }
+}
--- jdk/src/share/classes/sun/awt/image/codec/JPEGParam.java 1969-12-31 19:00:00.000000000 -0500
+++ jdk/src/share/classes/sun/awt/image/codec/JPEGParam.java 2011-07-07 09:19:34.000000000 -0400
@@ -0,0 +1,750 @@
+/* JPEGParam.java -- keeps track of encode and decode parameters for JPEG.
+ * Copyright (C) 2011 Red Hat
+ *
+ * This program 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 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package sun.awt.image.codec;
+
+import java.util.Arrays;
+
+import com.sun.image.codec.jpeg.JPEGDecodeParam;
+import com.sun.image.codec.jpeg.JPEGEncodeParam;
+import com.sun.image.codec.jpeg.JPEGHuffmanTable;
+import com.sun.image.codec.jpeg.JPEGQTable;
+import com.sun.imageio.plugins.jpeg.JPEG;
+
+/**
+ * This class encapsulates the information about encoding and decoding the JPEG
+ * image.
+ *
+ * @author Andrew Su (asu@redhat.com)
+ *
+ */
+public class JPEGParam implements JPEGEncodeParam {
+ /*
+ * NOTE: bands mean the same thing as components, trying to keep it
+ * Consistent with the documentation
+ *
+ * NOTE: subsampling is not done implementing.
+ */
+
+ private float quality = JPEG.DEFAULT_QUALITY;
+ private int colorID = -1;
+ private int width;
+ private int height;
+ private int numBands;
+ private boolean imageInfoValid = false;
+ private boolean tableInfoValid = false;
+ private JPEGQTable[] qTable = new JPEGQTable[NUM_TABLES];
+ private JPEGHuffmanTable[] acHuffmanTable = new JPEGHuffmanTable[NUM_TABLES];
+ private JPEGHuffmanTable[] dcHuffmanTable = new JPEGHuffmanTable[NUM_TABLES];
+
+ private int restartInterval = 0;
+ private int[] horizontalSubsampleComponents;
+ private int[] verticalSubsampleComponents;
+
+ /* [marker between 0xE0 to 0xEF minus 0xE0 to get index][data] */
+ private byte[][][] markers = new byte[16][][];
+ private byte[][] commentMarker = null;
+
+ /* number of components each color id has (color id from JPEGDecodeParam) */
+ private static int[] components = { 0, 1, 3, 3, 4, 3, 4, 4, 4, 4, 4, 4, };
+ private int[] qTableComponentMapping;
+ private int[] acHuffmanComponentMapping;
+ private int[] dcHuffmanComponentMapping;
+
+ /*
+ * Breakdown for marker bytes
+ * 5 for name.
+ * 2 for version.
+ * 1 for density type.
+ * 2 for x density.
+ * 2 for y density.
+ * 2 for thumbnail.
+ */
+ private byte APP0_MARKER_NUM_BYTES = 14;
+
+ public JPEGParam(JPEGEncodeParam param) {
+ this((JPEGDecodeParam) param);
+ }
+
+ public JPEGParam(JPEGDecodeParam param) {
+ this(param.getEncodedColorID(), param.getNumComponents());
+
+ setTableInfoValid(param.isTableInfoValid());
+ setImageInfoValid(param.isImageInfoValid());
+ setRestartInterval(param.getRestartInterval());
+
+ // Copy the Q tables and Huffman tables.
+ for (int i = 0; i < NUM_TABLES; i++) {
+ qTable[i] = param.getQTable(i);
+ acHuffmanTable[i] = param.getACHuffmanTable(i);
+ dcHuffmanTable[i] = param.getDCHuffmanTable(i);
+ }
+
+ // Next we want to copy the component mappings.
+ for (int i = 0; i < getNumComponents(); i++) {
+ setQTableComponentMapping(i, param.getQTableComponentMapping(i));
+ setACHuffmanComponentMapping(i,
+ param.getACHuffmanComponentMapping(i));
+ setDCHuffmanComponentMapping(i,
+ param.getDCHuffmanComponentMapping(i));
+ }
+
+ // Copy all the marker data.
+ for (int i = APP0_MARKER; i < APPF_MARKER; i++) {
+ byte[][] markerData = param.getMarkerData(i);
+ byte[][] copyMarkerData = null;
+ if (markerData != null) {
+ copyMarkerData = new byte[markerData.length][];
+ for (int j = 0; j < markerData.length; j++) {
+ copyMarkerData[j] = Arrays.copyOf(markerData[j],
+ markerData[j].length);
+ }
+ }
+ setMarkerData(i, copyMarkerData);
+ }
+
+ byte[][] commentData = param.getMarkerData(COMMENT_MARKER);
+ byte[][] copyCommentData = null;
+ if (commentData != null) {
+ copyCommentData = new byte[commentData.length][];
+ for (int i = 0; i < commentData.length; i++) {
+ copyCommentData[i] = Arrays.copyOf(commentData[i],
+ commentData[i].length);
+ }
+ setMarkerData(COMMENT_MARKER, copyCommentData);
+ }
+ }
+
+ public JPEGParam(int colorID) {
+ this(colorID, components[colorID]);
+ }
+
+ public JPEGParam(int colorID, int numBands) {
+ // We were given an invalid color id, or the number of bands given to us
+ // did not match requirements.
+ if (colorID < 0
+ || colorID >= JPEGDecodeParam.NUM_COLOR_ID
+ || (colorID != COLOR_ID_UNKNOWN && numBands != components[colorID])) {
+ throw new IllegalArgumentException();
+ }
+ this.colorID = colorID;
+ this.numBands = numBands;
+
+ initialize();
+ }
+
+ private void initialize() {
+
+ qTable[0] = JPEGQTable.StdLuminance;
+ qTable[1] = JPEGQTable.StdChrominance;
+
+ acHuffmanTable[0] = JPEGHuffmanTable.StdACLuminance;
+ acHuffmanTable[1] = JPEGHuffmanTable.StdACChrominance;
+
+ dcHuffmanTable[0] = JPEGHuffmanTable.StdDCLuminance;
+ dcHuffmanTable[1] = JPEGHuffmanTable.StdDCChrominance;
+
+ qTableComponentMapping = new int[getNumComponents()];
+ acHuffmanComponentMapping = new int[getNumComponents()];
+ dcHuffmanComponentMapping = new int[getNumComponents()];
+
+ horizontalSubsampleComponents = new int[getNumComponents()];
+ verticalSubsampleComponents = new int[getNumComponents()];
+
+ /*
+ * we can just set these to true since they are using default values
+ * right now
+ */
+ setTableInfoValid(true);
+ setImageInfoValid(true);
+
+ setMarkerData(APP0_MARKER,
+ arrayAdd(getMarkerData(APP0_MARKER), createAPP0MarkerData()));
+
+ }
+
+ private byte[] createAPP0MarkerData() {
+ byte[] data = null;
+ // Create JFIF APP0 Marker if compatible.
+ // By compatible, it must be one of the following cases.
+ // Reference:
+ // http://www.jpeg.org/public/jfif.pdf
+ // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JFIF.html
+ switch (colorID) {
+ case COLOR_ID_UNKNOWN:
+ case COLOR_ID_GRAY:
+ case COLOR_ID_RGB:
+ case COLOR_ID_YCbCr:
+ case COLOR_ID_CMYK:
+ data = new byte[APP0_MARKER_NUM_BYTES];
+
+ // Null terminated JFIF string. [5 bytes]
+ data[0] = 'J';
+ data[1] = 'F';
+ data[2] = 'I';
+ data[3] = 'F';
+ data[4] = 0x0;
+
+ // Version number [2 bytes]
+ data[5] = 1;
+ data[6] = 2;
+
+ // Density unit [1 byte]
+ data[7] = DENSITY_UNIT_ASPECT_RATIO;
+
+ // X density [2 bytes]
+ data[8] = 0;
+ data[9] = 1;
+
+ // Y density [2 bytes]
+ data[10] = 0;
+ data[11] = 1;
+
+ // Thumbnail [2 bytes]
+ data[12] = 0;
+ data[13] = 0;
+ break;
+ }
+
+ return data;
+ }
+
+ public void setQuality(float quality, boolean forceBaseline) {
+ if (quality < 0.0) {
+ quality = 0.00f;
+ } else if (quality > 1.0) {
+ quality = 1.0f;
+ }
+
+ this.quality = quality; // preserve original.
+
+ /*
+ * Since quality value of 1 is the lowest compression, we want our
+ * QTable to contain as much 1s as possible. Since scaling is by a
+ * factor, we want to invert the selection such that highest quality is
+ * 0 and lowest is 1.
+ */
+ quality = 1 - quality;
+
+ // We will scale our QTables to match the quality value given to us.
+ for (int i = 0; i < NUM_TABLES; i++) {
+ if (qTable[i] != null) {
+ qTable[i] = qTable[i].getScaledInstance(quality, forceBaseline);
+ }
+ }
+ }
+
+ public Object clone() {
+ JPEGParam c = new JPEGParam(this);
+ return c;
+ }
+
+ @Override
+ public int getWidth() {
+ return width;
+ }
+
+ @Override
+ public int getHeight() {
+ return height;
+ }
+
+ @Override
+ public int getHorizontalSubsampling(int component) {
+ if (component < 0 || component > getNumComponents()) {
+ throw new IllegalArgumentException("Invalid component");
+ }
+
+ return horizontalSubsampleComponents[component];
+ }
+
+ @Override
+ public int getVerticalSubsampling(int component) {
+ if (component < 0 || component > getNumComponents()) {
+ throw new IllegalArgumentException("Invalid component");
+ }
+
+ return verticalSubsampleComponents[component];
+ }
+
+ @Override
+ public JPEGQTable getQTable(int tableNum) {
+ if (tableNum < 0 || tableNum > NUM_TABLES)
+ throw new IllegalArgumentException("tableNum must be [0-"
+ + (NUM_TABLES - 1) + "]");
+ return qTable[tableNum];
+ }
+
+ @Override
+ public JPEGQTable getQTableForComponent(int component) {
+ if (component < 0 || component > getNumComponents()) {
+ throw new IllegalArgumentException("Invalid component");
+ }
+
+ return qTable[qTableComponentMapping[component]];
+ }
+
+ @Override
+ public JPEGHuffmanTable getDCHuffmanTable(int tableNum) {
+ if (tableNum < 0 || tableNum > NUM_TABLES)
+ throw new IllegalArgumentException("tableNum must be [0-"
+ + (NUM_TABLES - 1) + "]");
+ return dcHuffmanTable[tableNum];
+ }
+
+ @Override
+ public JPEGHuffmanTable getDCHuffmanTableForComponent(int component) {
+ if (component < 0 || component > getNumComponents()) {
+ throw new IllegalArgumentException("Invalid component");
+ }
+
+ return dcHuffmanTable[dcHuffmanComponentMapping[component]];
+ }
+
+ @Override
+ public JPEGHuffmanTable getACHuffmanTable(int tableNum) {
+ if (tableNum < 0 || tableNum > NUM_TABLES)
+ throw new IllegalArgumentException("tableNum must be [0-"
+ + (NUM_TABLES - 1) + "]");
+ return acHuffmanTable[tableNum];
+ }
+
+ @Override
+ public JPEGHuffmanTable getACHuffmanTableForComponent(int component) {
+ if (component < 0 || component > getNumComponents()) {
+ throw new IllegalArgumentException("Invalid component");
+ }
+
+ return acHuffmanTable[acHuffmanComponentMapping[component]];
+ }
+
+ @Override
+ public int getDCHuffmanComponentMapping(int component) {
+ if (component < 0 || component > getNumComponents()) {
+ throw new IllegalArgumentException("Invalid component");
+ }
+ return dcHuffmanComponentMapping[component];
+ }
+
+ @Override
+ public int getACHuffmanComponentMapping(int component) {
+ if (component < 0 || component > getNumComponents()) {
+ throw new IllegalArgumentException("Invalid component");
+ }
+ return acHuffmanComponentMapping[component];
+ }
+
+ @Override
+ public int getQTableComponentMapping(int component) {
+ if (component < 0 || component > getNumComponents()) {
+ throw new IllegalArgumentException("Invalid component");
+ }
+ return qTableComponentMapping[component];
+ }
+
+ @Override
+ public boolean isImageInfoValid() {
+ return imageInfoValid;
+ }
+
+ @Override
+ public boolean isTableInfoValid() {
+ return tableInfoValid;
+ }
+
+ @Override
+ public boolean getMarker(int marker) {
+ byte[][] data = null;
+ switch (marker) {
+ case APP0_MARKER:
+ case APP1_MARKER:
+ case APP2_MARKER:
+ case APP3_MARKER:
+ case APP4_MARKER:
+ case APP5_MARKER:
+ case APP6_MARKER:
+ case APP7_MARKER:
+ case APP8_MARKER:
+ case APP9_MARKER:
+ case APPA_MARKER:
+ case APPB_MARKER:
+ case APPC_MARKER:
+ case APPD_MARKER:
+ case APPE_MARKER:
+ case APPF_MARKER:
+ data = markers[marker - APP0_MARKER];
+ break;
+ case COMMENT_MARKER:
+ data = commentMarker;
+ break;
+ default:
+ throw new IllegalArgumentException("Marker provided is invalid");
+ }
+
+ return data != null && data.length > 0;
+ }
+
+ @Override
+ public byte[][] getMarkerData(int marker) {
+ byte[][] data = null;
+
+ switch (marker) {
+ case APP0_MARKER:
+ case APP1_MARKER:
+ case APP2_MARKER:
+ case APP3_MARKER:
+ case APP4_MARKER:
+ case APP5_MARKER:
+ case APP6_MARKER:
+ case APP7_MARKER:
+ case APP8_MARKER:
+ case APP9_MARKER:
+ case APPA_MARKER:
+ case APPB_MARKER:
+ case APPC_MARKER:
+ case APPD_MARKER:
+ case APPE_MARKER:
+ case APPF_MARKER:
+ data = markers[marker - APP0_MARKER];
+ break;
+ case COMMENT_MARKER:
+ // TODO: Add stuff for comment marker
+ break;
+ default:
+ throw new IllegalArgumentException("Marker provided is invalid");
+ }
+ return data;
+ }
+
+ @Override
+ public int getEncodedColorID() {
+ return colorID;
+ }
+
+ @Override
+ public int getNumComponents() {
+ return numBands;
+ }
+
+ @Override
+ public int getRestartInterval() {
+ return restartInterval;
+ }
+
+ @Override
+ public int getDensityUnit() {
+ if (!getMarker(APP0_MARKER))
+ throw new IllegalArgumentException("APP0 Marker not found.");
+ byte[] data = getValidAPP0Marker();
+
+ if (data == null)
+ throw new IllegalArgumentException("No valid APP0 Marker found");
+
+ return data[7];
+ }
+
+ @Override
+ public int getXDensity() {
+ if (!getMarker(APP0_MARKER))
+ throw new IllegalArgumentException("APP0 Marker not found.");
+ byte[] data = getValidAPP0Marker();
+
+ if (data == null)
+ throw new IllegalArgumentException("No valid APP0 Marker found");
+
+ // data[8] is the upper portion of the density value
+ // data[9] is the lower portion of the density value
+ int upper = data[8] << 8; // Shift it so we can merge with lower value.
+ int lower = data[9] & 0xFF; // Keep it in bounds 0 - 256
+ return upper | lower; // Merge
+
+ }
+
+ @Override
+ public int getYDensity() {
+ if (!getMarker(APP0_MARKER))
+ throw new IllegalArgumentException("APP0 Marker not found.");
+ byte[] data = getValidAPP0Marker();
+
+ if (data == null)
+ throw new IllegalArgumentException("No valid APP0 Marker found");
+
+ // data[10] is the upper portion of the density value
+ // data[11] is the lower portion of the density value
+ int upper = data[10] << 8; // Shift it so we can merge with lower value.
+ int lower = data[11] & 0xFF;// Keep it in bounds 0 - 256
+ return upper | lower; // merge
+ }
+
+ @Override
+ public void setHorizontalSubsampling(int component, int subsample) {
+ if (component < 0 || component > getNumComponents()) {
+ throw new IllegalArgumentException("Invalid component");
+ }
+
+ horizontalSubsampleComponents[component] = subsample;
+ }
+
+ @Override
+ public void setVerticalSubsampling(int component, int subsample) {
+ if (component < 0 || component > getNumComponents()) {
+ throw new IllegalArgumentException("Invalid component");
+ }
+
+ verticalSubsampleComponents[component] = subsample;
+ }
+
+ @Override
+ public void setQTable(int tableNum, JPEGQTable qTable) {
+ if (tableNum < 0 || tableNum > NUM_TABLES)
+ throw new IllegalArgumentException("tableNum must be [0-"
+ + (NUM_TABLES - 1) + "]");
+
+ this.qTable[tableNum] = qTable;
+ }
+
+ @Override
+ public void setDCHuffmanTable(int tableNum, JPEGHuffmanTable huffTable) {
+ if (tableNum < 0 || tableNum > NUM_TABLES)
+ throw new IllegalArgumentException("tableNum must be [0-"
+ + (NUM_TABLES - 1) + "]");
+
+ dcHuffmanTable[tableNum] = huffTable;
+ }
+
+ @Override
+ public void setACHuffmanTable(int tableNum, JPEGHuffmanTable huffTable) {
+ if (tableNum < 0 || tableNum > NUM_TABLES)
+ throw new IllegalArgumentException("tableNum must be [0-"
+ + (NUM_TABLES - 1) + "]");
+ acHuffmanTable[tableNum] = huffTable;
+ }
+
+ @Override
+ public void setACHuffmanComponentMapping(int component, int table) {
+ if (component < 0 || component > getNumComponents()) {
+ throw new IllegalArgumentException("Invalid component specified.");
+ } else if (table < 0 || table > NUM_TABLES) {
+ throw new IllegalArgumentException("Invalid table specified");
+ }
+
+ acHuffmanComponentMapping[component] = table;
+ }
+
+ @Override
+ public void setDCHuffmanComponentMapping(int component, int table) {
+ if (component < 0 || component > getNumComponents()) {
+ throw new IllegalArgumentException("Invalid component specified.");
+ } else if (table < 0 || table > NUM_TABLES) {
+ throw new IllegalArgumentException("Invalid table specified");
+ }
+
+ dcHuffmanComponentMapping[component] = table;
+ }
+
+ @Override
+ public void setQTableComponentMapping(int component, int table) {
+ if (component < 0 || component > getNumComponents()) {
+ throw new IllegalArgumentException("Invalid component specified.");
+ } else if (table < 0 || table > NUM_TABLES) {
+ throw new IllegalArgumentException("Invalid table specified");
+ }
+
+ qTableComponentMapping[component] = table;
+ }
+
+ @Override
+ public void setImageInfoValid(boolean flag) {
+ imageInfoValid = flag;
+ }
+
+ @Override
+ public void setTableInfoValid(boolean flag) {
+ tableInfoValid = flag;
+ }
+
+ @Override
+ public void setMarkerData(int marker, byte[][] data) {
+ if (data == null) {
+ return;
+ }
+
+ switch (marker) {
+ case APP0_MARKER:
+ case APP1_MARKER:
+ case APP2_MARKER:
+ case APP3_MARKER:
+ case APP4_MARKER:
+ case APP5_MARKER:
+ case APP6_MARKER:
+ case APP7_MARKER:
+ case APP8_MARKER:
+ case APP9_MARKER:
+ case APPA_MARKER:
+ case APPB_MARKER:
+ case APPC_MARKER:
+ case APPD_MARKER:
+ case APPE_MARKER:
+ case APPF_MARKER:
+ markers[marker - APP0_MARKER] = data;
+ break;
+ case COMMENT_MARKER:
+ commentMarker = data;
+ break;
+ default:
+ throw new IllegalArgumentException("Marker provided is invalid");
+ }
+ }
+
+ @Override
+ public void addMarkerData(int marker, byte[] data) {
+ if (data == null) {
+ return;
+ }
+ switch (marker) {
+ case APP0_MARKER:
+ case APP1_MARKER:
+ case APP2_MARKER:
+ case APP3_MARKER:
+ case APP4_MARKER:
+ case APP5_MARKER:
+ case APP6_MARKER:
+ case APP7_MARKER:
+ case APP8_MARKER:
+ case APP9_MARKER:
+ case APPA_MARKER:
+ case APPB_MARKER:
+ case APPC_MARKER:
+ case APPD_MARKER:
+ case APPE_MARKER:
+ case APPF_MARKER:
+ markers[marker - APP0_MARKER] = arrayAdd(markers[marker
+ - APP0_MARKER], data);
+ break;
+ case COMMENT_MARKER:
+ commentMarker = arrayAdd(commentMarker, data);
+ break;
+ default:
+ throw new IllegalArgumentException("Marker provided is invalid");
+ }
+ }
+
+ @Override
+ public void setRestartInterval(int restartInterval) {
+ this.restartInterval = restartInterval;
+ }
+
+ @Override
+ public void setDensityUnit(int unit) {
+ if (unit < 0 || unit > NUM_DENSITY_UNIT) {
+ throw new IllegalArgumentException("Invalid density unit.");
+ }
+
+ byte[] data = getValidAPP0Marker();
+ if (data == null) { // We will create one now.
+ data = createAPP0MarkerData();
+ // markers[0] = array of APP0_MARKER
+ markers[0] = arrayAdd(markers[0], data);
+ }
+
+ data[7] = (byte) unit;
+ }
+
+ @Override
+ public void setXDensity(int density) {
+ byte[] data = getValidAPP0Marker();
+ if (data == null) { // We will create one now.
+ data = createAPP0MarkerData();
+ // markers[0] = array of APP0_MARKER
+ markers[0] = arrayAdd(markers[0], data);
+ }
+
+ byte upper = (byte) (density >>> 8 & 0xFF); // unsigned shift to keep it
+ // positive
+ byte lower = (byte) (density & 0xFF);
+ data[8] = upper;
+ data[9] = lower;
+ }
+
+ @Override
+ public void setYDensity(int density) {
+ byte[] data = getValidAPP0Marker();
+ if (data == null) { // We will create one now.
+ data = createAPP0MarkerData();
+ // markers[0] = array of APP0_MARKER
+ markers[0] = arrayAdd(markers[0], data);
+ }
+
+ byte upper = (byte) (density >>> 8 & 0xFF); // unsigned shift to keep it
+ // positive
+ byte lower = (byte) (density & 0xFF);
+ data[10] = upper;
+ data[11] = lower;
+ }
+
+ public void setWidth(int width) {
+ this.width = width;
+ }
+
+ public void setHeight(int height) {
+ this.height = height;
+ }
+
+ /**
+ * get the quality value.
+ *
+ * @return currently set quality value.
+ */
+ public float getQuality() {
+ return quality;
+ }
+
+ /**
+ * Appends new data to original array
+ *
+ * @param origArr
+ * @param newArr
+ * @return
+ */
+ private byte[][] arrayAdd(byte[][] origArr, byte[] newArr) {
+ byte[][] newData;
+ if (origArr != null) {
+ newData = Arrays.copyOf(origArr, origArr.length + 1);
+ newData[origArr.length] = Arrays.copyOf(newArr, newArr.length);
+ } else {
+ newData = new byte[1][];
+ newData[0] = Arrays.copyOf(newArr, newArr.length);
+ }
+
+ return newData;
+ }
+
+ private byte[] getValidAPP0Marker() {
+ byte[][] app0Markers = getMarkerData(APP0_MARKER);
+ for (int i = 0; i < app0Markers.length; i++) {
+ byte[] data = app0Markers[i];
+ if (data[0] == 'J' && data[1] == 'F' && data[2] == 'I'
+ && data[3] == 'F' && data[4] == 0x0) {
+ if (data[5] <= 1) { // version is 1 or below.
+ // We have a valid JFIF header.
+ return data;
+ }
+ }
+ }
+ return null;
+ }
+}