--- 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; + +/** + *

+ * 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. + *

+ *

+ * 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. + *

+ *

+ * 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. + *

+ * DECODING: + * + *
+ * 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 **
+ * 
+ *

+ * 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 + *

+ *

+ * 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. + *

+ */ +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; + +/** + *

+ * 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. + *

+ *

+ * 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. + *

+ *

+ * 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. + *

+ *

+ * 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. + *

+ * + * ENCODING: + * + *
+ * 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
+ * 
+ *

+ * 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. + *

+ *

+ * 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. + *

+ *

+ * 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. + *

+ */ +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 lengths[k] is + * equal to the number of values with corresponding codes of + * length k + 1 bits. + * @param values + * an array of shorts containing the values in order of + * increasing code length. + * @throws IllegalArgumentException + * if lengths or values are null, the + * length of lengths is greater than 16, the length + * of values is greater than 256, if any value in + * lengths or values 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 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 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(), null)); + } + + public void encode(Raster rs, JPEGEncodeParam writeParam) + throws IOException, ImageFormatException { + setJPEGEncodeParam(writeParam); + encode(new IIOImage(rs, new ArrayList(), 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; + } +}