changeset 290:91087975bff7

6662775: Move imaging and color classes from closed to open Reviewed-by: tdv, campbell
author prr
date Thu, 10 Apr 2008 16:28:45 -0700
parents bda7549ac1d0
children aaa5637a841d
files make/common/internal/BinaryPlugs.gmk make/java/awt/Makefile src/share/classes/java/awt/color/CMMException.java src/share/classes/java/awt/color/ColorSpace.java src/share/classes/java/awt/color/ICC_ColorSpace.java src/share/classes/java/awt/color/ICC_Profile.java src/share/classes/java/awt/color/ICC_ProfileGray.java src/share/classes/java/awt/color/ICC_ProfileRGB.java src/share/classes/java/awt/image/BandedSampleModel.java src/share/classes/java/awt/image/ColorConvertOp.java src/share/classes/java/awt/image/ComponentSampleModel.java src/share/classes/java/awt/image/DataBuffer.java src/share/classes/java/awt/image/DataBufferByte.java src/share/classes/java/awt/image/DataBufferInt.java src/share/classes/java/awt/image/DataBufferShort.java src/share/classes/java/awt/image/DataBufferUShort.java src/share/classes/java/awt/image/MultiPixelPackedSampleModel.java src/share/classes/java/awt/image/Raster.java src/share/classes/java/awt/image/RenderedImage.java src/share/classes/java/awt/image/SampleModel.java src/share/classes/java/awt/image/SinglePixelPackedSampleModel.java src/share/classes/java/awt/image/WritableRaster.java src/share/classes/java/awt/image/WritableRenderedImage.java src/share/classes/java/awt/image/renderable/ContextualRenderedImageFactory.java src/share/classes/java/awt/image/renderable/RenderContext.java src/share/classes/java/awt/image/renderable/RenderableImage.java src/share/classes/java/awt/image/renderable/RenderableImageOp.java src/share/classes/java/awt/image/renderable/RenderableImageProducer.java src/share/classes/java/awt/image/renderable/RenderedImageFactory.java
diffstat 29 files changed, 15620 insertions(+), 59 deletions(-) [+]
line wrap: on
line diff
--- a/make/common/internal/BinaryPlugs.gmk	Thu Apr 10 10:32:31 2008 -0700
+++ b/make/common/internal/BinaryPlugs.gmk	Thu Apr 10 16:28:45 2008 -0700
@@ -126,44 +126,10 @@
 com/sun/media/sound/SimpleInputDeviceProvider\$$InputDeviceInfo.class \
 com/sun/media/sound/SimpleInputDeviceProvider.class
 
-PLUG_AWT_CLASS_NAMES = \
-java/awt/color/CMMException.class \
-java/awt/color/ColorSpace.class \
-java/awt/color/ICC_ColorSpace.class \
-java/awt/color/ICC_Profile\$$1.class \
-java/awt/color/ICC_Profile\$$2.class \
-java/awt/color/ICC_Profile\$$3.class \
-java/awt/color/ICC_Profile.class \
-java/awt/color/ICC_ProfileGray.class \
-java/awt/color/ICC_ProfileRGB.class \
-java/awt/image/BandedSampleModel.class \
-java/awt/image/ColorConvertOp.class \
-java/awt/image/ComponentSampleModel.class \
-java/awt/image/DataBuffer\$$1.class \
-java/awt/image/DataBuffer.class \
-java/awt/image/DataBufferByte.class \
-java/awt/image/DataBufferInt.class \
-java/awt/image/DataBufferShort.class \
-java/awt/image/DataBufferUShort.class \
-java/awt/image/MultiPixelPackedSampleModel.class \
-java/awt/image/Raster.class \
-java/awt/image/RenderedImage.class \
-java/awt/image/SampleModel.class \
-java/awt/image/SinglePixelPackedSampleModel.class \
-java/awt/image/WritableRaster.class \
-java/awt/image/WritableRenderedImage.class \
-java/awt/image/renderable/ContextualRenderedImageFactory.class \
-java/awt/image/renderable/ParameterBlock.class \
-java/awt/image/renderable/RenderContext.class \
-java/awt/image/renderable/RenderableImage.class \
-java/awt/image/renderable/RenderableImageOp.class \
-java/awt/image/renderable/RenderableImageProducer.class \
-java/awt/image/renderable/RenderedImageFactory.class
-
 # Class list temp files (used by both import and export of plugs)
 
 PLUG_TEMPDIR=$(ABS_TEMPDIR)/plugs
-PLUG_CLASS_AREAS = jmf sound awt
+PLUG_CLASS_AREAS = jmf sound
 PLUG_CLISTS = $(PLUG_CLASS_AREAS:%=$(PLUG_TEMPDIR)/%.clist)
 
 # Create jargs file command
@@ -186,11 +152,6 @@
 	@for i in $(PLUG_SOUND_CLASS_NAMES) ; do \
 	  $(ECHO) "$$i" >> $@ ; \
 	done
-$(PLUG_TEMPDIR)/awt.clist:
-	@$(prep-target)
-	@for i in $(PLUG_AWT_CLASS_NAMES) ; do \
-	  $(ECHO) "$$i" >> $@ ; \
-	done
 $(PLUG_TEMPDIR)/all.clist: $(PLUG_CLISTS)
 	@$(prep-target)
 	$(CAT) $(PLUG_CLISTS) > $@
@@ -198,8 +159,6 @@
 	$(plug-create-jargs)
 $(PLUG_TEMPDIR)/sound.jargs: $(PLUG_TEMPDIR)/sound.clist
 	$(plug-create-jargs)
-$(PLUG_TEMPDIR)/awt.jargs: $(PLUG_TEMPDIR)/awt.clist
-	$(plug-create-jargs)
 $(PLUG_TEMPDIR)/all.jargs: $(PLUG_TEMPDIR)/all.clist
 	$(plug-create-jargs)
 
@@ -235,15 +194,12 @@
 	$(call import-binary-plug-classes,$(PLUG_TEMPDIR)/jmf.clist)
 import-binary-plug-sound-classes: $(PLUG_IMPORT_JARFILE) $(PLUG_TEMPDIR)/sound.clist
 	$(call import-binary-plug-classes,$(PLUG_TEMPDIR)/sound.clist)
-import-binary-plug-awt-classes: $(PLUG_IMPORT_JARFILE) $(PLUG_TEMPDIR)/awt.clist
-	$(call import-binary-plug-classes,$(PLUG_TEMPDIR)/awt.clist)
 
 # Import all classes from the jar file
 
 import-binary-plug-jar: \
 	     import-binary-plug-jmf-classes \
-	     import-binary-plug-sound-classes \
-	     import-binary-plug-awt-classes
+	     import-binary-plug-sound-classes
 
 # Import native libraries
 
@@ -286,7 +242,6 @@
 	import-binary-plug-jar \
         import-binary-plug-jmf-classes \
         import-binary-plug-sound-classes \
-	import-binary-plug-awt-classes \
         import-binary-plug-jsound-library
 
 else # !OPENJDK
--- a/make/java/awt/Makefile	Thu Apr 10 10:32:31 2008 -0700
+++ b/make/java/awt/Makefile	Thu Apr 10 16:28:45 2008 -0700
@@ -28,24 +28,12 @@
 PRODUCT = sun
 include $(BUILDDIR)/common/Defs.gmk
 
-# WARNING: Make sure the OPENJDK plugs are up-to-date, see make/common/internal/BinaryPlugs.gmk
 
 #
 # Files
 #
 AUTO_FILES_JAVA_DIRS = java/awt sun/awt/geom
 
-#
-# Specific to OPENJDK
-#
-ifdef OPENJDK
-
-build: import-binary-plug-awt-classes
-
-include $(BUILDDIR)/common/internal/BinaryPlugs.gmk
-
-endif
-
 build: properties cursors
 
 #
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/awt/color/CMMException.java	Thu Apr 10 16:28:45 2008 -0700
@@ -0,0 +1,57 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+    Created by gbp, October 25, 1997
+
+ *
+ */
+/**********************************************************************
+ **********************************************************************
+ **********************************************************************
+ *** COPYRIGHT (c) Eastman Kodak Company, 1997                      ***
+ *** As  an unpublished  work pursuant to Title 17 of the United    ***
+ *** States Code.  All rights reserved.                             ***
+ **********************************************************************
+ **********************************************************************
+ **********************************************************************/
+
+
+package java.awt.color;
+
+
+/**
+ * This exception is thrown if the native CMM returns an error.
+ */
+
+public class CMMException extends java.lang.RuntimeException {
+
+    /**
+     *  Constructs a CMMException with the specified detail message.
+     *  @param s the specified detail message
+     */
+    public CMMException (String s) {
+        super (s);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/awt/color/ColorSpace.java	Thu Apr 10 16:28:45 2008 -0700
@@ -0,0 +1,611 @@
+/*
+ * Portions Copyright 1997-2006 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/**********************************************************************
+ **********************************************************************
+ **********************************************************************
+ *** COPYRIGHT (c) Eastman Kodak Company, 1997                      ***
+ *** As  an unpublished  work pursuant to Title 17 of the United    ***
+ *** States Code.  All rights reserved.                             ***
+ **********************************************************************
+ **********************************************************************
+ **********************************************************************/
+
+package java.awt.color;
+
+import sun.java2d.cmm.PCMM;
+import sun.java2d.cmm.CMSManager;
+
+
+/**
+ * This abstract class is used to serve as a color space tag to identify the
+ * specific color space of a Color object or, via a ColorModel object,
+ * of an Image, a BufferedImage, or a GraphicsDevice.  It contains
+ * methods that transform colors in a specific color space to/from sRGB
+ * and to/from a well-defined CIEXYZ color space.
+ * <p>
+ * For purposes of the methods in this class, colors are represented as
+ * arrays of color components represented as floats in a normalized range
+ * defined by each ColorSpace.  For many ColorSpaces (e.g. sRGB), this
+ * range is 0.0 to 1.0.  However, some ColorSpaces have components whose
+ * values have a different range.  Methods are provided to inquire per
+ * component minimum and maximum normalized values.
+ * <p>
+ * Several variables are defined for purposes of referring to color
+ * space types (e.g. TYPE_RGB, TYPE_XYZ, etc.) and to refer to specific
+ * color spaces (e.g. CS_sRGB and CS_CIEXYZ).
+ * sRGB is a proposed standard RGB color space.  For more information,
+ * see <A href="http://www.w3.org/pub/WWW/Graphics/Color/sRGB.html">
+ * http://www.w3.org/pub/WWW/Graphics/Color/sRGB.html
+ * </A>.
+ * <p>
+ * The purpose of the methods to transform to/from the well-defined
+ * CIEXYZ color space is to support conversions between any two color
+ * spaces at a reasonably high degree of accuracy.  It is expected that
+ * particular implementations of subclasses of ColorSpace (e.g.
+ * ICC_ColorSpace) will support high performance conversion based on
+ * underlying platform color management systems.
+ * <p>
+ * The CS_CIEXYZ space used by the toCIEXYZ/fromCIEXYZ methods can be
+ * described as follows:
+<pre>
+
+&nbsp;     CIEXYZ
+&nbsp;     viewing illuminance: 200 lux
+&nbsp;     viewing white point: CIE D50
+&nbsp;     media white point: "that of a perfectly reflecting diffuser" -- D50
+&nbsp;     media black point: 0 lux or 0 Reflectance
+&nbsp;     flare: 1 percent
+&nbsp;     surround: 20percent of the media white point
+&nbsp;     media description: reflection print (i.e., RLAB, Hunt viewing media)
+&nbsp;     note: For developers creating an ICC profile for this conversion
+&nbsp;           space, the following is applicable.  Use a simple Von Kries
+&nbsp;           white point adaptation folded into the 3X3 matrix parameters
+&nbsp;           and fold the flare and surround effects into the three
+&nbsp;           one-dimensional lookup tables (assuming one uses the minimal
+&nbsp;           model for monitors).
+
+</pre>
+ *
+ * <p>
+ * @see ICC_ColorSpace
+ */
+
+
+
+public abstract class ColorSpace implements java.io.Serializable {
+
+    static final long serialVersionUID = -409452704308689724L;
+
+    private int type;
+    private int numComponents;
+    private transient String [] compName = null;
+
+    // Cache of singletons for the predefined color spaces.
+    private static ColorSpace sRGBspace;
+    private static ColorSpace XYZspace;
+    private static ColorSpace PYCCspace;
+    private static ColorSpace GRAYspace;
+    private static ColorSpace LINEAR_RGBspace;
+
+    /**
+     * Any of the family of XYZ color spaces.
+     */
+    public static final int TYPE_XYZ = 0;
+
+    /**
+     * Any of the family of Lab color spaces.
+     */
+    public static final int TYPE_Lab = 1;
+
+    /**
+     * Any of the family of Luv color spaces.
+     */
+    public static final int TYPE_Luv = 2;
+
+    /**
+     * Any of the family of YCbCr color spaces.
+     */
+    public static final int TYPE_YCbCr = 3;
+
+    /**
+     * Any of the family of Yxy color spaces.
+     */
+    public static final int TYPE_Yxy = 4;
+
+    /**
+     * Any of the family of RGB color spaces.
+     */
+    public static final int TYPE_RGB = 5;
+
+    /**
+     * Any of the family of GRAY color spaces.
+     */
+    public static final int TYPE_GRAY = 6;
+
+    /**
+     * Any of the family of HSV color spaces.
+     */
+    public static final int TYPE_HSV = 7;
+
+    /**
+     * Any of the family of HLS color spaces.
+     */
+    public static final int TYPE_HLS = 8;
+
+    /**
+     * Any of the family of CMYK color spaces.
+     */
+    public static final int TYPE_CMYK = 9;
+
+    /**
+     * Any of the family of CMY color spaces.
+     */
+    public static final int TYPE_CMY = 11;
+
+    /**
+     * Generic 2 component color spaces.
+     */
+    public static final int TYPE_2CLR = 12;
+
+    /**
+     * Generic 3 component color spaces.
+     */
+    public static final int TYPE_3CLR = 13;
+
+    /**
+     * Generic 4 component color spaces.
+     */
+    public static final int TYPE_4CLR = 14;
+
+    /**
+     * Generic 5 component color spaces.
+     */
+    public static final int TYPE_5CLR = 15;
+
+    /**
+     * Generic 6 component color spaces.
+     */
+    public static final int TYPE_6CLR = 16;
+
+    /**
+     * Generic 7 component color spaces.
+     */
+    public static final int TYPE_7CLR = 17;
+
+    /**
+     * Generic 8 component color spaces.
+     */
+    public static final int TYPE_8CLR = 18;
+
+    /**
+     * Generic 9 component color spaces.
+     */
+    public static final int TYPE_9CLR = 19;
+
+    /**
+     * Generic 10 component color spaces.
+     */
+    public static final int TYPE_ACLR = 20;
+
+    /**
+     * Generic 11 component color spaces.
+     */
+    public static final int TYPE_BCLR = 21;
+
+    /**
+     * Generic 12 component color spaces.
+     */
+    public static final int TYPE_CCLR = 22;
+
+    /**
+     * Generic 13 component color spaces.
+     */
+    public static final int TYPE_DCLR = 23;
+
+    /**
+     * Generic 14 component color spaces.
+     */
+    public static final int TYPE_ECLR = 24;
+
+    /**
+     * Generic 15 component color spaces.
+     */
+    public static final int TYPE_FCLR = 25;
+
+    /**
+     * The sRGB color space defined at
+     * <A href="http://www.w3.org/pub/WWW/Graphics/Color/sRGB.html">
+     * http://www.w3.org/pub/WWW/Graphics/Color/sRGB.html
+     * </A>.
+     */
+    public static final int CS_sRGB = 1000;
+
+    /**
+     * A built-in linear RGB color space.  This space is based on the
+     * same RGB primaries as CS_sRGB, but has a linear tone reproduction curve.
+     */
+    public static final int CS_LINEAR_RGB = 1004;
+
+    /**
+     * The CIEXYZ conversion color space defined above.
+     */
+    public static final int CS_CIEXYZ = 1001;
+
+    /**
+     * The Photo YCC conversion color space.
+     */
+    public static final int CS_PYCC = 1002;
+
+    /**
+     * The built-in linear gray scale color space.
+     */
+    public static final int CS_GRAY = 1003;
+
+
+    /**
+     * Constructs a ColorSpace object given a color space type
+     * and the number of components.
+     * @param type one of the <CODE>ColorSpace</CODE> type constants
+     * @param numcomponents the number of components in the color space
+     */
+    protected ColorSpace (int type, int numcomponents) {
+        this.type = type;
+        this.numComponents = numcomponents;
+    }
+
+
+    /**
+     * Returns a ColorSpace representing one of the specific
+     * predefined color spaces.
+     * @param colorspace a specific color space identified by one of
+     *        the predefined class constants (e.g. CS_sRGB, CS_LINEAR_RGB,
+     *        CS_CIEXYZ, CS_GRAY, or CS_PYCC)
+     * @return the requested <CODE>ColorSpace</CODE> object
+     */
+    // NOTE: This method may be called by privileged threads.
+    //       DO NOT INVOKE CLIENT CODE ON THIS THREAD!
+    public static ColorSpace getInstance (int colorspace)
+    {
+    ColorSpace    theColorSpace;
+
+        switch (colorspace) {
+        case CS_sRGB:
+            synchronized(ColorSpace.class) {
+                if (sRGBspace == null) {
+                    ICC_Profile theProfile = ICC_Profile.getInstance (CS_sRGB);
+                    sRGBspace = new ICC_ColorSpace (theProfile);
+                }
+
+                theColorSpace = sRGBspace;
+            }
+            break;
+
+        case CS_CIEXYZ:
+            synchronized(ColorSpace.class) {
+                if (XYZspace == null) {
+                    ICC_Profile theProfile =
+                        ICC_Profile.getInstance (CS_CIEXYZ);
+                    XYZspace = new ICC_ColorSpace (theProfile);
+                }
+
+                theColorSpace = XYZspace;
+            }
+            break;
+
+        case CS_PYCC:
+            synchronized(ColorSpace.class) {
+                if (PYCCspace == null) {
+                    ICC_Profile theProfile = ICC_Profile.getInstance (CS_PYCC);
+                    PYCCspace = new ICC_ColorSpace (theProfile);
+                }
+
+                theColorSpace = PYCCspace;
+            }
+            break;
+
+
+        case CS_GRAY:
+            synchronized(ColorSpace.class) {
+                if (GRAYspace == null) {
+                    ICC_Profile theProfile = ICC_Profile.getInstance (CS_GRAY);
+                    GRAYspace = new ICC_ColorSpace (theProfile);
+                    /* to allow access from java.awt.ColorModel */
+                    CMSManager.GRAYspace = GRAYspace;
+                }
+
+                theColorSpace = GRAYspace;
+            }
+            break;
+
+
+        case CS_LINEAR_RGB:
+            synchronized(ColorSpace.class) {
+                if (LINEAR_RGBspace == null) {
+                    ICC_Profile theProfile =
+                        ICC_Profile.getInstance(CS_LINEAR_RGB);
+                    LINEAR_RGBspace = new ICC_ColorSpace (theProfile);
+                    /* to allow access from java.awt.ColorModel */
+                    CMSManager.LINEAR_RGBspace = LINEAR_RGBspace;
+                }
+
+                theColorSpace = LINEAR_RGBspace;
+            }
+            break;
+
+
+        default:
+            throw new IllegalArgumentException ("Unknown color space");
+        }
+
+        return theColorSpace;
+    }
+
+
+    /**
+     * Returns true if the ColorSpace is CS_sRGB.
+     * @return <CODE>true</CODE> if this is a <CODE>CS_sRGB</CODE> color
+     *         space, <code>false</code> if it is not
+     */
+    public boolean isCS_sRGB () {
+        /* REMIND - make sure we know sRGBspace exists already */
+        return (this == sRGBspace);
+    }
+
+    /**
+     * Transforms a color value assumed to be in this ColorSpace
+     * into a value in the default CS_sRGB color space.
+     * <p>
+     * This method transforms color values using algorithms designed
+     * to produce the best perceptual match between input and output
+     * colors.  In order to do colorimetric conversion of color values,
+     * you should use the <code>toCIEXYZ</code>
+     * method of this color space to first convert from the input
+     * color space to the CS_CIEXYZ color space, and then use the
+     * <code>fromCIEXYZ</code> method of the CS_sRGB color space to
+     * convert from CS_CIEXYZ to the output color space.
+     * See {@link #toCIEXYZ(float[]) toCIEXYZ} and
+     * {@link #fromCIEXYZ(float[]) fromCIEXYZ} for further information.
+     * <p>
+     * @param colorvalue a float array with length of at least the number
+     *        of components in this ColorSpace
+     * @return a float array of length 3
+     * @throws ArrayIndexOutOfBoundsException if array length is not
+     *         at least the number of components in this ColorSpace
+     */
+    public abstract float[] toRGB(float[] colorvalue);
+
+
+    /**
+     * Transforms a color value assumed to be in the default CS_sRGB
+     * color space into this ColorSpace.
+     * <p>
+     * This method transforms color values using algorithms designed
+     * to produce the best perceptual match between input and output
+     * colors.  In order to do colorimetric conversion of color values,
+     * you should use the <code>toCIEXYZ</code>
+     * method of the CS_sRGB color space to first convert from the input
+     * color space to the CS_CIEXYZ color space, and then use the
+     * <code>fromCIEXYZ</code> method of this color space to
+     * convert from CS_CIEXYZ to the output color space.
+     * See {@link #toCIEXYZ(float[]) toCIEXYZ} and
+     * {@link #fromCIEXYZ(float[]) fromCIEXYZ} for further information.
+     * <p>
+     * @param rgbvalue a float array with length of at least 3
+     * @return a float array with length equal to the number of
+     *         components in this ColorSpace
+     * @throws ArrayIndexOutOfBoundsException if array length is not
+     *         at least 3
+     */
+    public abstract float[] fromRGB(float[] rgbvalue);
+
+
+    /**
+     * Transforms a color value assumed to be in this ColorSpace
+     * into the CS_CIEXYZ conversion color space.
+     * <p>
+     * This method transforms color values using relative colorimetry,
+     * as defined by the International Color Consortium standard.  This
+     * means that the XYZ values returned by this method are represented
+     * relative to the D50 white point of the CS_CIEXYZ color space.
+     * This representation is useful in a two-step color conversion
+     * process in which colors are transformed from an input color
+     * space to CS_CIEXYZ and then to an output color space.  This
+     * representation is not the same as the XYZ values that would
+     * be measured from the given color value by a colorimeter.
+     * A further transformation is necessary to compute the XYZ values
+     * that would be measured using current CIE recommended practices.
+     * See the {@link ICC_ColorSpace#toCIEXYZ(float[]) toCIEXYZ} method of
+     * <code>ICC_ColorSpace</code> for further information.
+     * <p>
+     * @param colorvalue a float array with length of at least the number
+     *        of components in this ColorSpace
+     * @return a float array of length 3
+     * @throws ArrayIndexOutOfBoundsException if array length is not
+     *         at least the number of components in this ColorSpace.
+     */
+    public abstract float[] toCIEXYZ(float[] colorvalue);
+
+
+    /**
+     * Transforms a color value assumed to be in the CS_CIEXYZ conversion
+     * color space into this ColorSpace.
+     * <p>
+     * This method transforms color values using relative colorimetry,
+     * as defined by the International Color Consortium standard.  This
+     * means that the XYZ argument values taken by this method are represented
+     * relative to the D50 white point of the CS_CIEXYZ color space.
+     * This representation is useful in a two-step color conversion
+     * process in which colors are transformed from an input color
+     * space to CS_CIEXYZ and then to an output color space.  The color
+     * values returned by this method are not those that would produce
+     * the XYZ value passed to the method when measured by a colorimeter.
+     * If you have XYZ values corresponding to measurements made using
+     * current CIE recommended practices, they must be converted to D50
+     * relative values before being passed to this method.
+     * See the {@link ICC_ColorSpace#fromCIEXYZ(float[]) fromCIEXYZ} method of
+     * <code>ICC_ColorSpace</code> for further information.
+     * <p>
+     * @param colorvalue a float array with length of at least 3
+     * @return a float array with length equal to the number of
+     *         components in this ColorSpace
+     * @throws ArrayIndexOutOfBoundsException if array length is not
+     *         at least 3
+     */
+    public abstract float[] fromCIEXYZ(float[] colorvalue);
+
+    /**
+     * Returns the color space type of this ColorSpace (for example
+     * TYPE_RGB, TYPE_XYZ, ...).  The type defines the
+     * number of components of the color space and the interpretation,
+     * e.g. TYPE_RGB identifies a color space with three components - red,
+     * green, and blue.  It does not define the particular color
+     * characteristics of the space, e.g. the chromaticities of the
+     * primaries.
+     *
+     * @return the type constant that represents the type of this
+     *         <CODE>ColorSpace</CODE>
+     */
+    public int getType() {
+        return type;
+    }
+
+    /**
+     * Returns the number of components of this ColorSpace.
+     * @return The number of components in this <CODE>ColorSpace</CODE>.
+     */
+    public int getNumComponents() {
+        return numComponents;
+    }
+
+    /**
+     * Returns the name of the component given the component index.
+     *
+     * @param idx the component index
+     * @return the name of the component at the specified index
+     * @throws IllegalArgumentException if <code>idx</code> is
+     *         less than 0 or greater than numComponents - 1
+     */
+    public String getName (int idx) {
+        /* REMIND - handle common cases here */
+        if ((idx < 0) || (idx > numComponents - 1)) {
+            throw new IllegalArgumentException(
+                "Component index out of range: " + idx);
+        }
+
+        if (compName == null) {
+            switch (type) {
+                case ColorSpace.TYPE_XYZ:
+                    compName = new String[] {"X", "Y", "Z"};
+                    break;
+                case ColorSpace.TYPE_Lab:
+                    compName = new String[] {"L", "a", "b"};
+                    break;
+                case ColorSpace.TYPE_Luv:
+                    compName = new String[] {"L", "u", "v"};
+                    break;
+                case ColorSpace.TYPE_YCbCr:
+                    compName = new String[] {"Y", "Cb", "Cr"};
+                    break;
+                case ColorSpace.TYPE_Yxy:
+                    compName = new String[] {"Y", "x", "y"};
+                    break;
+                case ColorSpace.TYPE_RGB:
+                    compName = new String[] {"Red", "Green", "Blue"};
+                    break;
+                case ColorSpace.TYPE_GRAY:
+                    compName = new String[] {"Gray"};
+                    break;
+                case ColorSpace.TYPE_HSV:
+                    compName = new String[] {"Hue", "Saturation", "Value"};
+                    break;
+                case ColorSpace.TYPE_HLS:
+                    compName = new String[] {"Hue", "Lightness",
+                                             "Saturation"};
+                    break;
+                case ColorSpace.TYPE_CMYK:
+                    compName = new String[] {"Cyan", "Magenta", "Yellow",
+                                             "Black"};
+                    break;
+                case ColorSpace.TYPE_CMY:
+                    compName = new String[] {"Cyan", "Magenta", "Yellow"};
+                    break;
+                default:
+                    String [] tmp = new String[numComponents];
+                    for (int i = 0; i < tmp.length; i++) {
+                        tmp[i] = "Unnamed color component(" + i + ")";
+                    }
+                    compName = tmp;
+            }
+        }
+        return compName[idx];
+    }
+
+    /**
+     * Returns the minimum normalized color component value for the
+     * specified component.  The default implementation in this abstract
+     * class returns 0.0 for all components.  Subclasses should override
+     * this method if necessary.
+     *
+     * @param component the component index
+     * @return the minimum normalized component value
+     * @throws IllegalArgumentException if component is less than 0 or
+     *         greater than numComponents - 1
+     * @since 1.4
+     */
+    public float getMinValue(int component) {
+        if ((component < 0) || (component > numComponents - 1)) {
+            throw new IllegalArgumentException(
+                "Component index out of range: " + component);
+        }
+        return 0.0f;
+    }
+
+    /**
+     * Returns the maximum normalized color component value for the
+     * specified component.  The default implementation in this abstract
+     * class returns 1.0 for all components.  Subclasses should override
+     * this method if necessary.
+     *
+     * @param component the component index
+     * @return the maximum normalized component value
+     * @throws IllegalArgumentException if component is less than 0 or
+     *         greater than numComponents - 1
+     * @since 1.4
+     */
+    public float getMaxValue(int component) {
+        if ((component < 0) || (component > numComponents - 1)) {
+            throw new IllegalArgumentException(
+                "Component index out of range: " + component);
+        }
+        return 1.0f;
+    }
+
+    /* Returns true if cspace is the XYZspace.
+     */
+    static boolean isCS_CIEXYZ(ColorSpace cspace) {
+        return (cspace == XYZspace);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/awt/color/ICC_ColorSpace.java	Thu Apr 10 16:28:45 2008 -0700
@@ -0,0 +1,616 @@
+/*
+ * Portions Copyright 1997-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/**********************************************************************
+ **********************************************************************
+ **********************************************************************
+ *** COPYRIGHT (c) Eastman Kodak Company, 1997                      ***
+ *** As  an unpublished  work pursuant to Title 17 of the United    ***
+ *** States Code.  All rights reserved.                             ***
+ **********************************************************************
+ **********************************************************************
+ **********************************************************************/
+
+package java.awt.color;
+
+import sun.java2d.cmm.ColorTransform;
+import sun.java2d.cmm.CMSManager;
+import sun.java2d.cmm.PCMM;
+
+
+/**
+ *
+ * The ICC_ColorSpace class is an implementation of the abstract
+ * ColorSpace class.  This representation of
+ * device independent and device dependent color spaces is based on the
+ * International Color Consortium Specification ICC.1:2001-12, File Format for
+ * Color Profiles (see <A href="http://www.color.org">http://www.color.org</A>).
+ * <p>
+ * Typically, a Color or ColorModel would be associated with an ICC
+ * Profile which is either an input, display, or output profile (see
+ * the ICC specification).  There are other types of ICC Profiles, e.g.
+ * abstract profiles, device link profiles, and named color profiles,
+ * which do not contain information appropriate for representing the color
+ * space of a color, image, or device (see ICC_Profile).
+ * Attempting to create an ICC_ColorSpace object from an inappropriate ICC
+ * Profile is an error.
+ * <p>
+ * ICC Profiles represent transformations from the color space of
+ * the profile (e.g. a monitor) to a Profile Connection Space (PCS).
+ * Profiles of interest for tagging images or colors have a
+ * PCS which is one of the device independent
+ * spaces (one CIEXYZ space and two CIELab spaces) defined in the
+ * ICC Profile Format Specification.  Most profiles of interest
+ * either have invertible transformations or explicitly specify
+ * transformations going both directions.  Should an ICC_ColorSpace
+ * object be used in a way requiring a conversion from PCS to
+ * the profile's native space and there is inadequate data to
+ * correctly perform the conversion, the ICC_ColorSpace object will
+ * produce output in the specified type of color space (e.g. TYPE_RGB,
+ * TYPE_CMYK, etc.), but the specific color values of the output data
+ * will be undefined.
+ * <p>
+ * The details of this class are not important for simple applets,
+ * which draw in a default color space or manipulate and display
+ * imported images with a known color space.  At most, such applets
+ * would need to get one of the default color spaces via
+ * ColorSpace.getInstance().
+ * <p>
+ * @see ColorSpace
+ * @see ICC_Profile
+ */
+
+
+
+public class ICC_ColorSpace extends ColorSpace {
+
+    static final long serialVersionUID = 3455889114070431483L;
+
+    private ICC_Profile    thisProfile;
+    private float[] minVal;
+    private float[] maxVal;
+    private float[] diffMinMax;
+    private float[] invDiffMinMax;
+    private boolean needScaleInit = true;
+
+    // {to,from}{RGB,CIEXYZ} methods create and cache these when needed
+    private transient ColorTransform this2srgb;
+    private transient ColorTransform srgb2this;
+    private transient ColorTransform this2xyz;
+    private transient ColorTransform xyz2this;
+
+
+    /**
+    * Constructs a new ICC_ColorSpace from an ICC_Profile object.
+    * @param profile the specified ICC_Profile object
+    * @exception IllegalArgumentException if profile is inappropriate for
+    *            representing a ColorSpace.
+    */
+    public ICC_ColorSpace (ICC_Profile profile) {
+        super (profile.getColorSpaceType(), profile.getNumComponents());
+
+        int profileClass = profile.getProfileClass();
+
+        /* REMIND - is NAMEDCOLOR OK? */
+        if ((profileClass != ICC_Profile.CLASS_INPUT) &&
+            (profileClass != ICC_Profile.CLASS_DISPLAY) &&
+            (profileClass != ICC_Profile.CLASS_OUTPUT) &&
+            (profileClass != ICC_Profile.CLASS_COLORSPACECONVERSION) &&
+            (profileClass != ICC_Profile.CLASS_NAMEDCOLOR) &&
+            (profileClass != ICC_Profile.CLASS_ABSTRACT)) {
+            throw new IllegalArgumentException("Invalid profile type");
+        }
+
+        thisProfile = profile;
+        setMinMax();
+    }
+
+    /**
+    * Returns the ICC_Profile for this ICC_ColorSpace.
+    * @return the ICC_Profile for this ICC_ColorSpace.
+    */
+    public ICC_Profile getProfile() {
+        return thisProfile;
+    }
+
+    /**
+     * Transforms a color value assumed to be in this ColorSpace
+     * into a value in the default CS_sRGB color space.
+     * <p>
+     * This method transforms color values using algorithms designed
+     * to produce the best perceptual match between input and output
+     * colors.  In order to do colorimetric conversion of color values,
+     * you should use the <code>toCIEXYZ</code>
+     * method of this color space to first convert from the input
+     * color space to the CS_CIEXYZ color space, and then use the
+     * <code>fromCIEXYZ</code> method of the CS_sRGB color space to
+     * convert from CS_CIEXYZ to the output color space.
+     * See {@link #toCIEXYZ(float[]) toCIEXYZ} and
+     * {@link #fromCIEXYZ(float[]) fromCIEXYZ} for further information.
+     * <p>
+     * @param colorvalue a float array with length of at least the number
+     *      of components in this ColorSpace.
+     * @return a float array of length 3.
+     * @throws ArrayIndexOutOfBoundsException if array length is not
+     * at least the number of components in this ColorSpace.
+     */
+    public float[]    toRGB (float[] colorvalue) {
+
+        if (this2srgb == null) {
+            ColorTransform[] transformList = new ColorTransform [2];
+            ICC_ColorSpace srgbCS =
+                (ICC_ColorSpace) ColorSpace.getInstance (CS_sRGB);
+            PCMM mdl = CMSManager.getModule();
+            transformList[0] = mdl.createTransform(
+                thisProfile, ColorTransform.Any, ColorTransform.In);
+            transformList[1] = mdl.createTransform(
+                srgbCS.getProfile(), ColorTransform.Any, ColorTransform.Out);
+            this2srgb = mdl.createTransform(transformList);
+            if (needScaleInit) {
+                setComponentScaling();
+            }
+        }
+
+        int nc = this.getNumComponents();
+        short tmp[] = new short[nc];
+        for (int i = 0; i < nc; i++) {
+            tmp[i] = (short)
+                ((colorvalue[i] - minVal[i]) * invDiffMinMax[i] + 0.5f);
+        }
+        tmp = this2srgb.colorConvert(tmp, null);
+        float[] result = new float [3];
+        for (int i = 0; i < 3; i++) {
+            result[i] = ((float) (tmp[i] & 0xffff)) / 65535.0f;
+        }
+        return result;
+    }
+
+    /**
+     * Transforms a color value assumed to be in the default CS_sRGB
+     * color space into this ColorSpace.
+     * <p>
+     * This method transforms color values using algorithms designed
+     * to produce the best perceptual match between input and output
+     * colors.  In order to do colorimetric conversion of color values,
+     * you should use the <code>toCIEXYZ</code>
+     * method of the CS_sRGB color space to first convert from the input
+     * color space to the CS_CIEXYZ color space, and then use the
+     * <code>fromCIEXYZ</code> method of this color space to
+     * convert from CS_CIEXYZ to the output color space.
+     * See {@link #toCIEXYZ(float[]) toCIEXYZ} and
+     * {@link #fromCIEXYZ(float[]) fromCIEXYZ} for further information.
+     * <p>
+     * @param rgbvalue a float array with length of at least 3.
+     * @return a float array with length equal to the number of
+     *       components in this ColorSpace.
+     * @throws ArrayIndexOutOfBoundsException if array length is not
+     * at least 3.
+     */
+    public float[]    fromRGB(float[] rgbvalue) {
+
+        if (srgb2this == null) {
+            ColorTransform[] transformList = new ColorTransform [2];
+            ICC_ColorSpace srgbCS =
+                (ICC_ColorSpace) ColorSpace.getInstance (CS_sRGB);
+            PCMM mdl = CMSManager.getModule();
+            transformList[0] = mdl.createTransform(
+                srgbCS.getProfile(), ColorTransform.Any, ColorTransform.In);
+            transformList[1] = mdl.createTransform(
+                thisProfile, ColorTransform.Any, ColorTransform.Out);
+            srgb2this = mdl.createTransform(transformList);
+            if (needScaleInit) {
+                setComponentScaling();
+            }
+        }
+
+        short tmp[] = new short[3];
+        for (int i = 0; i < 3; i++) {
+            tmp[i] = (short) ((rgbvalue[i] * 65535.0f) + 0.5f);
+        }
+        tmp = srgb2this.colorConvert(tmp, null);
+        int nc = this.getNumComponents();
+        float[] result = new float [nc];
+        for (int i = 0; i < nc; i++) {
+            result[i] = (((float) (tmp[i] & 0xffff)) / 65535.0f) *
+                        diffMinMax[i] + minVal[i];
+        }
+        return result;
+    }
+
+
+    /**
+     * Transforms a color value assumed to be in this ColorSpace
+     * into the CS_CIEXYZ conversion color space.
+     * <p>
+     * This method transforms color values using relative colorimetry,
+     * as defined by the ICC Specification.  This
+     * means that the XYZ values returned by this method are represented
+     * relative to the D50 white point of the CS_CIEXYZ color space.
+     * This representation is useful in a two-step color conversion
+     * process in which colors are transformed from an input color
+     * space to CS_CIEXYZ and then to an output color space.  This
+     * representation is not the same as the XYZ values that would
+     * be measured from the given color value by a colorimeter.
+     * A further transformation is necessary to compute the XYZ values
+     * that would be measured using current CIE recommended practices.
+     * The paragraphs below explain this in more detail.
+     * <p>
+     * The ICC standard uses a device independent color space (DICS) as the
+     * mechanism for converting color from one device to another device.  In
+     * this architecture, colors are converted from the source device's color
+     * space to the ICC DICS and then from the ICC DICS to the destination
+     * device's color space.  The ICC standard defines device profiles which
+     * contain transforms which will convert between a device's color space
+     * and the ICC DICS.  The overall conversion of colors from a source
+     * device to colors of a destination device is done by connecting the
+     * device-to-DICS transform of the profile for the source device to the
+     * DICS-to-device transform of the profile for the destination device.
+     * For this reason, the ICC DICS is commonly referred to as the profile
+     * connection space (PCS).  The color space used in the methods
+     * toCIEXYZ and fromCIEXYZ is the CIEXYZ PCS defined by the ICC
+     * Specification.  This is also the color space represented by
+     * ColorSpace.CS_CIEXYZ.
+     * <p>
+     * The XYZ values of a color are often represented as relative to some
+     * white point, so the actual meaning of the XYZ values cannot be known
+     * without knowing the white point of those values.  This is known as
+     * relative colorimetry.  The PCS uses a white point of D50, so the XYZ
+     * values of the PCS are relative to D50.  For example, white in the PCS
+     * will have the XYZ values of D50, which is defined to be X=.9642,
+     * Y=1.000, and Z=0.8249.  This white point is commonly used for graphic
+     * arts applications, but others are often used in other applications.
+     * <p>
+     * To quantify the color characteristics of a device such as a printer
+     * or monitor, measurements of XYZ values for particular device colors
+     * are typically made.  For purposes of this discussion, the term
+     * device XYZ values is used to mean the XYZ values that would be
+     * measured from device colors using current CIE recommended practices.
+     * <p>
+     * Converting between device XYZ values and the PCS XYZ values returned
+     * by this method corresponds to converting between the device's color
+     * space, as represented by CIE colorimetric values, and the PCS.  There
+     * are many factors involved in this process, some of which are quite
+     * subtle.  The most important, however, is the adjustment made to account
+     * for differences between the device's white point and the white point of
+     * the PCS.  There are many techniques for doing this and it is the
+     * subject of much current research and controversy.  Some commonly used
+     * methods are XYZ scaling, the von Kries transform, and the Bradford
+     * transform.  The proper method to use depends upon each particular
+     * application.
+     * <p>
+     * The simplest method is XYZ scaling.  In this method each device XYZ
+     * value is  converted to a PCS XYZ value by multiplying it by the ratio
+     * of the PCS white point (D50) to the device white point.
+     * <pre>
+     *
+     * Xd, Yd, Zd are the device XYZ values
+     * Xdw, Ydw, Zdw are the device XYZ white point values
+     * Xp, Yp, Zp are the PCS XYZ values
+     * Xd50, Yd50, Zd50 are the PCS XYZ white point values
+     *
+     * Xp = Xd * (Xd50 / Xdw)
+     * Yp = Yd * (Yd50 / Ydw)
+     * Zp = Zd * (Zd50 / Zdw)
+     *
+     * </pre>
+     * <p>
+     * Conversion from the PCS to the device would be done by inverting these
+     * equations:
+     * <pre>
+     *
+     * Xd = Xp * (Xdw / Xd50)
+     * Yd = Yp * (Ydw / Yd50)
+     * Zd = Zp * (Zdw / Zd50)
+     *
+     * </pre>
+     * <p>
+     * Note that the media white point tag in an ICC profile is not the same
+     * as the device white point.  The media white point tag is expressed in
+     * PCS values and is used to represent the difference between the XYZ of
+     * device illuminant and the XYZ of the device media when measured under
+     * that illuminant.  The device white point is expressed as the device
+     * XYZ values corresponding to white displayed on the device.  For
+     * example, displaying the RGB color (1.0, 1.0, 1.0) on an sRGB device
+     * will result in a measured device XYZ value of D65.  This will not
+     * be the same as the media white point tag XYZ value in the ICC
+     * profile for an sRGB device.
+     * <p>
+     * @param colorvalue a float array with length of at least the number
+     *        of components in this ColorSpace.
+     * @return a float array of length 3.
+     * @throws ArrayIndexOutOfBoundsException if array length is not
+     * at least the number of components in this ColorSpace.
+     */
+    public float[]    toCIEXYZ(float[] colorvalue) {
+
+        if (this2xyz == null) {
+            ColorTransform[] transformList = new ColorTransform [2];
+            ICC_ColorSpace xyzCS =
+                (ICC_ColorSpace) ColorSpace.getInstance (CS_CIEXYZ);
+            PCMM mdl = CMSManager.getModule();
+            try {
+                transformList[0] = mdl.createTransform(
+                    thisProfile, ICC_Profile.icRelativeColorimetric,
+                    ColorTransform.In);
+            } catch (CMMException e) {
+                transformList[0] = mdl.createTransform(
+                    thisProfile, ColorTransform.Any, ColorTransform.In);
+            }
+            transformList[1] = mdl.createTransform(
+                xyzCS.getProfile(), ColorTransform.Any, ColorTransform.Out);
+            this2xyz = mdl.createTransform (transformList);
+            if (needScaleInit) {
+                setComponentScaling();
+            }
+        }
+
+        int nc = this.getNumComponents();
+        short tmp[] = new short[nc];
+        for (int i = 0; i < nc; i++) {
+            tmp[i] = (short)
+                ((colorvalue[i] - minVal[i]) * invDiffMinMax[i] + 0.5f);
+        }
+        tmp = this2xyz.colorConvert(tmp, null);
+        float ALMOST_TWO = 1.0f + (32767.0f / 32768.0f);
+        // For CIEXYZ, min = 0.0, max = ALMOST_TWO for all components
+        float[] result = new float [3];
+        for (int i = 0; i < 3; i++) {
+            result[i] = (((float) (tmp[i] & 0xffff)) / 65535.0f) * ALMOST_TWO;
+        }
+        return result;
+    }
+
+
+    /**
+     * Transforms a color value assumed to be in the CS_CIEXYZ conversion
+     * color space into this ColorSpace.
+     * <p>
+     * This method transforms color values using relative colorimetry,
+     * as defined by the ICC Specification.  This
+     * means that the XYZ argument values taken by this method are represented
+     * relative to the D50 white point of the CS_CIEXYZ color space.
+     * This representation is useful in a two-step color conversion
+     * process in which colors are transformed from an input color
+     * space to CS_CIEXYZ and then to an output color space.  The color
+     * values returned by this method are not those that would produce
+     * the XYZ value passed to the method when measured by a colorimeter.
+     * If you have XYZ values corresponding to measurements made using
+     * current CIE recommended practices, they must be converted to D50
+     * relative values before being passed to this method.
+     * The paragraphs below explain this in more detail.
+     * <p>
+     * The ICC standard uses a device independent color space (DICS) as the
+     * mechanism for converting color from one device to another device.  In
+     * this architecture, colors are converted from the source device's color
+     * space to the ICC DICS and then from the ICC DICS to the destination
+     * device's color space.  The ICC standard defines device profiles which
+     * contain transforms which will convert between a device's color space
+     * and the ICC DICS.  The overall conversion of colors from a source
+     * device to colors of a destination device is done by connecting the
+     * device-to-DICS transform of the profile for the source device to the
+     * DICS-to-device transform of the profile for the destination device.
+     * For this reason, the ICC DICS is commonly referred to as the profile
+     * connection space (PCS).  The color space used in the methods
+     * toCIEXYZ and fromCIEXYZ is the CIEXYZ PCS defined by the ICC
+     * Specification.  This is also the color space represented by
+     * ColorSpace.CS_CIEXYZ.
+     * <p>
+     * The XYZ values of a color are often represented as relative to some
+     * white point, so the actual meaning of the XYZ values cannot be known
+     * without knowing the white point of those values.  This is known as
+     * relative colorimetry.  The PCS uses a white point of D50, so the XYZ
+     * values of the PCS are relative to D50.  For example, white in the PCS
+     * will have the XYZ values of D50, which is defined to be X=.9642,
+     * Y=1.000, and Z=0.8249.  This white point is commonly used for graphic
+     * arts applications, but others are often used in other applications.
+     * <p>
+     * To quantify the color characteristics of a device such as a printer
+     * or monitor, measurements of XYZ values for particular device colors
+     * are typically made.  For purposes of this discussion, the term
+     * device XYZ values is used to mean the XYZ values that would be
+     * measured from device colors using current CIE recommended practices.
+     * <p>
+     * Converting between device XYZ values and the PCS XYZ values taken as
+     * arguments by this method corresponds to converting between the device's
+     * color space, as represented by CIE colorimetric values, and the PCS.
+     * There are many factors involved in this process, some of which are quite
+     * subtle.  The most important, however, is the adjustment made to account
+     * for differences between the device's white point and the white point of
+     * the PCS.  There are many techniques for doing this and it is the
+     * subject of much current research and controversy.  Some commonly used
+     * methods are XYZ scaling, the von Kries transform, and the Bradford
+     * transform.  The proper method to use depends upon each particular
+     * application.
+     * <p>
+     * The simplest method is XYZ scaling.  In this method each device XYZ
+     * value is  converted to a PCS XYZ value by multiplying it by the ratio
+     * of the PCS white point (D50) to the device white point.
+     * <pre>
+     *
+     * Xd, Yd, Zd are the device XYZ values
+     * Xdw, Ydw, Zdw are the device XYZ white point values
+     * Xp, Yp, Zp are the PCS XYZ values
+     * Xd50, Yd50, Zd50 are the PCS XYZ white point values
+     *
+     * Xp = Xd * (Xd50 / Xdw)
+     * Yp = Yd * (Yd50 / Ydw)
+     * Zp = Zd * (Zd50 / Zdw)
+     *
+     * </pre>
+     * <p>
+     * Conversion from the PCS to the device would be done by inverting these
+     * equations:
+     * <pre>
+     *
+     * Xd = Xp * (Xdw / Xd50)
+     * Yd = Yp * (Ydw / Yd50)
+     * Zd = Zp * (Zdw / Zd50)
+     *
+     * </pre>
+     * <p>
+     * Note that the media white point tag in an ICC profile is not the same
+     * as the device white point.  The media white point tag is expressed in
+     * PCS values and is used to represent the difference between the XYZ of
+     * device illuminant and the XYZ of the device media when measured under
+     * that illuminant.  The device white point is expressed as the device
+     * XYZ values corresponding to white displayed on the device.  For
+     * example, displaying the RGB color (1.0, 1.0, 1.0) on an sRGB device
+     * will result in a measured device XYZ value of D65.  This will not
+     * be the same as the media white point tag XYZ value in the ICC
+     * profile for an sRGB device.
+     * <p>
+     * <p>
+     * @param colorvalue a float array with length of at least 3.
+     * @return a float array with length equal to the number of
+     *         components in this ColorSpace.
+     * @throws ArrayIndexOutOfBoundsException if array length is not
+     * at least 3.
+     */
+    public float[]    fromCIEXYZ(float[] colorvalue) {
+
+        if (xyz2this == null) {
+            ColorTransform[] transformList = new ColorTransform [2];
+            ICC_ColorSpace xyzCS =
+                (ICC_ColorSpace) ColorSpace.getInstance (CS_CIEXYZ);
+            PCMM mdl = CMSManager.getModule();
+            transformList[0] = mdl.createTransform (
+                xyzCS.getProfile(), ColorTransform.Any, ColorTransform.In);
+            try {
+                transformList[1] = mdl.createTransform(
+                    thisProfile, ICC_Profile.icRelativeColorimetric,
+                    ColorTransform.Out);
+            } catch (CMMException e) {
+                transformList[1] = CMSManager.getModule().createTransform(
+                thisProfile, ColorTransform.Any, ColorTransform.Out);
+            }
+            xyz2this = mdl.createTransform(transformList);
+            if (needScaleInit) {
+                setComponentScaling();
+            }
+        }
+
+        short tmp[] = new short[3];
+        float ALMOST_TWO = 1.0f + (32767.0f / 32768.0f);
+        float factor = 65535.0f / ALMOST_TWO;
+        // For CIEXYZ, min = 0.0, max = ALMOST_TWO for all components
+        for (int i = 0; i < 3; i++) {
+            tmp[i] = (short) ((colorvalue[i] * factor) + 0.5f);
+        }
+        tmp = xyz2this.colorConvert(tmp, null);
+        int nc = this.getNumComponents();
+        float[] result = new float [nc];
+        for (int i = 0; i < nc; i++) {
+            result[i] = (((float) (tmp[i] & 0xffff)) / 65535.0f) *
+                        diffMinMax[i] + minVal[i];
+        }
+        return result;
+    }
+
+    /**
+     * Returns the minimum normalized color component value for the
+     * specified component.  For TYPE_XYZ spaces, this method returns
+     * minimum values of 0.0 for all components.  For TYPE_Lab spaces,
+     * this method returns 0.0 for L and -128.0 for a and b components.
+     * This is consistent with the encoding of the XYZ and Lab Profile
+     * Connection Spaces in the ICC specification.  For all other types, this
+     * method returns 0.0 for all components.  When using an ICC_ColorSpace
+     * with a profile that requires different minimum component values,
+     * it is necessary to subclass this class and override this method.
+     * @param component The component index.
+     * @return The minimum normalized component value.
+     * @throws IllegalArgumentException if component is less than 0 or
+     *         greater than numComponents - 1.
+     * @since 1.4
+     */
+    public float getMinValue(int component) {
+        if ((component < 0) || (component > this.getNumComponents() - 1)) {
+            throw new IllegalArgumentException(
+                "Component index out of range: + component");
+        }
+        return minVal[component];
+    }
+
+    /**
+     * Returns the maximum normalized color component value for the
+     * specified component.  For TYPE_XYZ spaces, this method returns
+     * maximum values of 1.0 + (32767.0 / 32768.0) for all components.
+     * For TYPE_Lab spaces,
+     * this method returns 100.0 for L and 127.0 for a and b components.
+     * This is consistent with the encoding of the XYZ and Lab Profile
+     * Connection Spaces in the ICC specification.  For all other types, this
+     * method returns 1.0 for all components.  When using an ICC_ColorSpace
+     * with a profile that requires different maximum component values,
+     * it is necessary to subclass this class and override this method.
+     * @param component The component index.
+     * @return The maximum normalized component value.
+     * @throws IllegalArgumentException if component is less than 0 or
+     *         greater than numComponents - 1.
+     * @since 1.4
+     */
+    public float getMaxValue(int component) {
+        if ((component < 0) || (component > this.getNumComponents() - 1)) {
+            throw new IllegalArgumentException(
+                "Component index out of range: + component");
+        }
+        return maxVal[component];
+    }
+
+    private void setMinMax() {
+        int nc = this.getNumComponents();
+        int type = this.getType();
+        minVal = new float[nc];
+        maxVal = new float[nc];
+        if (type == ColorSpace.TYPE_Lab) {
+            minVal[0] = 0.0f;    // L
+            maxVal[0] = 100.0f;
+            minVal[1] = -128.0f; // a
+            maxVal[1] = 127.0f;
+            minVal[2] = -128.0f; // b
+            maxVal[2] = 127.0f;
+        } else if (type == ColorSpace.TYPE_XYZ) {
+            minVal[0] = minVal[1] = minVal[2] = 0.0f; // X, Y, Z
+            maxVal[0] = maxVal[1] = maxVal[2] = 1.0f + (32767.0f/ 32768.0f);
+        } else {
+            for (int i = 0; i < nc; i++) {
+                minVal[i] = 0.0f;
+                maxVal[i] = 1.0f;
+            }
+        }
+    }
+
+    private void setComponentScaling() {
+        int nc = this.getNumComponents();
+        diffMinMax = new float[nc];
+        invDiffMinMax = new float[nc];
+        for (int i = 0; i < nc; i++) {
+            minVal[i] = this.getMinValue(i); // in case getMinVal is overridden
+            maxVal[i] = this.getMaxValue(i); // in case getMaxVal is overridden
+            diffMinMax[i] = maxVal[i] - minVal[i];
+            invDiffMinMax[i] = 65535.0f / diffMinMax[i];
+        }
+        needScaleInit = false;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/awt/color/ICC_Profile.java	Thu Apr 10 16:28:45 2008 -0700
@@ -0,0 +1,2003 @@
+/*
+ * Portions Copyright 1997-2006 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/**********************************************************************
+ **********************************************************************
+ **********************************************************************
+ *** COPYRIGHT (c) Eastman Kodak Company, 1997                      ***
+ *** As  an unpublished  work pursuant to Title 17 of the United    ***
+ *** States Code.  All rights reserved.                             ***
+ **********************************************************************
+ **********************************************************************
+ **********************************************************************/
+
+package java.awt.color;
+
+import sun.java2d.cmm.PCMM;
+import sun.java2d.cmm.CMSManager;
+import sun.java2d.cmm.ProfileDeferralMgr;
+import sun.java2d.cmm.ProfileDeferralInfo;
+import sun.java2d.cmm.ProfileActivator;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamException;
+import java.io.OutputStream;
+import java.io.Serializable;
+
+import java.util.StringTokenizer;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * A representation of color profile data for device independent and
+ * device dependent color spaces based on the International Color
+ * Consortium Specification ICC.1:2001-12, File Format for Color Profiles,
+ * (see <A href="http://www.color.org"> http://www.color.org</A>).
+ * <p>
+ * An ICC_ColorSpace object can be constructed from an appropriate
+ * ICC_Profile.
+ * Typically, an ICC_ColorSpace would be associated with an ICC
+ * Profile which is either an input, display, or output profile (see
+ * the ICC specification).  There are also device link, abstract,
+ * color space conversion, and named color profiles.  These are less
+ * useful for tagging a color or image, but are useful for other
+ * purposes (in particular device link profiles can provide improved
+ * performance for converting from one device's color space to
+ * another's).
+ * <p>
+ * ICC Profiles represent transformations from the color space of
+ * the profile (e.g. a monitor) to a Profile Connection Space (PCS).
+ * Profiles of interest for tagging images or colors have a PCS
+ * which is one of the two specific device independent
+ * spaces (one CIEXYZ space and one CIELab space) defined in the
+ * ICC Profile Format Specification.  Most profiles of interest
+ * either have invertible transformations or explicitly specify
+ * transformations going both directions.
+ * <p>
+ * @see ICC_ColorSpace
+ */
+
+
+public class ICC_Profile implements Serializable {
+
+    private static final long serialVersionUID = -3938515861990936766L;
+
+    transient long ID;
+
+    private transient ProfileDeferralInfo deferralInfo;
+    private transient ProfileActivator profileActivator;
+
+    // Registry of singleton profile objects for specific color spaces
+    // defined in the ColorSpace class (e.g. CS_sRGB), see
+    // getInstance(int cspace) factory method.
+    private static ICC_Profile sRGBprofile;
+    private static ICC_Profile XYZprofile;
+    private static ICC_Profile PYCCprofile;
+    private static ICC_Profile GRAYprofile;
+    private static ICC_Profile LINEAR_RGBprofile;
+
+
+    /**
+     * Profile class is input.
+     */
+    public static final int CLASS_INPUT = 0;
+
+    /**
+     * Profile class is display.
+     */
+    public static final int CLASS_DISPLAY = 1;
+
+    /**
+     * Profile class is output.
+     */
+    public static final int CLASS_OUTPUT = 2;
+
+    /**
+     * Profile class is device link.
+     */
+    public static final int CLASS_DEVICELINK = 3;
+
+    /**
+     * Profile class is color space conversion.
+     */
+    public static final int CLASS_COLORSPACECONVERSION = 4;
+
+    /**
+     * Profile class is abstract.
+     */
+    public static final int CLASS_ABSTRACT = 5;
+
+    /**
+     * Profile class is named color.
+     */
+    public static final int CLASS_NAMEDCOLOR = 6;
+
+
+    /**
+     * ICC Profile Color Space Type Signature: 'XYZ '.
+     */
+    public static final int icSigXYZData        = 0x58595A20;    /* 'XYZ ' */
+
+    /**
+     * ICC Profile Color Space Type Signature: 'Lab '.
+     */
+    public static final int icSigLabData        = 0x4C616220;    /* 'Lab ' */
+
+    /**
+     * ICC Profile Color Space Type Signature: 'Luv '.
+     */
+    public static final int icSigLuvData        = 0x4C757620;    /* 'Luv ' */
+
+    /**
+     * ICC Profile Color Space Type Signature: 'YCbr'.
+     */
+    public static final int icSigYCbCrData        = 0x59436272;    /* 'YCbr' */
+
+    /**
+     * ICC Profile Color Space Type Signature: 'Yxy '.
+     */
+    public static final int icSigYxyData        = 0x59787920;    /* 'Yxy ' */
+
+    /**
+     * ICC Profile Color Space Type Signature: 'RGB '.
+     */
+    public static final int icSigRgbData        = 0x52474220;    /* 'RGB ' */
+
+    /**
+     * ICC Profile Color Space Type Signature: 'GRAY'.
+     */
+    public static final int icSigGrayData        = 0x47524159;    /* 'GRAY' */
+
+    /**
+     * ICC Profile Color Space Type Signature: 'HSV'.
+     */
+    public static final int icSigHsvData        = 0x48535620;    /* 'HSV ' */
+
+    /**
+     * ICC Profile Color Space Type Signature: 'HLS'.
+     */
+    public static final int icSigHlsData        = 0x484C5320;    /* 'HLS ' */
+
+    /**
+     * ICC Profile Color Space Type Signature: 'CMYK'.
+     */
+    public static final int icSigCmykData        = 0x434D594B;    /* 'CMYK' */
+
+    /**
+     * ICC Profile Color Space Type Signature: 'CMY '.
+     */
+    public static final int icSigCmyData        = 0x434D5920;    /* 'CMY ' */
+
+    /**
+     * ICC Profile Color Space Type Signature: '2CLR'.
+     */
+    public static final int icSigSpace2CLR        = 0x32434C52;    /* '2CLR' */
+
+    /**
+     * ICC Profile Color Space Type Signature: '3CLR'.
+     */
+    public static final int icSigSpace3CLR        = 0x33434C52;    /* '3CLR' */
+
+    /**
+     * ICC Profile Color Space Type Signature: '4CLR'.
+     */
+    public static final int icSigSpace4CLR        = 0x34434C52;    /* '4CLR' */
+
+    /**
+     * ICC Profile Color Space Type Signature: '5CLR'.
+     */
+    public static final int icSigSpace5CLR        = 0x35434C52;    /* '5CLR' */
+
+    /**
+     * ICC Profile Color Space Type Signature: '6CLR'.
+     */
+    public static final int icSigSpace6CLR        = 0x36434C52;    /* '6CLR' */
+
+    /**
+     * ICC Profile Color Space Type Signature: '7CLR'.
+     */
+    public static final int icSigSpace7CLR        = 0x37434C52;    /* '7CLR' */
+
+    /**
+     * ICC Profile Color Space Type Signature: '8CLR'.
+     */
+    public static final int icSigSpace8CLR        = 0x38434C52;    /* '8CLR' */
+
+    /**
+     * ICC Profile Color Space Type Signature: '9CLR'.
+     */
+    public static final int icSigSpace9CLR        = 0x39434C52;    /* '9CLR' */
+
+    /**
+     * ICC Profile Color Space Type Signature: 'ACLR'.
+     */
+    public static final int icSigSpaceACLR        = 0x41434C52;    /* 'ACLR' */
+
+    /**
+     * ICC Profile Color Space Type Signature: 'BCLR'.
+     */
+    public static final int icSigSpaceBCLR        = 0x42434C52;    /* 'BCLR' */
+
+    /**
+     * ICC Profile Color Space Type Signature: 'CCLR'.
+     */
+    public static final int icSigSpaceCCLR        = 0x43434C52;    /* 'CCLR' */
+
+    /**
+     * ICC Profile Color Space Type Signature: 'DCLR'.
+     */
+    public static final int icSigSpaceDCLR        = 0x44434C52;    /* 'DCLR' */
+
+    /**
+     * ICC Profile Color Space Type Signature: 'ECLR'.
+     */
+    public static final int icSigSpaceECLR        = 0x45434C52;    /* 'ECLR' */
+
+    /**
+     * ICC Profile Color Space Type Signature: 'FCLR'.
+     */
+    public static final int icSigSpaceFCLR        = 0x46434C52;    /* 'FCLR' */
+
+
+    /**
+     * ICC Profile Class Signature: 'scnr'.
+     */
+    public static final int icSigInputClass       = 0x73636E72;    /* 'scnr' */
+
+    /**
+     * ICC Profile Class Signature: 'mntr'.
+     */
+    public static final int icSigDisplayClass     = 0x6D6E7472;    /* 'mntr' */
+
+    /**
+     * ICC Profile Class Signature: 'prtr'.
+     */
+    public static final int icSigOutputClass      = 0x70727472;    /* 'prtr' */
+
+    /**
+     * ICC Profile Class Signature: 'link'.
+     */
+    public static final int icSigLinkClass        = 0x6C696E6B;    /* 'link' */
+
+    /**
+     * ICC Profile Class Signature: 'abst'.
+     */
+    public static final int icSigAbstractClass    = 0x61627374;    /* 'abst' */
+
+    /**
+     * ICC Profile Class Signature: 'spac'.
+     */
+    public static final int icSigColorSpaceClass  = 0x73706163;    /* 'spac' */
+
+    /**
+     * ICC Profile Class Signature: 'nmcl'.
+     */
+    public static final int icSigNamedColorClass  = 0x6e6d636c;    /* 'nmcl' */
+
+
+    /**
+     * ICC Profile Rendering Intent: Perceptual.
+     */
+    public static final int icPerceptual            = 0;
+
+    /**
+     * ICC Profile Rendering Intent: RelativeColorimetric.
+     */
+    public static final int icRelativeColorimetric    = 1;
+
+    /**
+     * ICC Profile Rendering Intent: Media-RelativeColorimetric.
+     * @since 1.5
+     */
+    public static final int icMediaRelativeColorimetric = 1;
+
+    /**
+     * ICC Profile Rendering Intent: Saturation.
+     */
+    public static final int icSaturation            = 2;
+
+    /**
+     * ICC Profile Rendering Intent: AbsoluteColorimetric.
+     */
+    public static final int icAbsoluteColorimetric    = 3;
+
+    /**
+     * ICC Profile Rendering Intent: ICC-AbsoluteColorimetric.
+     * @since 1.5
+     */
+    public static final int icICCAbsoluteColorimetric = 3;
+
+
+    /**
+     * ICC Profile Tag Signature: 'head' - special.
+     */
+    public static final int icSigHead      = 0x68656164; /* 'head' - special */
+
+    /**
+     * ICC Profile Tag Signature: 'A2B0'.
+     */
+    public static final int icSigAToB0Tag         = 0x41324230;    /* 'A2B0' */
+
+    /**
+     * ICC Profile Tag Signature: 'A2B1'.
+     */
+    public static final int icSigAToB1Tag         = 0x41324231;    /* 'A2B1' */
+
+    /**
+     * ICC Profile Tag Signature: 'A2B2'.
+     */
+    public static final int icSigAToB2Tag         = 0x41324232;    /* 'A2B2' */
+
+    /**
+     * ICC Profile Tag Signature: 'bXYZ'.
+     */
+    public static final int icSigBlueColorantTag  = 0x6258595A;    /* 'bXYZ' */
+
+    /**
+     * ICC Profile Tag Signature: 'bXYZ'.
+     * @since 1.5
+     */
+    public static final int icSigBlueMatrixColumnTag = 0x6258595A; /* 'bXYZ' */
+
+    /**
+     * ICC Profile Tag Signature: 'bTRC'.
+     */
+    public static final int icSigBlueTRCTag       = 0x62545243;    /* 'bTRC' */
+
+    /**
+     * ICC Profile Tag Signature: 'B2A0'.
+     */
+    public static final int icSigBToA0Tag         = 0x42324130;    /* 'B2A0' */
+
+    /**
+     * ICC Profile Tag Signature: 'B2A1'.
+     */
+    public static final int icSigBToA1Tag         = 0x42324131;    /* 'B2A1' */
+
+    /**
+     * ICC Profile Tag Signature: 'B2A2'.
+     */
+    public static final int icSigBToA2Tag         = 0x42324132;    /* 'B2A2' */
+
+    /**
+     * ICC Profile Tag Signature: 'calt'.
+     */
+    public static final int icSigCalibrationDateTimeTag = 0x63616C74;
+                                                                   /* 'calt' */
+
+    /**
+     * ICC Profile Tag Signature: 'targ'.
+     */
+    public static final int icSigCharTargetTag    = 0x74617267;    /* 'targ' */
+
+    /**
+     * ICC Profile Tag Signature: 'cprt'.
+     */
+    public static final int icSigCopyrightTag     = 0x63707274;    /* 'cprt' */
+
+    /**
+     * ICC Profile Tag Signature: 'crdi'.
+     */
+    public static final int icSigCrdInfoTag       = 0x63726469;    /* 'crdi' */
+
+    /**
+     * ICC Profile Tag Signature: 'dmnd'.
+     */
+    public static final int icSigDeviceMfgDescTag = 0x646D6E64;    /* 'dmnd' */
+
+    /**
+     * ICC Profile Tag Signature: 'dmdd'.
+     */
+    public static final int icSigDeviceModelDescTag = 0x646D6464;  /* 'dmdd' */
+
+    /**
+     * ICC Profile Tag Signature: 'devs'.
+     */
+    public static final int icSigDeviceSettingsTag =  0x64657673;  /* 'devs' */
+
+    /**
+     * ICC Profile Tag Signature: 'gamt'.
+     */
+    public static final int icSigGamutTag         = 0x67616D74;    /* 'gamt' */
+
+    /**
+     * ICC Profile Tag Signature: 'kTRC'.
+     */
+    public static final int icSigGrayTRCTag       = 0x6b545243;    /* 'kTRC' */
+
+    /**
+     * ICC Profile Tag Signature: 'gXYZ'.
+     */
+    public static final int icSigGreenColorantTag = 0x6758595A;    /* 'gXYZ' */
+
+    /**
+     * ICC Profile Tag Signature: 'gXYZ'.
+     * @since 1.5
+     */
+    public static final int icSigGreenMatrixColumnTag = 0x6758595A;/* 'gXYZ' */
+
+    /**
+     * ICC Profile Tag Signature: 'gTRC'.
+     */
+    public static final int icSigGreenTRCTag      = 0x67545243;    /* 'gTRC' */
+
+    /**
+     * ICC Profile Tag Signature: 'lumi'.
+     */
+    public static final int icSigLuminanceTag     = 0x6C756d69;    /* 'lumi' */
+
+    /**
+     * ICC Profile Tag Signature: 'meas'.
+     */
+    public static final int icSigMeasurementTag   = 0x6D656173;    /* 'meas' */
+
+    /**
+     * ICC Profile Tag Signature: 'bkpt'.
+     */
+    public static final int icSigMediaBlackPointTag = 0x626B7074;  /* 'bkpt' */
+
+    /**
+     * ICC Profile Tag Signature: 'wtpt'.
+     */
+    public static final int icSigMediaWhitePointTag = 0x77747074;  /* 'wtpt' */
+
+    /**
+     * ICC Profile Tag Signature: 'ncl2'.
+     */
+    public static final int icSigNamedColor2Tag   = 0x6E636C32;    /* 'ncl2' */
+
+    /**
+     * ICC Profile Tag Signature: 'resp'.
+     */
+    public static final int icSigOutputResponseTag = 0x72657370;   /* 'resp' */
+
+    /**
+     * ICC Profile Tag Signature: 'pre0'.
+     */
+    public static final int icSigPreview0Tag      = 0x70726530;    /* 'pre0' */
+
+    /**
+     * ICC Profile Tag Signature: 'pre1'.
+     */
+    public static final int icSigPreview1Tag      = 0x70726531;    /* 'pre1' */
+
+    /**
+     * ICC Profile Tag Signature: 'pre2'.
+     */
+    public static final int icSigPreview2Tag      = 0x70726532;    /* 'pre2' */
+
+    /**
+     * ICC Profile Tag Signature: 'desc'.
+     */
+    public static final int icSigProfileDescriptionTag = 0x64657363;
+                                                                   /* 'desc' */
+
+    /**
+     * ICC Profile Tag Signature: 'pseq'.
+     */
+    public static final int icSigProfileSequenceDescTag = 0x70736571;
+                                                                   /* 'pseq' */
+
+    /**
+     * ICC Profile Tag Signature: 'psd0'.
+     */
+    public static final int icSigPs2CRD0Tag       = 0x70736430;    /* 'psd0' */
+
+    /**
+     * ICC Profile Tag Signature: 'psd1'.
+     */
+    public static final int icSigPs2CRD1Tag       = 0x70736431;    /* 'psd1' */
+
+    /**
+     * ICC Profile Tag Signature: 'psd2'.
+     */
+    public static final int icSigPs2CRD2Tag       = 0x70736432;    /* 'psd2' */
+
+    /**
+     * ICC Profile Tag Signature: 'psd3'.
+     */
+    public static final int icSigPs2CRD3Tag       = 0x70736433;    /* 'psd3' */
+
+    /**
+     * ICC Profile Tag Signature: 'ps2s'.
+     */
+    public static final int icSigPs2CSATag        = 0x70733273;    /* 'ps2s' */
+
+    /**
+     * ICC Profile Tag Signature: 'ps2i'.
+     */
+    public static final int icSigPs2RenderingIntentTag = 0x70733269;
+                                                                   /* 'ps2i' */
+
+    /**
+     * ICC Profile Tag Signature: 'rXYZ'.
+     */
+    public static final int icSigRedColorantTag   = 0x7258595A;    /* 'rXYZ' */
+
+    /**
+     * ICC Profile Tag Signature: 'rXYZ'.
+     * @since 1.5
+     */
+    public static final int icSigRedMatrixColumnTag = 0x7258595A;  /* 'rXYZ' */
+
+    /**
+     * ICC Profile Tag Signature: 'rTRC'.
+     */
+    public static final int icSigRedTRCTag        = 0x72545243;    /* 'rTRC' */
+
+    /**
+     * ICC Profile Tag Signature: 'scrd'.
+     */
+    public static final int icSigScreeningDescTag = 0x73637264;    /* 'scrd' */
+
+    /**
+     * ICC Profile Tag Signature: 'scrn'.
+     */
+    public static final int icSigScreeningTag     = 0x7363726E;    /* 'scrn' */
+
+    /**
+     * ICC Profile Tag Signature: 'tech'.
+     */
+    public static final int icSigTechnologyTag    = 0x74656368;    /* 'tech' */
+
+    /**
+     * ICC Profile Tag Signature: 'bfd '.
+     */
+    public static final int icSigUcrBgTag         = 0x62666420;    /* 'bfd ' */
+
+    /**
+     * ICC Profile Tag Signature: 'vued'.
+     */
+    public static final int icSigViewingCondDescTag = 0x76756564;  /* 'vued' */
+
+    /**
+     * ICC Profile Tag Signature: 'view'.
+     */
+    public static final int icSigViewingConditionsTag = 0x76696577;/* 'view' */
+
+    /**
+     * ICC Profile Tag Signature: 'chrm'.
+     */
+    public static final int icSigChromaticityTag  = 0x6368726d;    /* 'chrm' */
+
+    /**
+     * ICC Profile Tag Signature: 'chad'.
+     * @since 1.5
+     */
+    public static final int icSigChromaticAdaptationTag = 0x63686164;/* 'chad' */
+
+    /**
+     * ICC Profile Tag Signature: 'clro'.
+     * @since 1.5
+     */
+    public static final int icSigColorantOrderTag = 0x636C726F;    /* 'clro' */
+
+    /**
+     * ICC Profile Tag Signature: 'clrt'.
+     * @since 1.5
+     */
+    public static final int icSigColorantTableTag = 0x636C7274;    /* 'clrt' */
+
+
+    /**
+     * ICC Profile Header Location: profile size in bytes.
+     */
+    public static final int icHdrSize         = 0;  /* Profile size in bytes */
+
+    /**
+     * ICC Profile Header Location: CMM for this profile.
+     */
+    public static final int icHdrCmmId        = 4;  /* CMM for this profile */
+
+    /**
+     * ICC Profile Header Location: format version number.
+     */
+    public static final int icHdrVersion      = 8;  /* Format version number */
+
+    /**
+     * ICC Profile Header Location: type of profile.
+     */
+    public static final int icHdrDeviceClass  = 12; /* Type of profile */
+
+    /**
+     * ICC Profile Header Location: color space of data.
+     */
+    public static final int icHdrColorSpace   = 16; /* Color space of data */
+
+    /**
+     * ICC Profile Header Location: PCS - XYZ or Lab only.
+     */
+    public static final int icHdrPcs          = 20; /* PCS - XYZ or Lab only */
+
+    /**
+     * ICC Profile Header Location: date profile was created.
+     */
+    public static final int icHdrDate       = 24; /* Date profile was created */
+
+    /**
+     * ICC Profile Header Location: icMagicNumber.
+     */
+    public static final int icHdrMagic        = 36; /* icMagicNumber */
+
+    /**
+     * ICC Profile Header Location: primary platform.
+     */
+    public static final int icHdrPlatform     = 40; /* Primary Platform */
+
+    /**
+     * ICC Profile Header Location: various bit settings.
+     */
+    public static final int icHdrFlags        = 44; /* Various bit settings */
+
+    /**
+     * ICC Profile Header Location: device manufacturer.
+     */
+    public static final int icHdrManufacturer = 48; /* Device manufacturer */
+
+    /**
+     * ICC Profile Header Location: device model number.
+     */
+    public static final int icHdrModel        = 52; /* Device model number */
+
+    /**
+     * ICC Profile Header Location: device attributes.
+     */
+    public static final int icHdrAttributes   = 56; /* Device attributes */
+
+    /**
+     * ICC Profile Header Location: rendering intent.
+     */
+    public static final int icHdrRenderingIntent = 64; /* Rendering intent */
+
+    /**
+     * ICC Profile Header Location: profile illuminant.
+     */
+    public static final int icHdrIlluminant   = 68; /* Profile illuminant */
+
+    /**
+     * ICC Profile Header Location: profile creator.
+     */
+    public static final int icHdrCreator      = 80; /* Profile creator */
+
+    /**
+     * ICC Profile Header Location: profile's ID.
+     * @since 1.5
+     */
+    public static final int icHdrProfileID = 84; /* Profile's ID */
+
+
+    /**
+     * ICC Profile Constant: tag type signaturE.
+     */
+    public static final int icTagType          = 0;    /* tag type signature */
+
+    /**
+     * ICC Profile Constant: reserved.
+     */
+    public static final int icTagReserved      = 4;    /* reserved */
+
+    /**
+     * ICC Profile Constant: curveType count.
+     */
+    public static final int icCurveCount       = 8;    /* curveType count */
+
+    /**
+     * ICC Profile Constant: curveType data.
+     */
+    public static final int icCurveData        = 12;   /* curveType data */
+
+    /**
+     * ICC Profile Constant: XYZNumber X.
+     */
+    public static final int icXYZNumberX       = 8;    /* XYZNumber X */
+
+
+    /**
+     * Constructs an ICC_Profile object with a given ID.
+     */
+    ICC_Profile(long ID) {
+        this.ID = ID;
+    }
+
+
+    /**
+     * Constructs an ICC_Profile object whose loading will be deferred.
+     * The ID will be 0 until the profile is loaded.
+     */
+    ICC_Profile(ProfileDeferralInfo pdi) {
+        this.deferralInfo = pdi;
+        this.profileActivator = new ProfileActivator() {
+            public void activate() {
+                activateDeferredProfile();
+            }
+        };
+        ProfileDeferralMgr.registerDeferral(this.profileActivator);
+    }
+
+
+    /**
+     * Frees the resources associated with an ICC_Profile object.
+     */
+    protected void finalize () {
+        if (ID != 0) {
+            CMSManager.getModule().freeProfile(ID);
+        } else if (profileActivator != null) {
+            ProfileDeferralMgr.unregisterDeferral(profileActivator);
+        }
+    }
+
+
+    /**
+     * Constructs an ICC_Profile object corresponding to the data in
+     * a byte array.  Throws an IllegalArgumentException if the data
+     * does not correspond to a valid ICC Profile.
+     * @param data the specified ICC Profile data
+     * @return an <code>ICC_Profile</code> object corresponding to
+     *          the data in the specified <code>data</code> array.
+     */
+    public static ICC_Profile getInstance(byte[] data) {
+    ICC_Profile thisProfile;
+
+        long theID;
+
+        if (ProfileDeferralMgr.deferring) {
+            ProfileDeferralMgr.activateProfiles();
+        }
+
+        try {
+            theID = CMSManager.getModule().loadProfile(data);
+        } catch (CMMException c) {
+            throw new IllegalArgumentException("Invalid ICC Profile Data");
+        }
+
+        try {
+            if ((getColorSpaceType (theID) == ColorSpace.TYPE_GRAY) &&
+                (getData (theID, icSigMediaWhitePointTag) != null) &&
+                (getData (theID, icSigGrayTRCTag) != null)) {
+                thisProfile = new ICC_ProfileGray (theID);
+            }
+            else if ((getColorSpaceType (theID) == ColorSpace.TYPE_RGB) &&
+                (getData (theID, icSigMediaWhitePointTag) != null) &&
+                (getData (theID, icSigRedColorantTag) != null) &&
+                (getData (theID, icSigGreenColorantTag) != null) &&
+                (getData (theID, icSigBlueColorantTag) != null) &&
+                (getData (theID, icSigRedTRCTag) != null) &&
+                (getData (theID, icSigGreenTRCTag) != null) &&
+                (getData (theID, icSigBlueTRCTag) != null)) {
+                thisProfile = new ICC_ProfileRGB (theID);
+            }
+            else {
+                thisProfile = new ICC_Profile (theID);
+            }
+        } catch (CMMException c) {
+            thisProfile = new ICC_Profile (theID);
+        }
+        return thisProfile;
+    }
+
+
+
+    /**
+     * Constructs an ICC_Profile corresponding to one of the specific color
+     * spaces defined by the ColorSpace class (for example CS_sRGB).
+     * Throws an IllegalArgumentException if cspace is not one of the
+     * defined color spaces.
+     *
+     * @param cspace the type of color space to create a profile for.
+     * The specified type is one of the color
+     * space constants defined in the  <CODE>ColorSpace</CODE> class.
+     *
+     * @return an <code>ICC_Profile</code> object corresponding to
+     *          the specified <code>ColorSpace</code> type.
+     * @exception IllegalArgumentException If <CODE>cspace</CODE> is not
+     * one of the predefined color space types.
+     */
+    public static ICC_Profile getInstance (int cspace) {
+        ICC_Profile thisProfile = null;
+        String fileName;
+
+        switch (cspace) {
+        case ColorSpace.CS_sRGB:
+            synchronized(ICC_Profile.class) {
+                if (sRGBprofile == null) {
+                    try {
+                        /*
+                         * Deferral is only used for standard profiles.
+                         * Enabling the appropriate access privileges is handled
+                         * at a lower level.
+                         */
+                        sRGBprofile = getDeferredInstance(
+                            new ProfileDeferralInfo("sRGB.pf",
+                                                    ColorSpace.TYPE_RGB,
+                                                    3, CLASS_DISPLAY));
+                    } catch (IOException e) {
+                        throw new IllegalArgumentException(
+                              "Can't load standard profile: sRGB.pf");
+                    }
+                }
+                thisProfile = sRGBprofile;
+            }
+
+            break;
+
+        case ColorSpace.CS_CIEXYZ:
+            synchronized(ICC_Profile.class) {
+                if (XYZprofile == null) {
+                    XYZprofile = getStandardProfile("CIEXYZ.pf");
+                }
+                thisProfile = XYZprofile;
+            }
+
+            break;
+
+        case ColorSpace.CS_PYCC:
+            synchronized(ICC_Profile.class) {
+                if (PYCCprofile == null) {
+                    PYCCprofile = getStandardProfile("PYCC.pf");
+                }
+                thisProfile = PYCCprofile;
+            }
+
+            break;
+
+        case ColorSpace.CS_GRAY:
+            synchronized(ICC_Profile.class) {
+                if (GRAYprofile == null) {
+                    GRAYprofile = getStandardProfile("GRAY.pf");
+                }
+                thisProfile = GRAYprofile;
+            }
+
+            break;
+
+        case ColorSpace.CS_LINEAR_RGB:
+            synchronized(ICC_Profile.class) {
+                if (LINEAR_RGBprofile == null) {
+                    LINEAR_RGBprofile = getStandardProfile("LINEAR_RGB.pf");
+                }
+                thisProfile = LINEAR_RGBprofile;
+            }
+
+            break;
+
+        default:
+            throw new IllegalArgumentException("Unknown color space");
+        }
+
+        return thisProfile;
+    }
+
+    /* This asserts system privileges, so is used only for the
+     * standard profiles.
+     */
+    private static ICC_Profile getStandardProfile(final String name) {
+
+        return (ICC_Profile) AccessController.doPrivileged(
+            new PrivilegedAction() {
+                 public Object run() {
+                     ICC_Profile p = null;
+                     try {
+                         p = getInstance (name);
+                     } catch (IOException ex) {
+                         throw new IllegalArgumentException(
+                               "Can't load standard profile: " + name);
+                     }
+                     return p;
+                 }
+             });
+    }
+
+    /**
+     * Constructs an ICC_Profile corresponding to the data in a file.
+     * fileName may be an absolute or a relative file specification.
+     * Relative file names are looked for in several places: first, relative
+     * to any directories specified by the java.iccprofile.path property;
+     * second, relative to any directories specified by the java.class.path
+     * property; finally, in a directory used to store profiles always
+     * available, such as the profile for sRGB.  Built-in profiles use .pf as
+     * the file name extension for profiles, e.g. sRGB.pf.
+     * This method throws an IOException if the specified file cannot be
+     * opened or if an I/O error occurs while reading the file.  It throws
+     * an IllegalArgumentException if the file does not contain valid ICC
+     * Profile data.
+     * @param fileName The file that contains the data for the profile.
+     *
+     * @return an <code>ICC_Profile</code> object corresponding to
+     *          the data in the specified file.
+     * @exception IOException If the specified file cannot be opened or
+     * an I/O error occurs while reading the file.
+     *
+     * @exception IllegalArgumentException If the file does not
+     * contain valid ICC Profile data.
+     *
+     * @exception SecurityException If a security manager is installed
+     * and it does not permit read access to the given file.
+     */
+    public static ICC_Profile getInstance(String fileName) throws IOException {
+    ICC_Profile thisProfile;
+    FileInputStream fis;
+
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkRead(fileName);
+        }
+
+        if ((fis = openProfile(fileName)) == null) {
+            throw new IOException("Cannot open file " + fileName);
+        }
+
+        thisProfile = getInstance(fis);
+
+        fis.close();    /* close the file */
+
+        return thisProfile;
+    }
+
+
+    /**
+     * Constructs an ICC_Profile corresponding to the data in an InputStream.
+     * This method throws an IllegalArgumentException if the stream does not
+     * contain valid ICC Profile data.  It throws an IOException if an I/O
+     * error occurs while reading the stream.
+     * @param s The input stream from which to read the profile data.
+     *
+     * @return an <CODE>ICC_Profile</CODE> object corresponding to the
+     *     data in the specified <code>InputStream</code>.
+     *
+     * @exception IOException If an I/O error occurs while reading the stream.
+     *
+     * @exception IllegalArgumentException If the stream does not
+     * contain valid ICC Profile data.
+     */
+    public static ICC_Profile getInstance(InputStream s) throws IOException {
+    byte profileData[];
+
+        if (s instanceof ProfileDeferralInfo) {
+            /* hack to detect profiles whose loading can be deferred */
+            return getDeferredInstance((ProfileDeferralInfo) s);
+        }
+
+        if ((profileData = getProfileDataFromStream(s)) == null) {
+            throw new IllegalArgumentException("Invalid ICC Profile Data");
+        }
+
+        return getInstance(profileData);
+    }
+
+
+    static byte[] getProfileDataFromStream(InputStream s) throws IOException {
+    byte profileData[];
+    int profileSize;
+
+        byte header[] = new byte[128];
+        int bytestoread = 128;
+        int bytesread = 0;
+        int n;
+
+        while (bytestoread != 0) {
+            if ((n = s.read(header, bytesread, bytestoread)) < 0) {
+                return null;
+            }
+            bytesread += n;
+            bytestoread -= n;
+        }
+        if (header[36] != 0x61 || header[37] != 0x63 ||
+            header[38] != 0x73 || header[39] != 0x70) {
+            return null;   /* not a valid profile */
+        }
+        profileSize = ((header[0] & 0xff) << 24) |
+                      ((header[1] & 0xff) << 16) |
+                      ((header[2] & 0xff) <<  8) |
+                       (header[3] & 0xff);
+        profileData = new byte[profileSize];
+        System.arraycopy(header, 0, profileData, 0, 128);
+        bytestoread = profileSize - 128;
+        bytesread = 128;
+        while (bytestoread != 0) {
+            if ((n = s.read(profileData, bytesread, bytestoread)) < 0) {
+                return null;
+            }
+            bytesread += n;
+            bytestoread -= n;
+        }
+
+        return profileData;
+    }
+
+
+    /**
+     * Constructs an ICC_Profile for which the actual loading of the
+     * profile data from a file and the initialization of the CMM should
+     * be deferred as long as possible.
+     * Deferral is only used for standard profiles.
+     * If deferring is disabled, then getStandardProfile() ensures
+     * that all of the appropriate access privileges are granted
+     * when loading this profile.
+     * If deferring is enabled, then the deferred activation
+     * code will take care of access privileges.
+     * @see activateDeferredProfile()
+     */
+    static ICC_Profile getDeferredInstance(ProfileDeferralInfo pdi)
+        throws IOException {
+
+        if (!ProfileDeferralMgr.deferring) {
+            return getStandardProfile(pdi.filename);
+        }
+        if (pdi.colorSpaceType == ColorSpace.TYPE_RGB) {
+            return new ICC_ProfileRGB(pdi);
+        } else if (pdi.colorSpaceType == ColorSpace.TYPE_GRAY) {
+            return new ICC_ProfileGray(pdi);
+        } else {
+            return new ICC_Profile(pdi);
+        }
+    }
+
+
+    void activateDeferredProfile() {
+    byte profileData[];
+    FileInputStream fis;
+    String fileName = deferralInfo.filename;
+
+        profileActivator = null;
+        deferralInfo = null;
+        if ((fis = openProfile(fileName)) == null) {
+            throw new IllegalArgumentException("Cannot open file " + fileName);
+        }
+        try {
+            profileData = getProfileDataFromStream(fis);
+            fis.close();    /* close the file */
+        }
+        catch (IOException e) {
+            throw new IllegalArgumentException("Invalid ICC Profile Data" +
+                fileName);
+        }
+        if (profileData == null) {
+            throw new IllegalArgumentException("Invalid ICC Profile Data" +
+                fileName);
+        }
+        try {
+            ID = CMSManager.getModule().loadProfile(profileData);
+        } catch (CMMException c) {
+            throw new IllegalArgumentException("Invalid ICC Profile Data" +
+                fileName);
+        }
+    }
+
+
+    /**
+     * Returns profile major version.
+     * @return  The major version of the profile.
+     */
+    public int getMajorVersion() {
+    byte[] theHeader;
+
+        theHeader = getData(icSigHead); /* getData will activate deferred
+                                           profiles if necessary */
+
+        return (int) theHeader[8];
+    }
+
+    /**
+     * Returns profile minor version.
+     * @return The minor version of the profile.
+     */
+    public int getMinorVersion() {
+    byte[] theHeader;
+
+        theHeader = getData(icSigHead); /* getData will activate deferred
+                                           profiles if necessary */
+
+        return (int) theHeader[9];
+    }
+
+    /**
+     * Returns the profile class.
+     * @return One of the predefined profile class constants.
+     */
+    public int getProfileClass() {
+    byte[] theHeader;
+    int theClassSig, theClass;
+
+        if (deferralInfo != null) {
+            return deferralInfo.profileClass; /* Need to have this info for
+                                                 ICC_ColorSpace without
+                                                 causing a deferred profile
+                                                 to be loaded */
+        }
+
+        theHeader = getData(icSigHead);
+
+        theClassSig = intFromBigEndian (theHeader, icHdrDeviceClass);
+
+        switch (theClassSig) {
+        case icSigInputClass:
+            theClass = CLASS_INPUT;
+            break;
+
+        case icSigDisplayClass:
+            theClass = CLASS_DISPLAY;
+            break;
+
+        case icSigOutputClass:
+            theClass = CLASS_OUTPUT;
+            break;
+
+        case icSigLinkClass:
+            theClass = CLASS_DEVICELINK;
+            break;
+
+        case icSigColorSpaceClass:
+            theClass = CLASS_COLORSPACECONVERSION;
+            break;
+
+        case icSigAbstractClass:
+            theClass = CLASS_ABSTRACT;
+            break;
+
+        case icSigNamedColorClass:
+            theClass = CLASS_NAMEDCOLOR;
+            break;
+
+        default:
+            throw new IllegalArgumentException("Unknown profile class");
+        }
+
+        return theClass;
+    }
+
+    /**
+     * Returns the color space type.  Returns one of the color space type
+     * constants defined by the ColorSpace class.  This is the
+     * "input" color space of the profile.  The type defines the
+     * number of components of the color space and the interpretation,
+     * e.g. TYPE_RGB identifies a color space with three components - red,
+     * green, and blue.  It does not define the particular color
+     * characteristics of the space, e.g. the chromaticities of the
+     * primaries.
+     * @return One of the color space type constants defined in the
+     * <CODE>ColorSpace</CODE> class.
+     */
+    public int getColorSpaceType() {
+        if (deferralInfo != null) {
+            return deferralInfo.colorSpaceType; /* Need to have this info for
+                                                   ICC_ColorSpace without
+                                                   causing a deferred profile
+                                                   to be loaded */
+        }
+        return    getColorSpaceType(ID);
+    }
+
+    static int getColorSpaceType(long profileID) {
+    byte[] theHeader;
+    int theColorSpaceSig, theColorSpace;
+
+        theHeader = getData(profileID, icSigHead);
+        theColorSpaceSig = intFromBigEndian(theHeader, icHdrColorSpace);
+        theColorSpace = iccCStoJCS (theColorSpaceSig);
+        return theColorSpace;
+    }
+
+    /**
+     * Returns the color space type of the Profile Connection Space (PCS).
+     * Returns one of the color space type constants defined by the
+     * ColorSpace class.  This is the "output" color space of the
+     * profile.  For an input, display, or output profile useful
+     * for tagging colors or images, this will be either TYPE_XYZ or
+     * TYPE_Lab and should be interpreted as the corresponding specific
+     * color space defined in the ICC specification.  For a device
+     * link profile, this could be any of the color space type constants.
+     * @return One of the color space type constants defined in the
+     * <CODE>ColorSpace</CODE> class.
+     */
+    public int getPCSType() {
+        if (ProfileDeferralMgr.deferring) {
+            ProfileDeferralMgr.activateProfiles();
+        }
+        return getPCSType(ID);
+    }
+
+
+    static int getPCSType(long profileID) {
+    byte[] theHeader;
+    int thePCSSig, thePCS;
+
+        theHeader = getData(profileID, icSigHead);
+        thePCSSig = intFromBigEndian(theHeader, icHdrPcs);
+        thePCS = iccCStoJCS(thePCSSig);
+        return thePCS;
+    }
+
+
+    /**
+     * Write this ICC_Profile to a file.
+     *
+     * @param fileName The file to write the profile data to.
+     *
+     * @exception IOException If the file cannot be opened for writing
+     * or an I/O error occurs while writing to the file.
+     */
+    public void write(String fileName) throws IOException {
+    FileOutputStream outputFile;
+    byte profileData[];
+
+        profileData = getData(); /* this will activate deferred
+                                    profiles if necessary */
+        outputFile = new FileOutputStream(fileName);
+        outputFile.write(profileData);
+        outputFile.close ();
+    }
+
+
+    /**
+     * Write this ICC_Profile to an OutputStream.
+     *
+     * @param s The stream to write the profile data to.
+     *
+     * @exception IOException If an I/O error occurs while writing to the
+     * stream.
+     */
+    public void write(OutputStream s) throws IOException {
+    byte profileData[];
+
+        profileData = getData(); /* this will activate deferred
+                                    profiles if necessary */
+        s.write(profileData);
+    }
+
+
+    /**
+     * Returns a byte array corresponding to the data of this ICC_Profile.
+     * @return A byte array that contains the profile data.
+     * @see #setData(int, byte[])
+     */
+    public byte[] getData() {
+    int profileSize;
+    byte[] profileData;
+
+        if (ProfileDeferralMgr.deferring) {
+            ProfileDeferralMgr.activateProfiles();
+        }
+
+        PCMM mdl = CMSManager.getModule();
+
+        /* get the number of bytes needed for this profile */
+        profileSize = mdl.getProfileSize(ID);
+
+        profileData = new byte [profileSize];
+
+        /* get the data for the profile */
+        mdl.getProfileData(ID, profileData);
+
+        return profileData;
+    }
+
+
+    /**
+     * Returns a particular tagged data element from the profile as
+     * a byte array.  Elements are identified by signatures
+     * as defined in the ICC specification.  The signature
+     * icSigHead can be used to get the header.  This method is useful
+     * for advanced applets or applications which need to access
+     * profile data directly.
+     *
+     * @param tagSignature The ICC tag signature for the data element you
+     * want to get.
+     *
+     * @return A byte array that contains the tagged data element. Returns
+     * <code>null</code> if the specified tag doesn't exist.
+     * @see #setData(int, byte[])
+     */
+    public byte[] getData(int tagSignature) {
+
+        if (ProfileDeferralMgr.deferring) {
+            ProfileDeferralMgr.activateProfiles();
+        }
+
+        return getData(ID, tagSignature);
+    }
+
+
+    static byte[] getData(long profileID, int tagSignature) {
+    int tagSize;
+    byte[] tagData;
+
+        try {
+            PCMM mdl = CMSManager.getModule();
+
+            /* get the number of bytes needed for this tag */
+            tagSize = mdl.getTagSize(profileID, tagSignature);
+
+            tagData = new byte[tagSize]; /* get an array for the tag */
+
+            /* get the tag's data */
+            mdl.getTagData(profileID, tagSignature, tagData);
+        } catch(CMMException c) {
+            tagData = null;
+        }
+
+        return tagData;
+    }
+
+    /**
+     * Sets a particular tagged data element in the profile from
+     * a byte array.  This method is useful
+     * for advanced applets or applications which need to access
+     * profile data directly.
+     *
+     * @param tagSignature The ICC tag signature for the data element
+     * you want to set.
+     * @param tagData the data to set for the specified tag signature
+     * @see #getData
+     */
+    public void setData(int tagSignature, byte[] tagData) {
+
+        if (ProfileDeferralMgr.deferring) {
+            ProfileDeferralMgr.activateProfiles();
+        }
+
+        CMSManager.getModule().setTagData(ID, tagSignature, tagData);
+    }
+
+    /**
+     * Sets the rendering intent of the profile.
+     * This is used to select the proper transform from a profile that
+     * has multiple transforms.
+     */
+    void setRenderingIntent(int renderingIntent) {
+        byte[] theHeader = getData(icSigHead);/* getData will activate deferred
+                                                 profiles if necessary */
+        intToBigEndian (renderingIntent, theHeader, icHdrRenderingIntent);
+                                                 /* set the rendering intent */
+        setData (icSigHead, theHeader);
+    }
+
+
+    /**
+     * Returns the rendering intent of the profile.
+     * This is used to select the proper transform from a profile that
+     * has multiple transforms.  It is typically set in a source profile
+     * to select a transform from an output profile.
+     */
+    int getRenderingIntent() {
+        byte[] theHeader = getData(icSigHead);/* getData will activate deferred
+                                                 profiles if necessary */
+
+        int renderingIntent = intFromBigEndian(theHeader, icHdrRenderingIntent);
+                                                 /* set the rendering intent */
+        return renderingIntent;
+    }
+
+
+    /**
+     * Returns the number of color components in the "input" color
+     * space of this profile.  For example if the color space type
+     * of this profile is TYPE_RGB, then this method will return 3.
+     *
+     * @return The number of color components in the profile's input
+     * color space.
+     *
+     * @throws ProfileDataException if color space is in the profile
+     *         is invalid
+     */
+    public int getNumComponents() {
+    byte[]    theHeader;
+    int    theColorSpaceSig, theNumComponents;
+
+        if (deferralInfo != null) {
+            return deferralInfo.numComponents; /* Need to have this info for
+                                                  ICC_ColorSpace without
+                                                  causing a deferred profile
+                                                  to be loaded */
+        }
+        theHeader = getData(icSigHead);
+
+        theColorSpaceSig = intFromBigEndian (theHeader, icHdrColorSpace);
+
+        switch (theColorSpaceSig) {
+        case icSigGrayData:
+            theNumComponents = 1;
+            break;
+
+        case icSigSpace2CLR:
+            theNumComponents = 2;
+            break;
+
+        case icSigXYZData:
+        case icSigLabData:
+        case icSigLuvData:
+        case icSigYCbCrData:
+        case icSigYxyData:
+        case icSigRgbData:
+        case icSigHsvData:
+        case icSigHlsData:
+        case icSigCmyData:
+        case icSigSpace3CLR:
+            theNumComponents = 3;
+            break;
+
+        case icSigCmykData:
+        case icSigSpace4CLR:
+            theNumComponents = 4;
+            break;
+
+        case icSigSpace5CLR:
+            theNumComponents = 5;
+            break;
+
+        case icSigSpace6CLR:
+            theNumComponents = 6;
+            break;
+
+        case icSigSpace7CLR:
+            theNumComponents = 7;
+            break;
+
+        case icSigSpace8CLR:
+            theNumComponents = 8;
+            break;
+
+        case icSigSpace9CLR:
+            theNumComponents = 9;
+            break;
+
+        case icSigSpaceACLR:
+            theNumComponents = 10;
+            break;
+
+        case icSigSpaceBCLR:
+            theNumComponents = 11;
+            break;
+
+        case icSigSpaceCCLR:
+            theNumComponents = 12;
+            break;
+
+        case icSigSpaceDCLR:
+            theNumComponents = 13;
+            break;
+
+        case icSigSpaceECLR:
+            theNumComponents = 14;
+            break;
+
+        case icSigSpaceFCLR:
+            theNumComponents = 15;
+            break;
+
+        default:
+            throw new ProfileDataException ("invalid ICC color space");
+        }
+
+        return theNumComponents;
+    }
+
+
+    /**
+     * Returns a float array of length 3 containing the X, Y, and Z
+     * components of the mediaWhitePointTag in the ICC profile.
+     */
+    float[] getMediaWhitePoint() {
+        return getXYZTag(icSigMediaWhitePointTag);
+                                           /* get the media white point tag */
+    }
+
+
+    /**
+     * Returns a float array of length 3 containing the X, Y, and Z
+     * components encoded in an XYZType tag.
+     */
+    float[] getXYZTag(int theTagSignature) {
+    byte[] theData;
+    float[] theXYZNumber;
+    int i1, i2, theS15Fixed16;
+
+        theData = getData(theTagSignature); /* get the tag data */
+                                            /* getData will activate deferred
+                                               profiles if necessary */
+
+        theXYZNumber = new float [3];        /* array to return */
+
+        /* convert s15Fixed16Number to float */
+        for (i1 = 0, i2 = icXYZNumberX; i1 < 3; i1++, i2 += 4) {
+            theS15Fixed16 = intFromBigEndian(theData, i2);
+            theXYZNumber [i1] = ((float) theS15Fixed16) / 65536.0f;
+        }
+        return theXYZNumber;
+    }
+
+
+    /**
+     * Returns a gamma value representing a tone reproduction
+     * curve (TRC).  If the profile represents the TRC as a table rather
+     * than a single gamma value, then an exception is thrown.  In this
+     * case the actual table can be obtained via getTRC().
+     * theTagSignature should be one of icSigGrayTRCTag, icSigRedTRCTag,
+     * icSigGreenTRCTag, or icSigBlueTRCTag.
+     * @return the gamma value as a float.
+     * @exception ProfileDataException if the profile does not specify
+     *            the TRC as a single gamma value.
+     */
+    float getGamma(int theTagSignature) {
+    byte[] theTRCData;
+    float theGamma;
+    int theU8Fixed8;
+
+        theTRCData = getData(theTagSignature); /* get the TRC */
+                                               /* getData will activate deferred
+                                                  profiles if necessary */
+
+        if (intFromBigEndian (theTRCData, icCurveCount) != 1) {
+            throw new ProfileDataException ("TRC is not a gamma");
+        }
+
+        /* convert u8Fixed8 to float */
+        theU8Fixed8 = (shortFromBigEndian(theTRCData, icCurveData)) & 0xffff;
+
+        theGamma = ((float) theU8Fixed8) / 256.0f;
+
+        return theGamma;
+    }
+
+
+    /**
+     * Returns the TRC as an array of shorts.  If the profile has
+     * specified the TRC as linear (gamma = 1.0) or as a simple gamma
+     * value, this method throws an exception, and the getGamma() method
+     * should be used to get the gamma value.  Otherwise the short array
+     * returned here represents a lookup table where the input Gray value
+     * is conceptually in the range [0.0, 1.0].  Value 0.0 maps
+     * to array index 0 and value 1.0 maps to array index length-1.
+     * Interpolation may be used to generate output values for
+     * input values which do not map exactly to an index in the
+     * array.  Output values also map linearly to the range [0.0, 1.0].
+     * Value 0.0 is represented by an array value of 0x0000 and
+     * value 1.0 by 0xFFFF, i.e. the values are really unsigned
+     * short values, although they are returned in a short array.
+     * theTagSignature should be one of icSigGrayTRCTag, icSigRedTRCTag,
+     * icSigGreenTRCTag, or icSigBlueTRCTag.
+     * @return a short array representing the TRC.
+     * @exception ProfileDataException if the profile does not specify
+     *            the TRC as a table.
+     */
+    short[] getTRC(int theTagSignature) {
+    byte[] theTRCData;
+    short[] theTRC;
+    int i1, i2, nElements, theU8Fixed8;
+
+        theTRCData = getData(theTagSignature); /* get the TRC */
+                                               /* getData will activate deferred
+                                                  profiles if necessary */
+
+        nElements = intFromBigEndian(theTRCData, icCurveCount);
+
+        if (nElements == 1) {
+            throw new ProfileDataException("TRC is not a table");
+        }
+
+        /* make the short array */
+        theTRC = new short [nElements];
+
+        for (i1 = 0, i2 = icCurveData; i1 < nElements; i1++, i2 += 2) {
+            theTRC[i1] = shortFromBigEndian(theTRCData, i2);
+        }
+
+        return theTRC;
+    }
+
+
+    /* convert an ICC color space signature into a Java color space type */
+    static int iccCStoJCS(int theColorSpaceSig) {
+    int theColorSpace;
+
+        switch (theColorSpaceSig) {
+        case icSigXYZData:
+            theColorSpace = ColorSpace.TYPE_XYZ;
+            break;
+
+        case icSigLabData:
+            theColorSpace = ColorSpace.TYPE_Lab;
+            break;
+
+        case icSigLuvData:
+            theColorSpace = ColorSpace.TYPE_Luv;
+            break;
+
+        case icSigYCbCrData:
+            theColorSpace = ColorSpace.TYPE_YCbCr;
+            break;
+
+        case icSigYxyData:
+            theColorSpace = ColorSpace.TYPE_Yxy;
+            break;
+
+        case icSigRgbData:
+            theColorSpace = ColorSpace.TYPE_RGB;
+            break;
+
+        case icSigGrayData:
+            theColorSpace = ColorSpace.TYPE_GRAY;
+            break;
+
+        case icSigHsvData:
+            theColorSpace = ColorSpace.TYPE_HSV;
+            break;
+
+        case icSigHlsData:
+            theColorSpace = ColorSpace.TYPE_HLS;
+            break;
+
+        case icSigCmykData:
+            theColorSpace = ColorSpace.TYPE_CMYK;
+            break;
+
+        case icSigCmyData:
+            theColorSpace = ColorSpace.TYPE_CMY;
+            break;
+
+        case icSigSpace2CLR:
+            theColorSpace = ColorSpace.TYPE_2CLR;
+            break;
+
+        case icSigSpace3CLR:
+            theColorSpace = ColorSpace.TYPE_3CLR;
+            break;
+
+        case icSigSpace4CLR:
+            theColorSpace = ColorSpace.TYPE_4CLR;
+            break;
+
+        case icSigSpace5CLR:
+            theColorSpace = ColorSpace.TYPE_5CLR;
+            break;
+
+        case icSigSpace6CLR:
+            theColorSpace = ColorSpace.TYPE_6CLR;
+            break;
+
+        case icSigSpace7CLR:
+            theColorSpace = ColorSpace.TYPE_7CLR;
+            break;
+
+        case icSigSpace8CLR:
+            theColorSpace = ColorSpace.TYPE_8CLR;
+            break;
+
+        case icSigSpace9CLR:
+            theColorSpace = ColorSpace.TYPE_9CLR;
+            break;
+
+        case icSigSpaceACLR:
+            theColorSpace = ColorSpace.TYPE_ACLR;
+            break;
+
+        case icSigSpaceBCLR:
+            theColorSpace = ColorSpace.TYPE_BCLR;
+            break;
+
+        case icSigSpaceCCLR:
+            theColorSpace = ColorSpace.TYPE_CCLR;
+            break;
+
+        case icSigSpaceDCLR:
+            theColorSpace = ColorSpace.TYPE_DCLR;
+            break;
+
+        case icSigSpaceECLR:
+            theColorSpace = ColorSpace.TYPE_ECLR;
+            break;
+
+        case icSigSpaceFCLR:
+            theColorSpace = ColorSpace.TYPE_FCLR;
+            break;
+
+        default:
+            throw new IllegalArgumentException ("Unknown color space");
+        }
+
+        return theColorSpace;
+    }
+
+
+    static int intFromBigEndian(byte[] array, int index) {
+        return (((array[index]   & 0xff) << 24) |
+                ((array[index+1] & 0xff) << 16) |
+                ((array[index+2] & 0xff) <<  8) |
+                 (array[index+3] & 0xff));
+    }
+
+
+    static void intToBigEndian(int value, byte[] array, int index) {
+            array[index]   = (byte) (value >> 24);
+            array[index+1] = (byte) (value >> 16);
+            array[index+2] = (byte) (value >>  8);
+            array[index+3] = (byte) (value);
+    }
+
+
+    static short shortFromBigEndian(byte[] array, int index) {
+        return (short) (((array[index]   & 0xff) << 8) |
+                         (array[index+1] & 0xff));
+    }
+
+
+    static void shortToBigEndian(short value, byte[] array, int index) {
+            array[index]   = (byte) (value >> 8);
+            array[index+1] = (byte) (value);
+    }
+
+
+    /*
+     * fileName may be an absolute or a relative file specification.
+     * Relative file names are looked for in several places: first, relative
+     * to any directories specified by the java.iccprofile.path property;
+     * second, relative to any directories specified by the java.class.path
+     * property; finally, in a directory used to store profiles always
+     * available, such as a profile for sRGB.  Built-in profiles use .pf as
+     * the file name extension for profiles, e.g. sRGB.pf.
+     */
+    private static FileInputStream openProfile(final String fileName) {
+        return (FileInputStream)java.security.AccessController.doPrivileged(
+            new java.security.PrivilegedAction() {
+            public Object run() {
+                return privilegedOpenProfile(fileName);
+            }
+        });
+    }
+
+    /*
+     * this version is called from doPrivileged in privilegedOpenProfile.
+     * the whole method is privileged!
+     */
+    private static FileInputStream privilegedOpenProfile(String fileName) {
+        FileInputStream fis = null;
+        String path, dir, fullPath;
+
+        File f = new File(fileName); /* try absolute file name */
+
+        if ((!f.isFile()) &&
+                ((path = System.getProperty("java.iccprofile.path")) != null)){
+                                    /* try relative to java.iccprofile.path */
+                StringTokenizer st =
+                    new StringTokenizer(path, File.pathSeparator);
+                while (st.hasMoreTokens() && (!f.isFile())) {
+                    dir = st.nextToken();
+                        fullPath = dir + File.separatorChar + fileName;
+                    f = new File(fullPath);
+                }
+            }
+
+        if ((!f.isFile()) &&
+                ((path = System.getProperty("java.class.path")) != null)) {
+                                    /* try relative to java.class.path */
+                StringTokenizer st =
+                    new StringTokenizer(path, File.pathSeparator);
+                while (st.hasMoreTokens() && (!f.isFile())) {
+                    dir = st.nextToken();
+                        fullPath = dir + File.separatorChar + fileName;
+                    f = new File(fullPath);
+                }
+            }
+
+        if (!f.isFile()) { /* try the directory of built-in profiles */
+                dir = System.getProperty("java.home") +
+                    File.separatorChar + "lib" + File.separatorChar + "cmm";
+                fullPath = dir + File.separatorChar + fileName;
+                f = new File(fullPath);
+            }
+
+        if (f.isFile()) {
+            try {
+                fis = new FileInputStream(f);
+            } catch (FileNotFoundException e) {
+            }
+        }
+        return fis;
+    }
+
+
+    /*
+     * Serialization support.
+     *
+     * Directly deserialized profiles are useless since they are not
+     * registered with CMM.  We don't allow constructor to be called
+     * directly and instead have clients to call one of getInstance
+     * factory methods that will register the profile with CMM.  For
+     * deserialization we implement readResolve method that will
+     * resolve the bogus deserialized profile object with one obtained
+     * with getInstance as well.
+     *
+     * There're two primary factory methods for construction of ICC
+     * profiles: getInstance(int cspace) and getInstance(byte[] data).
+     * This implementation of ICC_Profile uses the former to return a
+     * cached singleton profile object, other implementations will
+     * likely use this technique too.  To preserve the singleton
+     * pattern across serialization we serialize cached singleton
+     * profiles in such a way that deserializing VM could call
+     * getInstance(int cspace) method that will resolve deserialized
+     * object into the corresponding singleton as well.
+     *
+     * Since the singletons are private to ICC_Profile the readResolve
+     * method have to be `protected' instead of `private' so that
+     * singletons that are instances of subclasses of ICC_Profile
+     * could be correctly deserialized.
+     */
+
+
+    /**
+     * Version of the format of additional serialized data in the
+     * stream.  Version&nbsp;<code>1</code> corresponds to Java&nbsp;2
+     * Platform,&nbsp;v1.3.
+     * @since 1.3
+     * @serial
+     */
+    private int iccProfileSerializedDataVersion = 1;
+
+
+    /**
+     * Writes default serializable fields to the stream.  Writes a
+     * string and an array of bytes to the stream as additional data.
+     *
+     * @param s stream used for serialization.
+     * @throws IOException
+     *     thrown by <code>ObjectInputStream</code>.
+     * @serialData
+     *     The <code>String</code> is the name of one of
+     *     <code>CS_<var>*</var></code> constants defined in the
+     *     {@link ColorSpace} class if the profile object is a profile
+     *     for a predefined color space (for example
+     *     <code>"CS_sRGB"</code>).  The string is <code>null</code>
+     *     otherwise.
+     *     <p>
+     *     The <code>byte[]</code> array is the profile data for the
+     *     profile.  For predefined color spaces <code>null</code> is
+     *     written instead of the profile data.  If in the future
+     *     versions of Java API new predefined color spaces will be
+     *     added, future versions of this class may choose to write
+     *     for new predefined color spaces not only the color space
+     *     name, but the profile data as well so that older versions
+     *     could still deserialize the object.
+     */
+    private void writeObject(ObjectOutputStream s)
+      throws IOException
+    {
+        s.defaultWriteObject();
+
+        String csName = null;
+        if (this == sRGBprofile) {
+            csName = "CS_sRGB";
+        } else if (this == XYZprofile) {
+            csName = "CS_CIEXYZ";
+        } else if (this == PYCCprofile) {
+            csName = "CS_PYCC";
+        } else if (this == GRAYprofile) {
+            csName = "CS_GRAY";
+        } else if (this == LINEAR_RGBprofile) {
+            csName = "CS_LINEAR_RGB";
+        }
+
+        // Future versions may choose to write profile data for new
+        // predefined color spaces as well, if any will be introduced,
+        // so that old versions that don't recognize the new CS name
+        // may fall back to constructing profile from the data.
+        byte[] data = null;
+        if (csName == null) {
+            // getData will activate deferred profile if necessary
+            data = getData();
+        }
+
+        s.writeObject(csName);
+        s.writeObject(data);
+    }
+
+    // Temporary storage used by readObject to store resolved profile
+    // (obtained with getInstance) for readResolve to return.
+    private transient ICC_Profile resolvedDeserializedProfile;
+
+    /**
+     * Reads default serializable fields from the stream.  Reads from
+     * the stream a string and an array of bytes as additional data.
+     *
+     * @param s stream used for deserialization.
+     * @throws IOException
+     *     thrown by <code>ObjectInputStream</code>.
+     * @throws ClassNotFoundException
+     *     thrown by <code>ObjectInputStream</code>.
+     * @serialData
+     *     The <code>String</code> is the name of one of
+     *     <code>CS_<var>*</var></code> constants defined in the
+     *     {@link ColorSpace} class if the profile object is a profile
+     *     for a predefined color space (for example
+     *     <code>"CS_sRGB"</code>).  The string is <code>null</code>
+     *     otherwise.
+     *     <p>
+     *     The <code>byte[]</code> array is the profile data for the
+     *     profile.  It will usually be <code>null</code> for the
+     *     predefined profiles.
+     *     <p>
+     *     If the string is recognized as a constant name for
+     *     predefined color space the object will be resolved into
+     *     profile obtained with
+     *     <code>getInstance(int&nbsp;cspace)</code> and the profile
+     *     data are ignored.  Otherwise the object will be resolved
+     *     into profile obtained with
+     *     <code>getInstance(byte[]&nbsp;data)</code>.
+     * @see #readResolve()
+     * @see #getInstance(int)
+     * @see #getInstance(byte[])
+     */
+    private void readObject(ObjectInputStream s)
+      throws IOException, ClassNotFoundException
+    {
+        s.defaultReadObject();
+
+        String csName = (String)s.readObject();
+        byte[] data = (byte[])s.readObject();
+
+        int cspace = 0;         // ColorSpace.CS_* constant if known
+        boolean isKnownPredefinedCS = false;
+        if (csName != null) {
+            isKnownPredefinedCS = true;
+            if (csName.equals("CS_sRGB")) {
+                cspace = ColorSpace.CS_sRGB;
+            } else if (csName.equals("CS_CIEXYZ")) {
+                cspace = ColorSpace.CS_CIEXYZ;
+            } else if (csName.equals("CS_PYCC")) {
+                cspace = ColorSpace.CS_PYCC;
+            } else if (csName.equals("CS_GRAY")) {
+                cspace = ColorSpace.CS_GRAY;
+            } else if (csName.equals("CS_LINEAR_RGB")) {
+                cspace = ColorSpace.CS_LINEAR_RGB;
+            } else {
+                isKnownPredefinedCS = false;
+            }
+        }
+
+        if (isKnownPredefinedCS) {
+            resolvedDeserializedProfile = getInstance(cspace);
+        } else {
+            resolvedDeserializedProfile = getInstance(data);
+        }
+    }
+
+    /**
+     * Resolves instances being deserialized into instances registered
+     * with CMM.
+     * @return ICC_Profile object for profile registered with CMM.
+     * @throws ObjectStreamException
+     *     never thrown, but mandated by the serialization spec.
+     * @since 1.3
+     */
+    protected Object readResolve() throws ObjectStreamException {
+        return resolvedDeserializedProfile;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/awt/color/ICC_ProfileGray.java	Thu Apr 10 16:28:45 2008 -0700
@@ -0,0 +1,150 @@
+/*
+ * Portions Copyright 1997-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/**********************************************************************
+ **********************************************************************
+ **********************************************************************
+ *** COPYRIGHT (c) Eastman Kodak Company, 1997                      ***
+ *** As  an unpublished  work pursuant to Title 17 of the United    ***
+ *** States Code.  All rights reserved.                             ***
+ **********************************************************************
+ **********************************************************************
+ **********************************************************************/
+
+package java.awt.color;
+
+import java.awt.image.LookupTable;
+import sun.java2d.cmm.ProfileDeferralInfo;
+
+/**
+ *
+ * A subclass of the ICC_Profile class which represents profiles
+ * which meet the following criteria: the color space type of the
+ * profile is TYPE_GRAY and the profile includes the grayTRCTag and
+ * mediaWhitePointTag tags.  Examples of this kind of profile are
+ * monochrome input profiles, monochrome display profiles, and
+ * monochrome output profiles.  The getInstance methods in the
+ * ICC_Profile class will
+ * return an ICC_ProfileGray object when the above conditions are
+ * met.  The advantage of this class is that it provides a lookup
+ * table that Java or native methods may be able to use directly to
+ * optimize color conversion in some cases.
+ * <p>
+ * To transform from a GRAY device profile color space to the CIEXYZ Profile
+ * Connection Space, the device gray component is transformed by
+ * a lookup through the tone reproduction curve (TRC).  The result is
+ * treated as the achromatic component of the PCS.
+<pre>
+
+&nbsp;               PCSY = grayTRC[deviceGray]
+
+</pre>
+ * The inverse transform is done by converting the PCS Y components to
+ * device Gray via the inverse of the grayTRC.
+ * <p>
+ */
+
+
+
+public class ICC_ProfileGray
+extends ICC_Profile {
+
+    static final long serialVersionUID = -1124721290732002649L;
+
+    /**
+     * Constructs a new ICC_ProfileGray from a CMM ID.
+     */
+    ICC_ProfileGray(long ID) {
+        super(ID);
+    }
+
+    /**
+     * Constructs a new ICC_ProfileGray from a ProfileDeferralInfo object.
+     */
+    ICC_ProfileGray(ProfileDeferralInfo pdi) {
+        super(pdi);
+    }
+
+
+    /**
+     * Returns a float array of length 3 containing the X, Y, and Z
+     * components of the mediaWhitePointTag in the ICC profile.
+     * @return an array containing the components of the
+     * mediaWhitePointTag in the ICC profile.
+     */
+    public float[] getMediaWhitePoint() {
+        return super.getMediaWhitePoint();
+    }
+
+
+    /**
+     * Returns a gamma value representing the tone reproduction
+     * curve (TRC).  If the profile represents the TRC as a table rather
+     * than a single gamma value, then an exception is thrown.  In this
+     * case the actual table can be obtained via getTRC().  When
+     * using a gamma value, the PCS Y component is computed as follows:
+<pre>
+
+&nbsp;                         gamma
+&nbsp;        PCSY = deviceGray
+
+</pre>
+     * @return the gamma value as a float.
+     * @exception ProfileDataException if the profile does not specify
+     *            the TRC as a single gamma value.
+     */
+    public float getGamma() {
+    float theGamma;
+
+        theGamma = super.getGamma(ICC_Profile.icSigGrayTRCTag);
+        return theGamma;
+    }
+
+    /**
+     * Returns the TRC as an array of shorts.  If the profile has
+     * specified the TRC as linear (gamma = 1.0) or as a simple gamma
+     * value, this method throws an exception, and the getGamma() method
+     * should be used to get the gamma value.  Otherwise the short array
+     * returned here represents a lookup table where the input Gray value
+     * is conceptually in the range [0.0, 1.0].  Value 0.0 maps
+     * to array index 0 and value 1.0 maps to array index length-1.
+     * Interpolation may be used to generate output values for
+     * input values which do not map exactly to an index in the
+     * array.  Output values also map linearly to the range [0.0, 1.0].
+     * Value 0.0 is represented by an array value of 0x0000 and
+     * value 1.0 by 0xFFFF, i.e. the values are really unsigned
+     * short values, although they are returned in a short array.
+     * @return a short array representing the TRC.
+     * @exception ProfileDataException if the profile does not specify
+     *            the TRC as a table.
+     */
+    public short[] getTRC() {
+    short[]    theTRC;
+
+        theTRC = super.getTRC(ICC_Profile.icSigGrayTRCTag);
+        return theTRC;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/awt/color/ICC_ProfileRGB.java	Thu Apr 10 16:28:45 2008 -0700
@@ -0,0 +1,282 @@
+/*
+ * Portions Copyright 1997-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/**********************************************************************
+ **********************************************************************
+ **********************************************************************
+ *** COPYRIGHT (c) Eastman Kodak Company, 1997                      ***
+ *** As  an unpublished  work pursuant to Title 17 of the United    ***
+ *** States Code.  All rights reserved.                             ***
+ **********************************************************************
+ **********************************************************************
+ **********************************************************************/
+
+package java.awt.color;
+
+import java.awt.image.LookupTable;
+import sun.java2d.cmm.ProfileDeferralInfo;
+
+/**
+ *
+ * The ICC_ProfileRGB class is a subclass of the ICC_Profile class
+ * that represents profiles which meet the following criteria:
+ * <ul>
+ * <li>The profile's color space type is RGB.</li>
+ * <li>The profile includes the <code>redColorantTag</code>,
+ * <code>greenColorantTag</code>, <code>blueColorantTag</code>,
+ * <code>redTRCTag</code>, <code>greenTRCTag</code>,
+ * <code>blueTRCTag</code>, and <code>mediaWhitePointTag</code> tags.</li>
+ * </ul>
+ * The <code>ICC_Profile</code> <code>getInstance</code> method will
+ * return an <code>ICC_ProfileRGB</code> object when these conditions are met.
+ * Three-component, matrix-based input profiles and RGB display profiles are
+ * examples of this type of profile.
+ * <p>
+ * This profile class provides color transform matrices and lookup tables
+ * that Java or native methods can use directly to
+ * optimize color conversion in some cases.
+ * <p>
+ * To transform from a device profile color space to the CIEXYZ Profile
+ * Connection Space, each device color component is first linearized by
+ * a lookup through the corresponding tone reproduction curve (TRC).
+ * The resulting linear RGB components are converted to the CIEXYZ PCS
+ * using a a 3x3 matrix constructed from the RGB colorants.
+ * <pre>
+ *
+ * &nbsp;               linearR = redTRC[deviceR]
+ *
+ * &nbsp;               linearG = greenTRC[deviceG]
+ *
+ * &nbsp;               linearB = blueTRC[deviceB]
+ *
+ * &nbsp; _      _       _                                             _   _         _
+ * &nbsp;[  PCSX  ]     [  redColorantX  greenColorantX  blueColorantX  ] [  linearR  ]
+ * &nbsp;[        ]     [                                               ] [           ]
+ * &nbsp;[  PCSY  ]  =  [  redColorantY  greenColorantY  blueColorantY  ] [  linearG  ]
+ * &nbsp;[        ]     [                                               ] [           ]
+ * &nbsp;[_ PCSZ _]     [_ redColorantZ  greenColorantZ  blueColorantZ _] [_ linearB _]
+ *
+ * </pre>
+ * The inverse transform is performed by converting PCS XYZ components to linear
+ * RGB components through the inverse of the above 3x3 matrix, and then converting
+ * linear RGB to device RGB through inverses of the TRCs.
+ * <p>
+ */
+
+
+
+public class ICC_ProfileRGB
+extends ICC_Profile {
+
+    static final long serialVersionUID = 8505067385152579334L;
+
+    /**
+     * Used to get a gamma value or TRC for the red component.
+     */
+    public static final int REDCOMPONENT = 0;
+
+    /**
+     * Used to get a gamma value or TRC for the green component.
+     */
+    public static final int GREENCOMPONENT = 1;
+
+    /**
+     * Used to get a gamma value or TRC for the blue component.
+     */
+    public static final int BLUECOMPONENT = 2;
+
+
+    /**
+     * Constructs an new <code>ICC_ProfileRGB</code> from a CMM ID.
+     *
+     * @param ID The CMM ID for the profile.
+     *
+     */
+    ICC_ProfileRGB(long ID) {
+        super(ID);
+    }
+
+    /**
+     * Constructs a new <code>ICC_ProfileRGB</code> from a
+     * ProfileDeferralInfo object.
+     *
+     * @param pdi
+     */
+    ICC_ProfileRGB(ProfileDeferralInfo pdi) {
+        super(pdi);
+    }
+
+
+    /**
+     * Returns an array that contains the components of the profile's
+     * <CODE>mediaWhitePointTag</CODE>.
+     *
+     * @return A 3-element <CODE>float</CODE> array containing the x, y,
+     * and z components of the profile's <CODE>mediaWhitePointTag</CODE>.
+     */
+    public float[] getMediaWhitePoint() {
+        return super.getMediaWhitePoint();
+    }
+
+
+    /**
+     * Returns a 3x3 <CODE>float</CODE> matrix constructed from the
+     * X, Y, and Z components of the profile's <CODE>redColorantTag</CODE>,
+     * <CODE>greenColorantTag</CODE>, and <CODE>blueColorantTag</CODE>.
+     * <p>
+     * This matrix can be used for color transforms in the forward
+     * direction of the profile--from the profile color space
+     * to the CIEXYZ PCS.
+     *
+     * @return A 3x3 <CODE>float</CODE> array that contains the x, y, and z
+     * components of the profile's <CODE>redColorantTag</CODE>,
+     * <CODE>greenColorantTag</CODE>, and <CODE>blueColorantTag</CODE>.
+     */
+    public float[][] getMatrix() {
+        float[][] theMatrix = new float[3][3];
+        float[] tmpMatrix;
+
+        tmpMatrix = getXYZTag(ICC_Profile.icSigRedColorantTag);
+        theMatrix[0][0] = tmpMatrix[0];
+        theMatrix[1][0] = tmpMatrix[1];
+        theMatrix[2][0] = tmpMatrix[2];
+        tmpMatrix = getXYZTag(ICC_Profile.icSigGreenColorantTag);
+        theMatrix[0][1] = tmpMatrix[0];
+        theMatrix[1][1] = tmpMatrix[1];
+        theMatrix[2][1] = tmpMatrix[2];
+        tmpMatrix = getXYZTag(ICC_Profile.icSigBlueColorantTag);
+        theMatrix[0][2] = tmpMatrix[0];
+        theMatrix[1][2] = tmpMatrix[1];
+        theMatrix[2][2] = tmpMatrix[2];
+        return theMatrix;
+    }
+
+    /**
+     * Returns a gamma value representing the tone reproduction curve
+     * (TRC) for a particular component.  The component parameter
+     * must be one of REDCOMPONENT, GREENCOMPONENT, or BLUECOMPONENT.
+     * <p>
+     * If the profile
+     * represents the TRC for the corresponding component
+     * as a table rather than a single gamma value, an
+     * exception is thrown.  In this case the actual table
+     * can be obtained through the {@link #getTRC(int)} method.
+     * When using a gamma value,
+     * the linear component (R, G, or B) is computed as follows:
+     * <pre>
+     *
+     * &nbsp;                                         gamma
+     * &nbsp;        linearComponent = deviceComponent
+     *
+     *</pre>
+     * @param component The <CODE>ICC_ProfileRGB</CODE> constant that
+     * represents the component whose TRC you want to retrieve
+     * @return the gamma value as a float.
+     * @exception ProfileDataException if the profile does not specify
+     *            the corresponding TRC as a single gamma value.
+     */
+    public float getGamma(int component) {
+    float theGamma;
+    int theSignature;
+
+        switch (component) {
+        case REDCOMPONENT:
+            theSignature = ICC_Profile.icSigRedTRCTag;
+            break;
+
+        case GREENCOMPONENT:
+            theSignature = ICC_Profile.icSigGreenTRCTag;
+            break;
+
+        case BLUECOMPONENT:
+            theSignature = ICC_Profile.icSigBlueTRCTag;
+            break;
+
+        default:
+            throw new IllegalArgumentException("Must be Red, Green, or Blue");
+        }
+
+        theGamma = super.getGamma(theSignature);
+
+        return theGamma;
+    }
+
+    /**
+     * Returns the TRC for a particular component as an array.
+     * Component must be <code>REDCOMPONENT</code>,
+     * <code>GREENCOMPONENT</code>, or <code>BLUECOMPONENT</code>.
+     * Otherwise the returned array
+     * represents a lookup table where the input component value
+     * is conceptually in the range [0.0, 1.0].  Value 0.0 maps
+     * to array index 0 and value 1.0 maps to array index length-1.
+     * Interpolation might be used to generate output values for
+     * input values that do not map exactly to an index in the
+     * array.  Output values also map linearly to the range [0.0, 1.0].
+     * Value 0.0 is represented by an array value of 0x0000 and
+     * value 1.0 by 0xFFFF.  In other words, the values are really unsigned
+     * <code>short</code> values even though they are returned in a
+     * <code>short</code> array.
+     *
+     * If the profile has specified the corresponding TRC
+     * as linear (gamma = 1.0) or as a simple gamma value, this method
+     * throws an exception.  In this case, the {@link #getGamma(int)}
+     * method should be used to get the gamma value.
+     *
+     * @param component The <CODE>ICC_ProfileRGB</CODE> constant that
+     * represents the component whose TRC you want to retrieve:
+     * <CODE>REDCOMPONENT</CODE>, <CODE>GREENCOMPONENT</CODE>, or
+     * <CODE>BLUECOMPONENT</CODE>.
+     *
+     * @return a short array representing the TRC.
+     * @exception ProfileDataException if the profile does not specify
+     *            the corresponding TRC as a table.
+     */
+    public short[] getTRC(int component) {
+    short[] theTRC;
+    int theSignature;
+
+        switch (component) {
+        case REDCOMPONENT:
+            theSignature = ICC_Profile.icSigRedTRCTag;
+            break;
+
+        case GREENCOMPONENT:
+            theSignature = ICC_Profile.icSigGreenTRCTag;
+            break;
+
+        case BLUECOMPONENT:
+            theSignature = ICC_Profile.icSigBlueTRCTag;
+            break;
+
+        default:
+            throw new IllegalArgumentException("Must be Red, Green, or Blue");
+        }
+
+        theTRC = super.getTRC(theSignature);
+
+        return theTRC;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/awt/image/BandedSampleModel.java	Thu Apr 10 16:28:45 2008 -0700
@@ -0,0 +1,839 @@
+/*
+ * Portions Copyright 1997-2006 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* ****************************************************************
+ ******************************************************************
+ ******************************************************************
+ *** COPYRIGHT (c) Eastman Kodak Company, 1997
+ *** As  an unpublished  work pursuant to Title 17 of the United
+ *** States Code.  All rights reserved.
+ ******************************************************************
+ ******************************************************************
+ ******************************************************************/
+
+package java.awt.image;
+
+/**
+ *  This class represents image data which is stored in a band interleaved
+ *  fashion and for
+ *  which each sample of a pixel occupies one data element of the DataBuffer.
+ *  It subclasses ComponentSampleModel but provides a more efficent
+ *  implementation for accessing band interleaved image data than is provided
+ *  by ComponentSampleModel.  This class should typically be used when working
+ *  with images which store sample data for each band in a different bank of the
+ *  DataBuffer. Accessor methods are provided so that image data can be
+ *  manipulated directly. Pixel stride is the number of
+ *  data array elements between two samples for the same band on the same
+ *  scanline. The pixel stride for a BandedSampleModel is one.
+ *  Scanline stride is the number of data array elements between
+ *  a given sample and the corresponding sample in the same column of the next
+ *  scanline.  Band offsets denote the number
+ *  of data array elements from the first data array element of the bank
+ *  of the DataBuffer holding each band to the first sample of the band.
+ *  The bands are numbered from 0 to N-1.
+ *  Bank indices denote the correspondence between a bank of the data buffer
+ *  and a band of image data.  This class supports
+ *  {@link DataBuffer#TYPE_BYTE TYPE_BYTE},
+ *  {@link DataBuffer#TYPE_USHORT TYPE_USHORT},
+ *  {@link DataBuffer#TYPE_SHORT TYPE_SHORT},
+ *  {@link DataBuffer#TYPE_INT TYPE_INT},
+ *  {@link DataBuffer#TYPE_FLOAT TYPE_FLOAT}, and
+ *  {@link DataBuffer#TYPE_DOUBLE TYPE_DOUBLE} datatypes
+ */
+
+
+public final class BandedSampleModel extends ComponentSampleModel
+{
+
+    /**
+     * Constructs a BandedSampleModel with the specified parameters.
+     * The pixel stride will be one data element.  The scanline stride
+     * will be the same as the width.  Each band will be stored in
+     * a separate bank and all band offsets will be zero.
+     * @param dataType  The data type for storing samples.
+     * @param w         The width (in pixels) of the region of
+     *                  image data described.
+     * @param h         The height (in pixels) of the region of image
+     *                  data described.
+     * @param numBands  The number of bands for the image data.
+     * @throws IllegalArgumentException if <code>dataType</code> is not
+     *         one of the supported data types
+     */
+    public BandedSampleModel(int dataType, int w, int h, int numBands) {
+        super(dataType, w, h, 1, w,
+              BandedSampleModel.createIndicesArray(numBands),
+              BandedSampleModel.createOffsetArray(numBands));
+    }
+
+    /**
+     * Constructs a BandedSampleModel with the specified parameters.
+     * The number of bands will be inferred from the lengths of the
+     * bandOffsets bankIndices arrays, which must be equal.  The pixel
+     * stride will be one data element.
+     * @param dataType  The data type for storing samples.
+     * @param w         The width (in pixels) of the region of
+     *                  image data described.
+     * @param h         The height (in pixels) of the region of
+     *                  image data described.
+     * @param scanlineStride The line stride of the of the image data.
+     * @param bankIndices The bank index for each band.
+     * @param bandOffsets The band offset for each band.
+     * @throws IllegalArgumentException if <code>dataType</code> is not
+     *         one of the supported data types
+     */
+    public BandedSampleModel(int dataType,
+                             int w, int h,
+                             int scanlineStride,
+                             int bankIndices[],
+                             int bandOffsets[]) {
+
+        super(dataType, w, h, 1,scanlineStride, bankIndices, bandOffsets);
+    }
+
+    /**
+     * Creates a new BandedSampleModel with the specified
+     * width and height.  The new BandedSampleModel will have the same
+     * number of bands, storage data type, and bank indices
+     * as this BandedSampleModel.  The band offsets will be compressed
+     * such that the offset between bands will be w*pixelStride and
+     * the minimum of all of the band offsets is zero.
+     * @param w the width of the resulting <code>BandedSampleModel</code>
+     * @param h the height of the resulting <code>BandedSampleModel</code>
+     * @return a new <code>BandedSampleModel</code> with the specified
+     *         width and height.
+     * @throws IllegalArgumentException if <code>w</code> or
+     *         <code>h</code> equals either
+     *         <code>Integer.MAX_VALUE</code> or
+     *         <code>Integer.MIN_VALUE</code>
+     * @throws IllegalArgumentException if <code>dataType</code> is not
+     *         one of the supported data types
+     */
+    public SampleModel createCompatibleSampleModel(int w, int h) {
+        int[] bandOffs;
+
+        if (numBanks == 1) {
+            bandOffs = orderBands(bandOffsets, w*h);
+        }
+        else {
+            bandOffs = new int[bandOffsets.length];
+        }
+
+        SampleModel sampleModel =
+            new BandedSampleModel(dataType, w, h, w, bankIndices, bandOffs);
+        return sampleModel;
+    }
+
+    /**
+     * Creates a new BandedSampleModel with a subset of the bands of this
+     * BandedSampleModel.  The new BandedSampleModel can be
+     * used with any DataBuffer that the existing BandedSampleModel
+     * can be used with.  The new BandedSampleModel/DataBuffer
+     * combination will represent an image with a subset of the bands
+     * of the original BandedSampleModel/DataBuffer combination.
+     * @throws RasterFormatException if the number of bands is greater than
+     *                               the number of banks in this sample model.
+     * @throws IllegalArgumentException if <code>dataType</code> is not
+     *         one of the supported data types
+     */
+    public SampleModel createSubsetSampleModel(int bands[]) {
+        if (bands.length > bankIndices.length)
+            throw new RasterFormatException("There are only " +
+                                            bankIndices.length +
+                                            " bands");
+        int newBankIndices[] = new int[bands.length];
+        int newBandOffsets[] = new int[bands.length];
+
+        for (int i=0; i<bands.length; i++) {
+            newBankIndices[i] = bankIndices[bands[i]];
+            newBandOffsets[i] = bandOffsets[bands[i]];
+        }
+
+        return new BandedSampleModel(this.dataType, width, height,
+                                     this.scanlineStride,
+                                     newBankIndices, newBandOffsets);
+    }
+
+    /**
+     * Creates a DataBuffer that corresponds to this BandedSampleModel,
+     * The DataBuffer's data type, number of banks, and size
+     * will be consistent with this BandedSampleModel.
+     * @throws IllegalArgumentException if <code>dataType</code> is not
+     *         one of the supported types.
+     */
+    public DataBuffer createDataBuffer() {
+        DataBuffer dataBuffer = null;
+
+        int size = scanlineStride * height;
+        switch (dataType) {
+        case DataBuffer.TYPE_BYTE:
+            dataBuffer = new DataBufferByte(size, numBanks);
+            break;
+        case DataBuffer.TYPE_USHORT:
+            dataBuffer = new DataBufferUShort(size, numBanks);
+            break;
+        case DataBuffer.TYPE_SHORT:
+            dataBuffer = new DataBufferShort(size, numBanks);
+            break;
+        case DataBuffer.TYPE_INT:
+            dataBuffer = new DataBufferInt(size, numBanks);
+            break;
+        case DataBuffer.TYPE_FLOAT:
+            dataBuffer = new DataBufferFloat(size, numBanks);
+            break;
+        case DataBuffer.TYPE_DOUBLE:
+            dataBuffer = new DataBufferDouble(size, numBanks);
+            break;
+        default:
+            throw new IllegalArgumentException("dataType is not one " +
+                "of the supported types.");
+        }
+
+        return dataBuffer;
+    }
+
+
+    /**
+     * Returns data for a single pixel in a primitive array of type
+     * TransferType.  For a BandedSampleModel, this will be the same
+     * as the data type, and samples will be returned one per array
+     * element.  Generally, obj
+     * should be passed in as null, so that the Object will be created
+     * automatically and will be of the right primitive data type.
+     * <p>
+     * The following code illustrates transferring data for one pixel from
+     * DataBuffer <code>db1</code>, whose storage layout is described by
+     * BandedSampleModel <code>bsm1</code>, to DataBuffer <code>db2</code>,
+     * whose storage layout is described by
+     * BandedSampleModel <code>bsm2</code>.
+     * The transfer will generally be more efficient than using
+     * getPixel/setPixel.
+     * <pre>
+     *       BandedSampleModel bsm1, bsm2;
+     *       DataBufferInt db1, db2;
+     *       bsm2.setDataElements(x, y, bsm1.getDataElements(x, y, null, db1),
+     *                            db2);
+     * </pre>
+     * Using getDataElements/setDataElements to transfer between two
+     * DataBuffer/SampleModel pairs is legitimate if the SampleModels have
+     * the same number of bands, corresponding bands have the same number of
+     * bits per sample, and the TransferTypes are the same.
+     * <p>
+     * If obj is non-null, it should be a primitive array of type TransferType.
+     * Otherwise, a ClassCastException is thrown.  An
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds, or if obj is non-null and is not large enough to hold
+     * the pixel data.
+     * @param x         The X coordinate of the pixel location
+     * @param y         The Y coordinate of the pixel location
+     * @param obj       If non-null, a primitive array in which to return
+     *                  the pixel data.
+     * @param data      The DataBuffer containing the image data.
+     * @return the data for the specified pixel.
+     * @see #setDataElements(int, int, Object, DataBuffer)
+     */
+    public Object getDataElements(int x, int y, Object obj, DataBuffer data) {
+        if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+        int type = getTransferType();
+        int numDataElems = getNumDataElements();
+        int pixelOffset = y*scanlineStride + x;
+
+        switch(type) {
+
+        case DataBuffer.TYPE_BYTE:
+
+            byte[] bdata;
+
+            if (obj == null) {
+                bdata = new byte[numDataElems];
+            } else {
+                bdata = (byte[])obj;
+            }
+
+            for (int i=0; i<numDataElems; i++) {
+                bdata[i] = (byte)data.getElem(bankIndices[i],
+                                              pixelOffset + bandOffsets[i]);
+            }
+
+            obj = (Object)bdata;
+            break;
+
+        case DataBuffer.TYPE_USHORT:
+        case DataBuffer.TYPE_SHORT:
+
+            short[] sdata;
+
+            if (obj == null) {
+                sdata = new short[numDataElems];
+            } else {
+                sdata = (short[])obj;
+            }
+
+            for (int i=0; i<numDataElems; i++) {
+                sdata[i] = (short)data.getElem(bankIndices[i],
+                                               pixelOffset + bandOffsets[i]);
+            }
+
+            obj = (Object)sdata;
+            break;
+
+        case DataBuffer.TYPE_INT:
+
+            int[] idata;
+
+            if (obj == null) {
+                idata = new int[numDataElems];
+            } else {
+                idata = (int[])obj;
+            }
+
+            for (int i=0; i<numDataElems; i++) {
+                idata[i] = data.getElem(bankIndices[i],
+                                        pixelOffset + bandOffsets[i]);
+            }
+
+            obj = (Object)idata;
+            break;
+
+        case DataBuffer.TYPE_FLOAT:
+
+            float[] fdata;
+
+            if (obj == null) {
+                fdata = new float[numDataElems];
+            } else {
+                fdata = (float[])obj;
+            }
+
+            for (int i=0; i<numDataElems; i++) {
+                fdata[i] = data.getElemFloat(bankIndices[i],
+                                             pixelOffset + bandOffsets[i]);
+            }
+
+            obj = (Object)fdata;
+            break;
+
+        case DataBuffer.TYPE_DOUBLE:
+
+            double[] ddata;
+
+            if (obj == null) {
+                ddata = new double[numDataElems];
+            } else {
+                ddata = (double[])obj;
+            }
+
+            for (int i=0; i<numDataElems; i++) {
+                ddata[i] = data.getElemDouble(bankIndices[i],
+                                              pixelOffset + bandOffsets[i]);
+            }
+
+            obj = (Object)ddata;
+            break;
+        }
+
+        return obj;
+    }
+
+    /**
+     * Returns all samples for the specified pixel in an int array.
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the pixel location
+     * @param y         The Y coordinate of the pixel location
+     * @param iArray    If non-null, returns the samples in this array
+     * @param data      The DataBuffer containing the image data
+     * @return the samples for the specified pixel.
+     * @see #setPixel(int, int, int[], DataBuffer)
+     */
+    public int[] getPixel(int x, int y, int iArray[], DataBuffer data) {
+        if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+
+        int[] pixels;
+
+        if (iArray != null) {
+           pixels = iArray;
+        } else {
+           pixels = new int [numBands];
+        }
+
+        int pixelOffset = y*scanlineStride + x;
+        for (int i=0; i<numBands; i++) {
+            pixels[i] = data.getElem(bankIndices[i],
+                                     pixelOffset + bandOffsets[i]);
+        }
+        return pixels;
+    }
+
+    /**
+     * Returns all samples for the specified rectangle of pixels in
+     * an int array, one sample per data array element.
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the upper left pixel location
+     * @param y         The Y coordinate of the upper left pixel location
+     * @param w         The width of the pixel rectangle
+     * @param h         The height of the pixel rectangle
+     * @param iArray    If non-null, returns the samples in this array
+     * @param data      The DataBuffer containing the image data
+     * @return the samples for the pixels within the specified region.
+     * @see #setPixels(int, int, int, int, int[], DataBuffer)
+     */
+    public int[] getPixels(int x, int y, int w, int h,
+                           int iArray[], DataBuffer data) {
+        if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+        int[] pixels;
+
+        if (iArray != null) {
+           pixels = iArray;
+        } else {
+           pixels = new int[w*h*numBands];
+        }
+
+        for (int k = 0; k < numBands; k++) {
+            int lineOffset = y*scanlineStride + x + bandOffsets[k];
+            int srcOffset = k;
+            int bank = bankIndices[k];
+
+            for (int i = 0; i < h; i++) {
+                int pixelOffset = lineOffset;
+                for (int j = 0; j < w; j++) {
+                    pixels[srcOffset] = data.getElem(bank, pixelOffset++);
+                    srcOffset += numBands;
+                }
+                lineOffset += scanlineStride;
+            }
+        }
+        return pixels;
+    }
+
+    /**
+     * Returns as int the sample in a specified band for the pixel
+     * located at (x,y).
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the pixel location
+     * @param y         The Y coordinate of the pixel location
+     * @param b         The band to return
+     * @param data      The DataBuffer containing the image data
+     * @return the sample in the specified band for the specified pixel.
+     * @see #setSample(int, int, int, int, DataBuffer)
+     */
+    public int getSample(int x, int y, int b, DataBuffer data) {
+        // Bounds check for 'b' will be performed automatically
+        if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+        int sample =
+            data.getElem(bankIndices[b],
+                         y*scanlineStride + x + bandOffsets[b]);
+        return sample;
+    }
+
+    /**
+     * Returns the sample in a specified band
+     * for the pixel located at (x,y) as a float.
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the pixel location
+     * @param y         The Y coordinate of the pixel location
+     * @param b         The band to return
+     * @param data      The DataBuffer containing the image data
+     * @return a float value that represents the sample in the specified
+     * band for the specified pixel.
+     */
+    public float getSampleFloat(int x, int y, int b, DataBuffer data) {
+        // Bounds check for 'b' will be performed automatically
+        if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+
+        float sample = data.getElemFloat(bankIndices[b],
+                                    y*scanlineStride + x + bandOffsets[b]);
+        return sample;
+    }
+
+    /**
+     * Returns the sample in a specified band
+     * for a pixel located at (x,y) as a double.
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the pixel location
+     * @param y         The Y coordinate of the pixel location
+     * @param b         The band to return
+     * @param data      The DataBuffer containing the image data
+     * @return a double value that represents the sample in the specified
+     * band for the specified pixel.
+     */
+    public double getSampleDouble(int x, int y, int b, DataBuffer data) {
+        // Bounds check for 'b' will be performed automatically
+        if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+
+        double sample = data.getElemDouble(bankIndices[b],
+                                       y*scanlineStride + x + bandOffsets[b]);
+        return sample;
+    }
+
+    /**
+     * Returns the samples in a specified band for the specified rectangle
+     * of pixels in an int array, one sample per data array element.
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the upper left pixel location
+     * @param y         The Y coordinate of the upper left pixel location
+     * @param w         The width of the pixel rectangle
+     * @param h         The height of the pixel rectangle
+     * @param b         The band to return
+     * @param iArray    If non-null, returns the samples in this array
+     * @param data      The DataBuffer containing the image data
+     * @return the samples in the specified band for the pixels within
+     * the specified region.
+     * @see #setSamples(int, int, int, int, int, int[], DataBuffer)
+     */
+    public int[] getSamples(int x, int y, int w, int h, int b,
+                            int iArray[], DataBuffer data) {
+        // Bounds check for 'b' will be performed automatically
+        if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+        int samples[];
+        if (iArray != null) {
+           samples = iArray;
+        } else {
+           samples = new int [w*h];
+        }
+
+        int lineOffset = y*scanlineStride + x + bandOffsets[b];
+        int srcOffset = 0;
+        int bank = bankIndices[b];
+
+        for (int i = 0; i < h; i++) {
+           int sampleOffset = lineOffset;
+           for (int j = 0; j < w; j++) {
+               samples[srcOffset++] = data.getElem(bank, sampleOffset++);
+           }
+           lineOffset += scanlineStride;
+        }
+        return samples;
+    }
+
+    /**
+     * Sets the data for a single pixel in the specified DataBuffer from a
+     * primitive array of type TransferType.  For a BandedSampleModel,
+     * this will be the same as the data type, and samples are transferred
+     * one per array element.
+     * <p>
+     * The following code illustrates transferring data for one pixel from
+     * DataBuffer <code>db1</code>, whose storage layout is described by
+     * BandedSampleModel <code>bsm1</code>, to DataBuffer <code>db2</code>,
+     * whose storage layout is described by
+     * BandedSampleModel <code>bsm2</code>.
+     * The transfer will generally be more efficient than using
+     * getPixel/setPixel.
+     * <pre>
+     *       BandedSampleModel bsm1, bsm2;
+     *       DataBufferInt db1, db2;
+     *       bsm2.setDataElements(x, y, bsm1.getDataElements(x, y, null, db1),
+     *                            db2);
+     * </pre>
+     * Using getDataElements/setDataElements to transfer between two
+     * DataBuffer/SampleModel pairs is legitimate if the SampleModels have
+     * the same number of bands, corresponding bands have the same number of
+     * bits per sample, and the TransferTypes are the same.
+     * <p>
+     * obj must be a primitive array of type TransferType.  Otherwise,
+     * a ClassCastException is thrown.  An
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds, or if obj is not large enough to hold the pixel data.
+     * @param x         The X coordinate of the pixel location
+     * @param y         The Y coordinate of the pixel location
+     * @param obj       If non-null, returns the primitive array in this
+     *                  object
+     * @param data      The DataBuffer containing the image data
+     * @see #getDataElements(int, int, Object, DataBuffer)
+     */
+    public void setDataElements(int x, int y, Object obj, DataBuffer data) {
+        if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+        int type = getTransferType();
+        int numDataElems = getNumDataElements();
+        int pixelOffset = y*scanlineStride + x;
+
+        switch(type) {
+
+        case DataBuffer.TYPE_BYTE:
+
+            byte[] barray = (byte[])obj;
+
+            for (int i=0; i<numDataElems; i++) {
+                data.setElem(bankIndices[i], pixelOffset + bandOffsets[i],
+                             barray[i] & 0xff);
+            }
+            break;
+
+        case DataBuffer.TYPE_USHORT:
+        case DataBuffer.TYPE_SHORT:
+
+            short[] sarray = (short[])obj;
+
+            for (int i=0; i<numDataElems; i++) {
+                data.setElem(bankIndices[i], pixelOffset + bandOffsets[i],
+                             sarray[i] & 0xffff);
+            }
+            break;
+
+        case DataBuffer.TYPE_INT:
+
+            int[] iarray = (int[])obj;
+
+            for (int i=0; i<numDataElems; i++) {
+                data.setElem(bankIndices[i], pixelOffset + bandOffsets[i],
+                             iarray[i]);
+            }
+            break;
+
+        case DataBuffer.TYPE_FLOAT:
+
+            float[] farray = (float[])obj;
+
+            for (int i=0; i<numDataElems; i++) {
+                data.setElemFloat(bankIndices[i], pixelOffset + bandOffsets[i],
+                                  farray[i]);
+            }
+            break;
+
+        case DataBuffer.TYPE_DOUBLE:
+
+            double[] darray = (double[])obj;
+
+            for (int i=0; i<numDataElems; i++) {
+                data.setElemDouble(bankIndices[i], pixelOffset + bandOffsets[i],
+                                   darray[i]);
+            }
+            break;
+
+        }
+    }
+
+    /**
+     * Sets a pixel in the DataBuffer using an int array of samples for input.
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the pixel location
+     * @param y         The Y coordinate of the pixel location
+     * @param iArray    The input samples in an int array
+     * @param data      The DataBuffer containing the image data
+     * @see #getPixel(int, int, int[], DataBuffer)
+     */
+    public void setPixel(int x, int y, int iArray[], DataBuffer data) {
+        if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+       int pixelOffset = y*scanlineStride + x;
+       for (int i=0; i<numBands; i++) {
+           data.setElem(bankIndices[i], pixelOffset + bandOffsets[i],
+                        iArray[i]);
+       }
+    }
+
+    /**
+     * Sets all samples for a rectangle of pixels from an int array containing
+     * one sample per array element.
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the upper left pixel location
+     * @param y         The Y coordinate of the upper left pixel location
+     * @param w         The width of the pixel rectangle
+     * @param h         The height of the pixel rectangle
+     * @param iArray    The input samples in an int array
+     * @param data      The DataBuffer containing the image data
+     * @see #getPixels(int, int, int, int, int[], DataBuffer)
+     */
+    public void setPixels(int x, int y, int w, int h,
+                          int iArray[], DataBuffer data) {
+        if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+
+        for (int k = 0; k < numBands; k++) {
+            int lineOffset = y*scanlineStride + x + bandOffsets[k];
+            int srcOffset = k;
+            int bank = bankIndices[k];
+
+            for (int i = 0; i < h; i++) {
+                int pixelOffset = lineOffset;
+                for (int j = 0; j < w; j++) {
+                    data.setElem(bank, pixelOffset++, iArray[srcOffset]);
+                    srcOffset += numBands;
+                }
+                lineOffset += scanlineStride;
+           }
+        }
+    }
+
+    /**
+     * Sets a sample in the specified band for the pixel located at (x,y)
+     * in the DataBuffer using an int for input.
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the pixel location
+     * @param y         The Y coordinate of the pixel location
+     * @param b         The band to set
+     * @param s         The input sample as an int
+     * @param data      The DataBuffer containing the image data
+     * @see #getSample(int, int, int, DataBuffer)
+     */
+    public void setSample(int x, int y, int b, int s,
+                          DataBuffer data) {
+        // Bounds check for 'b' will be performed automatically
+        if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+        data.setElem(bankIndices[b],
+                     y*scanlineStride + x + bandOffsets[b], s);
+    }
+
+    /**
+     * Sets a sample in the specified band for the pixel located at (x,y)
+     * in the DataBuffer using a float for input.
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the pixel location
+     * @param y         The Y coordinate of the pixel location
+     * @param b         The band to set
+     * @param s         The input sample as a float
+     * @param data      The DataBuffer containing the image data
+     * @see #getSample(int, int, int, DataBuffer)
+     */
+    public void setSample(int x, int y, int b,
+                          float s ,
+                          DataBuffer data) {
+        // Bounds check for 'b' will be performed automatically
+        if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+        data.setElemFloat(bankIndices[b],
+                          y*scanlineStride + x + bandOffsets[b], s);
+    }
+
+    /**
+     * Sets a sample in the specified band for the pixel located at (x,y)
+     * in the DataBuffer using a double for input.
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the pixel location
+     * @param y         The Y coordinate of the pixel location
+     * @param b         The band to set
+     * @param s         The input sample as a double
+     * @param data      The DataBuffer containing the image data
+     * @see #getSample(int, int, int, DataBuffer)
+     */
+    public void setSample(int x, int y, int b,
+                          double s,
+                          DataBuffer data) {
+        // Bounds check for 'b' will be performed automatically
+        if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+        data.setElemDouble(bankIndices[b],
+                          y*scanlineStride + x + bandOffsets[b], s);
+    }
+
+    /**
+     * Sets the samples in the specified band for the specified rectangle
+     * of pixels from an int array containing one sample per data array element.
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the upper left pixel location
+     * @param y         The Y coordinate of the upper left pixel location
+     * @param w         The width of the pixel rectangle
+     * @param h         The height of the pixel rectangle
+     * @param b         The band to set
+     * @param iArray    The input sample array
+     * @param data      The DataBuffer containing the image data
+     * @see #getSamples(int, int, int, int, int, int[], DataBuffer)
+     */
+    public void setSamples(int x, int y, int w, int h, int b,
+                           int iArray[], DataBuffer data) {
+        // Bounds check for 'b' will be performed automatically
+        if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+        int lineOffset = y*scanlineStride + x + bandOffsets[b];
+        int srcOffset = 0;
+        int bank = bankIndices[b];
+
+        for (int i = 0; i < h; i++) {
+           int sampleOffset = lineOffset;
+           for (int j = 0; j < w; j++) {
+              data.setElem(bank, sampleOffset++, iArray[srcOffset++]);
+           }
+           lineOffset += scanlineStride;
+        }
+    }
+
+    private static int[] createOffsetArray(int numBands) {
+        int[] bandOffsets = new int[numBands];
+        for (int i=0; i < numBands; i++) {
+            bandOffsets[i] = 0;
+        }
+        return bandOffsets;
+    }
+
+    private static int[] createIndicesArray(int numBands) {
+        int[] bankIndices = new int[numBands];
+        for (int i=0; i < numBands; i++) {
+            bankIndices[i] = i;
+        }
+        return bankIndices;
+    }
+
+    // Differentiate hash code from other ComponentSampleModel subclasses
+    public int hashCode() {
+        return super.hashCode() ^ 0x2;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/awt/image/ColorConvertOp.java	Thu Apr 10 16:28:45 2008 -0700
@@ -0,0 +1,1109 @@
+/*
+ * Portions Copyright 1997-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/**********************************************************************
+ **********************************************************************
+ **********************************************************************
+ *** COPYRIGHT (c) Eastman Kodak Company, 1997                      ***
+ *** As  an unpublished  work pursuant to Title 17 of the United    ***
+ *** States Code.  All rights reserved.                             ***
+ **********************************************************************
+ **********************************************************************
+ **********************************************************************/
+
+package java.awt.image;
+
+import java.awt.Point;
+import java.awt.Graphics2D;
+import java.awt.color.*;
+import sun.java2d.cmm.ColorTransform;
+import sun.java2d.cmm.CMSManager;
+import sun.java2d.cmm.ProfileDeferralMgr;
+import sun.java2d.cmm.PCMM;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.Point2D;
+import java.awt.RenderingHints;
+
+/**
+ * This class performs a pixel-by-pixel color conversion of the data in
+ * the source image.  The resulting color values are scaled to the precision
+ * of the destination image.  Color conversion can be specified
+ * via an array of ColorSpace objects or an array of ICC_Profile objects.
+ * <p>
+ * If the source is a BufferedImage with premultiplied alpha, the
+ * color components are divided by the alpha component before color conversion.
+ * If the destination is a BufferedImage with premultiplied alpha, the
+ * color components are multiplied by the alpha component after conversion.
+ * Rasters are treated as having no alpha channel, i.e. all bands are
+ * color bands.
+ * <p>
+ * If a RenderingHints object is specified in the constructor, the
+ * color rendering hint and the dithering hint may be used to control
+ * color conversion.
+ * <p>
+ * Note that Source and Destination may be the same object.
+ * <p>
+ * @see java.awt.RenderingHints#KEY_COLOR_RENDERING
+ * @see java.awt.RenderingHints#KEY_DITHERING
+ */
+public class ColorConvertOp implements BufferedImageOp, RasterOp {
+    ICC_Profile[]    profileList;
+    ColorSpace[]     CSList;
+    ColorTransform    thisTransform, thisRasterTransform;
+    ICC_Profile      thisSrcProfile, thisDestProfile;
+    RenderingHints   hints;
+    boolean          gotProfiles;
+    float[]          srcMinVals, srcMaxVals, dstMinVals, dstMaxVals;
+
+    /* the class initializer */
+    static {
+        if (ProfileDeferralMgr.deferring) {
+            ProfileDeferralMgr.activateProfiles();
+        }
+    }
+
+    /**
+     * Constructs a new ColorConvertOp which will convert
+     * from a source color space to a destination color space.
+     * The RenderingHints argument may be null.
+     * This Op can be used only with BufferedImages, and will convert
+     * directly from the ColorSpace of the source image to that of the
+     * destination.  The destination argument of the filter method
+     * cannot be specified as null.
+     * @param hints the <code>RenderingHints</code> object used to control
+     *        the color conversion, or <code>null</code>
+     */
+    public ColorConvertOp (RenderingHints hints)
+    {
+        profileList = new ICC_Profile [0];    /* 0 length list */
+        this.hints  = hints;
+    }
+
+    /**
+     * Constructs a new ColorConvertOp from a ColorSpace object.
+     * The RenderingHints argument may be null.  This
+     * Op can be used only with BufferedImages, and is primarily useful
+     * when the {@link #filter(BufferedImage, BufferedImage) filter}
+     * method is invoked with a destination argument of null.
+     * In that case, the ColorSpace defines the destination color space
+     * for the destination created by the filter method.  Otherwise, the
+     * ColorSpace defines an intermediate space to which the source is
+     * converted before being converted to the destination space.
+     * @param cspace defines the destination <code>ColorSpace</code> or an
+     *        intermediate <code>ColorSpace</code>
+     * @param hints the <code>RenderingHints</code> object used to control
+     *        the color conversion, or <code>null</code>
+     * @throws NullPointerException if cspace is null
+     */
+    public ColorConvertOp (ColorSpace cspace, RenderingHints hints)
+    {
+        if (cspace == null) {
+            throw new NullPointerException("ColorSpace cannot be null");
+        }
+        if (cspace instanceof ICC_ColorSpace) {
+            profileList = new ICC_Profile [1];    /* 1 profile in the list */
+
+            profileList [0] = ((ICC_ColorSpace) cspace).getProfile();
+        }
+        else {
+            CSList = new ColorSpace[1]; /* non-ICC case: 1 ColorSpace in list */
+            CSList[0] = cspace;
+        }
+        this.hints  = hints;
+    }
+
+
+    /**
+     * Constructs a new ColorConvertOp from two ColorSpace objects.
+     * The RenderingHints argument may be null.
+     * This Op is primarily useful for calling the filter method on
+     * Rasters, in which case the two ColorSpaces define the operation
+     * to be performed on the Rasters.  In that case, the number of bands
+     * in the source Raster must match the number of components in
+     * srcCspace, and the number of bands in the destination Raster
+     * must match the number of components in dstCspace.  For BufferedImages,
+     * the two ColorSpaces define intermediate spaces through which the
+     * source is converted before being converted to the destination space.
+     * @param srcCspace the source <code>ColorSpace</code>
+     * @param dstCspace the destination <code>ColorSpace</code>
+     * @param hints the <code>RenderingHints</code> object used to control
+     *        the color conversion, or <code>null</code>
+     * @throws NullPointerException if either srcCspace or dstCspace is null
+     */
+    public ColorConvertOp(ColorSpace srcCspace, ColorSpace dstCspace,
+                           RenderingHints hints)
+    {
+        if ((srcCspace == null) || (dstCspace == null)) {
+            throw new NullPointerException("ColorSpaces cannot be null");
+        }
+        if ((srcCspace instanceof ICC_ColorSpace) &&
+            (dstCspace instanceof ICC_ColorSpace)) {
+            profileList = new ICC_Profile [2];    /* 2 profiles in the list */
+
+            profileList [0] = ((ICC_ColorSpace) srcCspace).getProfile();
+            profileList [1] = ((ICC_ColorSpace) dstCspace).getProfile();
+
+            getMinMaxValsFromColorSpaces(srcCspace, dstCspace);
+        } else {
+            /* non-ICC case: 2 ColorSpaces in list */
+            CSList = new ColorSpace[2];
+            CSList[0] = srcCspace;
+            CSList[1] = dstCspace;
+        }
+        this.hints  = hints;
+    }
+
+
+     /**
+     * Constructs a new ColorConvertOp from an array of ICC_Profiles.
+     * The RenderingHints argument may be null.
+     * The sequence of profiles may include profiles that represent color
+     * spaces, profiles that represent effects, etc.  If the whole sequence
+     * does not represent a well-defined color conversion, an exception is
+     * thrown.
+     * <p>For BufferedImages, if the ColorSpace
+     * of the source BufferedImage does not match the requirements of the
+     * first profile in the array,
+     * the first conversion is to an appropriate ColorSpace.
+     * If the requirements of the last profile in the array are not met
+     * by the ColorSpace of the destination BufferedImage,
+     * the last conversion is to the destination's ColorSpace.
+     * <p>For Rasters, the number of bands in the source Raster must match
+     * the requirements of the first profile in the array, and the
+     * number of bands in the destination Raster must match the requirements
+     * of the last profile in the array.  The array must have at least two
+     * elements or calling the filter method for Rasters will throw an
+     * IllegalArgumentException.
+     * @param profiles the array of <code>ICC_Profile</code> objects
+     * @param hints the <code>RenderingHints</code> object used to control
+     *        the color conversion, or <code>null</code>
+     * @exception IllegalArgumentException when the profile sequence does not
+     *             specify a well-defined color conversion
+     * @exception NullPointerException if profiles is null
+     */
+    public ColorConvertOp (ICC_Profile[] profiles, RenderingHints hints)
+    {
+        if (profiles == null) {
+            throw new NullPointerException("Profiles cannot be null");
+        }
+        gotProfiles = true;
+        profileList = new ICC_Profile[profiles.length];
+        for (int i1 = 0; i1 < profiles.length; i1++) {
+            profileList[i1] = profiles[i1];
+        }
+        this.hints  = hints;
+    }
+
+
+    /**
+     * Returns the array of ICC_Profiles used to construct this ColorConvertOp.
+     * Returns null if the ColorConvertOp was not constructed from such an
+     * array.
+     * @return the array of <code>ICC_Profile</code> objects of this
+     *         <code>ColorConvertOp</code>, or <code>null</code> if this
+     *         <code>ColorConvertOp</code> was not constructed with an
+     *         array of <code>ICC_Profile</code> objects.
+     */
+    public final ICC_Profile[] getICC_Profiles() {
+        if (gotProfiles) {
+            ICC_Profile[] profiles = new ICC_Profile[profileList.length];
+            for (int i1 = 0; i1 < profileList.length; i1++) {
+                profiles[i1] = profileList[i1];
+            }
+            return profiles;
+        }
+        return null;
+    }
+
+    /**
+     * ColorConverts the source BufferedImage.
+     * If the destination image is null,
+     * a BufferedImage will be created with an appropriate ColorModel.
+     * @param src the source <code>BufferedImage</code> to be converted
+     * @param dest the destination <code>BufferedImage</code>,
+     *        or <code>null</code>
+     * @return <code>dest</code> color converted from <code>src</code>
+     *         or a new, converted <code>BufferedImage</code>
+     *         if <code>dest</code> is <code>null</code>
+     * @exception IllegalArgumentException if dest is null and this op was
+     *             constructed using the constructor which takes only a
+     *             RenderingHints argument, since the operation is ill defined.
+     */
+    public final BufferedImage filter(BufferedImage src, BufferedImage dest) {
+        ColorSpace srcColorSpace, destColorSpace;
+        BufferedImage savdest = null;
+
+        if (src.getColorModel() instanceof IndexColorModel) {
+            IndexColorModel icm = (IndexColorModel) src.getColorModel();
+            src = icm.convertToIntDiscrete(src.getRaster(), true);
+        }
+        srcColorSpace = src.getColorModel().getColorSpace();
+        if (dest != null) {
+            if (dest.getColorModel() instanceof IndexColorModel) {
+                savdest = dest;
+                dest = null;
+                destColorSpace = null;
+            } else {
+                destColorSpace = dest.getColorModel().getColorSpace();
+            }
+        } else {
+            destColorSpace = null;
+        }
+
+        if ((CSList != null) ||
+            (!(srcColorSpace instanceof ICC_ColorSpace)) ||
+            ((dest != null) &&
+             (!(destColorSpace instanceof ICC_ColorSpace)))) {
+            /* non-ICC case */
+            dest = nonICCBIFilter(src, srcColorSpace, dest, destColorSpace);
+        } else {
+            dest = ICCBIFilter(src, srcColorSpace, dest, destColorSpace);
+        }
+
+        if (savdest != null) {
+            Graphics2D big = savdest.createGraphics();
+            try {
+                big.drawImage(dest, 0, 0, null);
+            } finally {
+                big.dispose();
+            }
+            return savdest;
+        } else {
+            return dest;
+        }
+    }
+
+    private final BufferedImage ICCBIFilter(BufferedImage src,
+                                            ColorSpace srcColorSpace,
+                                            BufferedImage dest,
+                                            ColorSpace destColorSpace) {
+    int              nProfiles = profileList.length;
+    ICC_Profile      srcProfile = null, destProfile = null;
+
+        srcProfile = ((ICC_ColorSpace) srcColorSpace).getProfile();
+
+        if (dest == null) {        /* last profile in the list defines
+                                      the output color space */
+            if (nProfiles == 0) {
+                throw new IllegalArgumentException(
+                    "Destination ColorSpace is undefined");
+            }
+            destProfile = profileList [nProfiles - 1];
+            dest = createCompatibleDestImage(src, null);
+        }
+        else {
+            if (src.getHeight() != dest.getHeight() ||
+                src.getWidth() != dest.getWidth()) {
+                throw new IllegalArgumentException(
+                    "Width or height of BufferedImages do not match");
+            }
+            destProfile = ((ICC_ColorSpace) destColorSpace).getProfile();
+        }
+
+        /* Checking if all profiles in the transform sequence are the same.
+         * If so, performing just copying the data.
+         */
+        if (srcProfile == destProfile) {
+            boolean noTrans = true;
+            for (int i = 0; i < nProfiles; i++) {
+                if (srcProfile != profileList[i]) {
+                    noTrans = false;
+                    break;
+                }
+            }
+            if (noTrans) {
+                Graphics2D g = dest.createGraphics();
+                try {
+                    g.drawImage(src, 0, 0, null);
+                } finally {
+                    g.dispose();
+                }
+
+                return dest;
+            }
+        }
+
+        /* make a new transform if needed */
+        if ((thisTransform == null) || (thisSrcProfile != srcProfile) ||
+            (thisDestProfile != destProfile) ) {
+            updateBITransform(srcProfile, destProfile);
+        }
+
+        /* color convert the image */
+        thisTransform.colorConvert(src, dest);
+
+        return dest;
+    }
+
+    private void updateBITransform(ICC_Profile srcProfile,
+                                   ICC_Profile destProfile) {
+        ICC_Profile[]    theProfiles;
+        int              i1, nProfiles, nTransforms, whichTrans, renderState;
+        ColorTransform[]  theTransforms;
+        boolean          useSrc = false, useDest = false;
+
+        nProfiles = profileList.length;
+        nTransforms = nProfiles;
+        if ((nProfiles == 0) || (srcProfile != profileList[0])) {
+            nTransforms += 1;
+            useSrc = true;
+        }
+        if ((nProfiles == 0) || (destProfile != profileList[nProfiles - 1]) ||
+            (nTransforms < 2)) {
+            nTransforms += 1;
+            useDest = true;
+        }
+
+        /* make the profile list */
+        theProfiles = new ICC_Profile[nTransforms]; /* the list of profiles
+                                                       for this Op */
+
+        int idx = 0;
+        if (useSrc) {
+            /* insert source as first profile */
+            theProfiles[idx++] = srcProfile;
+        }
+
+        for (i1 = 0; i1 < nProfiles; i1++) {
+                                   /* insert profiles defined in this Op */
+            theProfiles[idx++] = profileList [i1];
+        }
+
+        if (useDest) {
+            /* insert dest as last profile */
+            theProfiles[idx] = destProfile;
+        }
+
+        /* make the transform list */
+        theTransforms = new ColorTransform [nTransforms];
+
+        /* initialize transform get loop */
+        if (theProfiles[0].getProfileClass() == ICC_Profile.CLASS_OUTPUT) {
+                                        /* if first profile is a printer
+                                           render as colorimetric */
+            renderState = ICC_Profile.icRelativeColorimetric;
+        }
+        else {
+            renderState = ICC_Profile.icPerceptual; /* render any other
+                                                       class perceptually */
+        }
+
+        whichTrans = ColorTransform.In;
+
+        PCMM mdl = CMSManager.getModule();
+
+        /* get the transforms from each profile */
+        for (i1 = 0; i1 < nTransforms; i1++) {
+            if (i1 == nTransforms -1) {         /* last profile? */
+                whichTrans = ColorTransform.Out; /* get output transform */
+            }
+            else {      /* check for abstract profile */
+                if ((whichTrans == ColorTransform.Simulation) &&
+                    (theProfiles[i1].getProfileClass () ==
+                     ICC_Profile.CLASS_ABSTRACT)) {
+                renderState = ICC_Profile.icPerceptual;
+                    whichTrans = ColorTransform.In;
+                }
+            }
+
+            theTransforms[i1] = mdl.createTransform (
+                theProfiles[i1], renderState, whichTrans);
+
+            /* get this profile's rendering intent to select transform
+               from next profile */
+            renderState = getRenderingIntent(theProfiles[i1]);
+
+            /* "middle" profiles use simulation transform */
+            whichTrans = ColorTransform.Simulation;
+        }
+
+        /* make the net transform */
+        thisTransform = mdl.createTransform(theTransforms);
+
+        /* update corresponding source and dest profiles */
+        thisSrcProfile = srcProfile;
+        thisDestProfile = destProfile;
+    }
+
+    /**
+     * ColorConverts the image data in the source Raster.
+     * If the destination Raster is null, a new Raster will be created.
+     * The number of bands in the source and destination Rasters must
+     * meet the requirements explained above.  The constructor used to
+     * create this ColorConvertOp must have provided enough information
+     * to define both source and destination color spaces.  See above.
+     * Otherwise, an exception is thrown.
+     * @param src the source <code>Raster</code> to be converted
+     * @param dest the destination <code>WritableRaster</code>,
+     *        or <code>null</code>
+     * @return <code>dest</code> color converted from <code>src</code>
+     *         or a new, converted <code>WritableRaster</code>
+     *         if <code>dest</code> is <code>null</code>
+     * @exception IllegalArgumentException if the number of source or
+     *             destination bands is incorrect, the source or destination
+     *             color spaces are undefined, or this op was constructed
+     *             with one of the constructors that applies only to
+     *             operations on BufferedImages.
+     */
+    public final WritableRaster filter (Raster src, WritableRaster dest)  {
+
+        if (CSList != null) {
+            /* non-ICC case */
+            return nonICCRasterFilter(src, dest);
+        }
+        int nProfiles = profileList.length;
+        if (nProfiles < 2) {
+            throw new IllegalArgumentException(
+                "Source or Destination ColorSpace is undefined");
+        }
+        if (src.getNumBands() != profileList[0].getNumComponents()) {
+            throw new IllegalArgumentException(
+                "Numbers of source Raster bands and source color space " +
+                "components do not match");
+        }
+        if (dest == null) {
+            dest = createCompatibleDestRaster(src);
+        }
+        else {
+            if (src.getHeight() != dest.getHeight() ||
+                src.getWidth() != dest.getWidth()) {
+                throw new IllegalArgumentException(
+                    "Width or height of Rasters do not match");
+            }
+            if (dest.getNumBands() !=
+                profileList[nProfiles-1].getNumComponents()) {
+                throw new IllegalArgumentException(
+                    "Numbers of destination Raster bands and destination " +
+                    "color space components do not match");
+            }
+        }
+
+        /* make a new transform if needed */
+        if (thisRasterTransform == null) {
+            int              i1, whichTrans, renderState;
+            ColorTransform[]  theTransforms;
+
+            /* make the transform list */
+            theTransforms = new ColorTransform [nProfiles];
+
+            /* initialize transform get loop */
+            if (profileList[0].getProfileClass() == ICC_Profile.CLASS_OUTPUT) {
+                                            /* if first profile is a printer
+                                               render as colorimetric */
+                renderState = ICC_Profile.icRelativeColorimetric;
+            }
+            else {
+                renderState = ICC_Profile.icPerceptual; /* render any other
+                                                           class perceptually */
+            }
+
+            whichTrans = ColorTransform.In;
+
+            PCMM mdl = CMSManager.getModule();
+
+            /* get the transforms from each profile */
+            for (i1 = 0; i1 < nProfiles; i1++) {
+                if (i1 == nProfiles -1) {         /* last profile? */
+                    whichTrans = ColorTransform.Out; /* get output transform */
+                }
+                else {  /* check for abstract profile */
+                    if ((whichTrans == ColorTransform.Simulation) &&
+                        (profileList[i1].getProfileClass () ==
+                         ICC_Profile.CLASS_ABSTRACT)) {
+                        renderState = ICC_Profile.icPerceptual;
+                        whichTrans = ColorTransform.In;
+                    }
+                }
+
+                theTransforms[i1] = mdl.createTransform (
+                    profileList[i1], renderState, whichTrans);
+
+                /* get this profile's rendering intent to select transform
+                   from next profile */
+                renderState = getRenderingIntent(profileList[i1]);
+
+                /* "middle" profiles use simulation transform */
+                whichTrans = ColorTransform.Simulation;
+            }
+
+            /* make the net transform */
+            thisRasterTransform = mdl.createTransform(theTransforms);
+        }
+
+        int srcTransferType = src.getTransferType();
+        int dstTransferType = dest.getTransferType();
+        if ((srcTransferType == DataBuffer.TYPE_FLOAT) ||
+            (srcTransferType == DataBuffer.TYPE_DOUBLE) ||
+            (dstTransferType == DataBuffer.TYPE_FLOAT) ||
+            (dstTransferType == DataBuffer.TYPE_DOUBLE)) {
+            if (srcMinVals == null) {
+                getMinMaxValsFromProfiles(profileList[0],
+                                          profileList[nProfiles-1]);
+            }
+            /* color convert the raster */
+            thisRasterTransform.colorConvert(src, dest,
+                                             srcMinVals, srcMaxVals,
+                                             dstMinVals, dstMaxVals);
+        } else {
+            /* color convert the raster */
+            thisRasterTransform.colorConvert(src, dest);
+        }
+
+
+        return dest;
+    }
+
+    /**
+     * Returns the bounding box of the destination, given this source.
+     * Note that this will be the same as the the bounding box of the
+     * source.
+     * @param src the source <code>BufferedImage</code>
+     * @return a <code>Rectangle2D</code> that is the bounding box
+     *         of the destination, given the specified <code>src</code>
+     */
+    public final Rectangle2D getBounds2D (BufferedImage src) {
+        return getBounds2D(src.getRaster());
+    }
+
+    /**
+     * Returns the bounding box of the destination, given this source.
+     * Note that this will be the same as the the bounding box of the
+     * source.
+     * @param src the source <code>Raster</code>
+     * @return a <code>Rectangle2D</code> that is the bounding box
+     *         of the destination, given the specified <code>src</code>
+     */
+    public final Rectangle2D getBounds2D (Raster src) {
+        /*        return new Rectangle (src.getXOffset(),
+                              src.getYOffset(),
+                              src.getWidth(), src.getHeight()); */
+        return src.getBounds();
+    }
+
+    /**
+     * Creates a zeroed destination image with the correct size and number of
+     * bands, given this source.
+     * @param src       Source image for the filter operation.
+     * @param destCM    ColorModel of the destination.  If null, an
+     *                  appropriate ColorModel will be used.
+     * @return a <code>BufferedImage</code> with the correct size and
+     * number of bands from the specified <code>src</code>.
+     * @throws IllegalArgumentException if <code>destCM</code> is
+     *         <code>null</code> and this <code>ColorConvertOp</code> was
+     *         created without any <code>ICC_Profile</code> or
+     *         <code>ColorSpace</code> defined for the destination
+     */
+    public BufferedImage createCompatibleDestImage (BufferedImage src,
+                                                    ColorModel destCM) {
+        ColorSpace cs = null;;
+        if (destCM == null) {
+            if (CSList == null) {
+                /* ICC case */
+                int nProfiles = profileList.length;
+                if (nProfiles == 0) {
+                    throw new IllegalArgumentException(
+                        "Destination ColorSpace is undefined");
+                }
+                ICC_Profile destProfile = profileList[nProfiles - 1];
+                cs = new ICC_ColorSpace(destProfile);
+            } else {
+                /* non-ICC case */
+                int nSpaces = CSList.length;
+                cs = CSList[nSpaces - 1];
+            }
+        }
+        return createCompatibleDestImage(src, destCM, cs);
+    }
+
+    private BufferedImage createCompatibleDestImage(BufferedImage src,
+                                                    ColorModel destCM,
+                                                    ColorSpace destCS) {
+        BufferedImage image;
+        if (destCM == null) {
+            ColorModel srcCM = src.getColorModel();
+            int nbands = destCS.getNumComponents();
+            boolean hasAlpha = srcCM.hasAlpha();
+            if (hasAlpha) {
+               nbands += 1;
+            }
+            int[] nbits = new int[nbands];
+            for (int i = 0; i < nbands; i++) {
+                nbits[i] = 8;
+            }
+            destCM = new ComponentColorModel(destCS, nbits, hasAlpha,
+                                             srcCM.isAlphaPremultiplied(),
+                                             srcCM.getTransparency(),
+                                             DataBuffer.TYPE_BYTE);
+        }
+        int w = src.getWidth();
+        int h = src.getHeight();
+        image = new BufferedImage(destCM,
+                                  destCM.createCompatibleWritableRaster(w, h),
+                                  destCM.isAlphaPremultiplied(), null);
+        return image;
+    }
+
+
+    /**
+     * Creates a zeroed destination Raster with the correct size and number of
+     * bands, given this source.
+     * @param src the specified <code>Raster</code>
+     * @return a <code>WritableRaster</code> with the correct size and number
+     *         of bands from the specified <code>src</code>
+     * @throws IllegalArgumentException if this <code>ColorConvertOp</code>
+     *         was created without sufficient information to define the
+     *         <code>dst</code> and <code>src</code> color spaces
+     */
+    public WritableRaster createCompatibleDestRaster (Raster src) {
+        int ncomponents;
+
+        if (CSList != null) {
+            /* non-ICC case */
+            if (CSList.length != 2) {
+                throw new IllegalArgumentException(
+                    "Destination ColorSpace is undefined");
+            }
+            ncomponents = CSList[1].getNumComponents();
+        } else {
+            /* ICC case */
+            int nProfiles = profileList.length;
+            if (nProfiles < 2) {
+                throw new IllegalArgumentException(
+                    "Destination ColorSpace is undefined");
+            }
+            ncomponents = profileList[nProfiles-1].getNumComponents();
+        }
+
+        WritableRaster dest =
+            Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
+                                  src.getWidth(),
+                                  src.getHeight(),
+                                  ncomponents,
+                                  new Point(src.getMinX(), src.getMinY()));
+        return dest;
+    }
+
+    /**
+     * Returns the location of the destination point given a
+     * point in the source.  If <code>dstPt</code> is non-null,
+     * it will be used to hold the return value.  Note that
+     * for this class, the destination point will be the same
+     * as the source point.
+     * @param srcPt the specified source <code>Point2D</code>
+     * @param dstPt the destination <code>Point2D</code>
+     * @return <code>dstPt</code> after setting its location to be
+     *         the same as <code>srcPt</code>
+     */
+    public final Point2D getPoint2D (Point2D srcPt, Point2D dstPt) {
+        if (dstPt == null) {
+            dstPt = new Point2D.Float();
+        }
+        dstPt.setLocation(srcPt.getX(), srcPt.getY());
+
+        return dstPt;
+    }
+
+
+    /**
+     * Returns the RenderingIntent from the specified ICC Profile.
+     */
+    private int getRenderingIntent (ICC_Profile profile) {
+        byte[] header = profile.getData(ICC_Profile.icSigHead);
+        int index = ICC_Profile.icHdrRenderingIntent;
+        return (((header[index]   & 0xff) << 24) |
+                ((header[index+1] & 0xff) << 16) |
+                ((header[index+2] & 0xff) <<  8) |
+                 (header[index+3] & 0xff));
+    }
+
+    /**
+     * Returns the rendering hints used by this op.
+     * @return the <code>RenderingHints</code> object of this
+     *         <code>ColorConvertOp</code>
+     */
+    public final RenderingHints getRenderingHints() {
+        return hints;
+    }
+
+    private final BufferedImage nonICCBIFilter(BufferedImage src,
+                                               ColorSpace srcColorSpace,
+                                               BufferedImage dst,
+                                               ColorSpace dstColorSpace) {
+
+        int w = src.getWidth();
+        int h = src.getHeight();
+        ICC_ColorSpace ciespace =
+            (ICC_ColorSpace) ColorSpace.getInstance(ColorSpace.CS_CIEXYZ);
+        if (dst == null) {
+            dst = createCompatibleDestImage(src, null);
+            dstColorSpace = dst.getColorModel().getColorSpace();
+        } else {
+            if ((h != dst.getHeight()) || (w != dst.getWidth())) {
+                throw new IllegalArgumentException(
+                    "Width or height of BufferedImages do not match");
+            }
+        }
+        Raster srcRas = src.getRaster();
+        WritableRaster dstRas = dst.getRaster();
+        ColorModel srcCM = src.getColorModel();
+        ColorModel dstCM = dst.getColorModel();
+        int srcNumComp = srcCM.getNumColorComponents();
+        int dstNumComp = dstCM.getNumColorComponents();
+        boolean dstHasAlpha = dstCM.hasAlpha();
+        boolean needSrcAlpha = srcCM.hasAlpha() && dstHasAlpha;
+        ColorSpace[] list;
+        if ((CSList == null) && (profileList.length != 0)) {
+            /* possible non-ICC src, some profiles, possible non-ICC dst */
+            boolean nonICCSrc, nonICCDst;
+            ICC_Profile srcProfile, dstProfile;
+            if (!(srcColorSpace instanceof ICC_ColorSpace)) {
+                nonICCSrc = true;
+                srcProfile = ciespace.getProfile();
+            } else {
+                nonICCSrc = false;
+                srcProfile = ((ICC_ColorSpace) srcColorSpace).getProfile();
+            }
+            if (!(dstColorSpace instanceof ICC_ColorSpace)) {
+                nonICCDst = true;
+                dstProfile = ciespace.getProfile();
+            } else {
+                nonICCDst = false;
+                dstProfile = ((ICC_ColorSpace) dstColorSpace).getProfile();
+            }
+            /* make a new transform if needed */
+            if ((thisTransform == null) || (thisSrcProfile != srcProfile) ||
+                (thisDestProfile != dstProfile) ) {
+                updateBITransform(srcProfile, dstProfile);
+            }
+            // process per scanline
+            float maxNum = 65535.0f; // use 16-bit precision in CMM
+            ColorSpace cs;
+            int iccSrcNumComp;
+            if (nonICCSrc) {
+                cs = ciespace;
+                iccSrcNumComp = 3;
+            } else {
+                cs = srcColorSpace;
+                iccSrcNumComp = srcNumComp;
+            }
+            float[] srcMinVal = new float[iccSrcNumComp];
+            float[] srcInvDiffMinMax = new float[iccSrcNumComp];
+            for (int i = 0; i < srcNumComp; i++) {
+                srcMinVal[i] = cs.getMinValue(i);
+                srcInvDiffMinMax[i] = maxNum / (cs.getMaxValue(i) - srcMinVal[i]);
+            }
+            int iccDstNumComp;
+            if (nonICCDst) {
+                cs = ciespace;
+                iccDstNumComp = 3;
+            } else {
+                cs = dstColorSpace;
+                iccDstNumComp = dstNumComp;
+            }
+            float[] dstMinVal = new float[iccDstNumComp];
+            float[] dstDiffMinMax = new float[iccDstNumComp];
+            for (int i = 0; i < dstNumComp; i++) {
+                dstMinVal[i] = cs.getMinValue(i);
+                dstDiffMinMax[i] = (cs.getMaxValue(i) - dstMinVal[i]) / maxNum;
+            }
+            float[] dstColor;
+            if (dstHasAlpha) {
+                int size = ((dstNumComp + 1) > 3) ? (dstNumComp + 1) : 3;
+                dstColor = new float[size];
+            } else {
+                int size = (dstNumComp  > 3) ? dstNumComp : 3;
+                dstColor = new float[size];
+            }
+            short[] srcLine = new short[w * iccSrcNumComp];
+            short[] dstLine = new short[w * iccDstNumComp];
+            Object pixel;
+            float[] color;
+            float[] alpha = null;
+            if (needSrcAlpha) {
+                alpha = new float[w];
+            }
+            int idx;
+            // process each scanline
+            for (int y = 0; y < h; y++) {
+                // convert src scanline
+                pixel = null;
+                color = null;
+                idx = 0;
+                for (int x = 0; x < w; x++) {
+                    pixel = srcRas.getDataElements(x, y, pixel);
+                    color = srcCM.getNormalizedComponents(pixel, color, 0);
+                    if (needSrcAlpha) {
+                        alpha[x] = color[srcNumComp];
+                    }
+                    if (nonICCSrc) {
+                        color = srcColorSpace.toCIEXYZ(color);
+                    }
+                    for (int i = 0; i < iccSrcNumComp; i++) {
+                        srcLine[idx++] = (short)
+                            ((color[i] - srcMinVal[i]) * srcInvDiffMinMax[i] +
+                             0.5f);
+                    }
+                }
+                // color convert srcLine to dstLine
+                thisTransform.colorConvert(srcLine, dstLine);
+                // convert dst scanline
+                pixel = null;
+                idx = 0;
+                for (int x = 0; x < w; x++) {
+                    for (int i = 0; i < iccDstNumComp; i++) {
+                        dstColor[i] = ((float) (dstLine[idx++] & 0xffff)) *
+                                      dstDiffMinMax[i] + dstMinVal[i];
+                    }
+                    if (nonICCDst) {
+                        color = srcColorSpace.fromCIEXYZ(dstColor);
+                        for (int i = 0; i < dstNumComp; i++) {
+                            dstColor[i] = color[i];
+                        }
+                    }
+                    if (needSrcAlpha) {
+                        dstColor[dstNumComp] = alpha[x];
+                    } else if (dstHasAlpha) {
+                        dstColor[dstNumComp] = 1.0f;
+                    }
+                    pixel = dstCM.getDataElements(dstColor, 0, pixel);
+                    dstRas.setDataElements(x, y, pixel);
+                }
+            }
+        } else {
+            /* possible non-ICC src, possible CSList, possible non-ICC dst */
+            // process per pixel
+            int numCS;
+            if (CSList == null) {
+                numCS = 0;
+            } else {
+                numCS = CSList.length;
+            }
+            float[] dstColor;
+            if (dstHasAlpha) {
+                dstColor = new float[dstNumComp + 1];
+            } else {
+                dstColor = new float[dstNumComp];
+            }
+            Object spixel = null;
+            Object dpixel = null;
+            float[] color = null;
+            float[] tmpColor;
+            // process each pixel
+            for (int y = 0; y < h; y++) {
+                for (int x = 0; x < w; x++) {
+                    spixel = srcRas.getDataElements(x, y, spixel);
+                    color = srcCM.getNormalizedComponents(spixel, color, 0);
+                    tmpColor = srcColorSpace.toCIEXYZ(color);
+                    for (int i = 0; i < numCS; i++) {
+                        tmpColor = CSList[i].fromCIEXYZ(tmpColor);
+                        tmpColor = CSList[i].toCIEXYZ(tmpColor);
+                    }
+                    tmpColor = dstColorSpace.fromCIEXYZ(tmpColor);
+                    for (int i = 0; i < dstNumComp; i++) {
+                        dstColor[i] = tmpColor[i];
+                    }
+                    if (needSrcAlpha) {
+                        dstColor[dstNumComp] = color[srcNumComp];
+                    } else if (dstHasAlpha) {
+                        dstColor[dstNumComp] = 1.0f;
+                    }
+                    dpixel = dstCM.getDataElements(dstColor, 0, dpixel);
+                    dstRas.setDataElements(x, y, dpixel);
+
+                }
+            }
+        }
+
+        return dst;
+    }
+
+    /* color convert a Raster - handles byte, ushort, int, short, float,
+       or double transferTypes */
+    private final WritableRaster nonICCRasterFilter(Raster src,
+                                                    WritableRaster dst)  {
+
+        if (CSList.length != 2) {
+            throw new IllegalArgumentException(
+                "Destination ColorSpace is undefined");
+        }
+        if (src.getNumBands() != CSList[0].getNumComponents()) {
+            throw new IllegalArgumentException(
+                "Numbers of source Raster bands and source color space " +
+                "components do not match");
+        }
+        if (dst == null) {
+            dst = createCompatibleDestRaster(src);
+        } else {
+            if (src.getHeight() != dst.getHeight() ||
+                src.getWidth() != dst.getWidth()) {
+                throw new IllegalArgumentException(
+                    "Width or height of Rasters do not match");
+            }
+            if (dst.getNumBands() != CSList[1].getNumComponents()) {
+                throw new IllegalArgumentException(
+                    "Numbers of destination Raster bands and destination " +
+                    "color space components do not match");
+            }
+        }
+
+        if (srcMinVals == null) {
+            getMinMaxValsFromColorSpaces(CSList[0], CSList[1]);
+        }
+
+        SampleModel srcSM = src.getSampleModel();
+        SampleModel dstSM = dst.getSampleModel();
+        boolean srcIsFloat, dstIsFloat;
+        int srcTransferType = src.getTransferType();
+        int dstTransferType = dst.getTransferType();
+        if ((srcTransferType == DataBuffer.TYPE_FLOAT) ||
+            (srcTransferType == DataBuffer.TYPE_DOUBLE)) {
+            srcIsFloat = true;
+        } else {
+            srcIsFloat = false;
+        }
+        if ((dstTransferType == DataBuffer.TYPE_FLOAT) ||
+            (dstTransferType == DataBuffer.TYPE_DOUBLE)) {
+            dstIsFloat = true;
+        } else {
+            dstIsFloat = false;
+        }
+        int w = src.getWidth();
+        int h = src.getHeight();
+        int srcNumBands = src.getNumBands();
+        int dstNumBands = dst.getNumBands();
+        float[] srcScaleFactor = null;
+        float[] dstScaleFactor = null;
+        if (!srcIsFloat) {
+            srcScaleFactor = new float[srcNumBands];
+            for (int i = 0; i < srcNumBands; i++) {
+                if (srcTransferType == DataBuffer.TYPE_SHORT) {
+                    srcScaleFactor[i] = (srcMaxVals[i] - srcMinVals[i]) /
+                                        32767.0f;
+                } else {
+                    srcScaleFactor[i] = (srcMaxVals[i] - srcMinVals[i]) /
+                        ((float) ((1 << srcSM.getSampleSize(i)) - 1));
+                }
+            }
+        }
+        if (!dstIsFloat) {
+            dstScaleFactor = new float[dstNumBands];
+            for (int i = 0; i < dstNumBands; i++) {
+                if (dstTransferType == DataBuffer.TYPE_SHORT) {
+                    dstScaleFactor[i] = 32767.0f /
+                                        (dstMaxVals[i] - dstMinVals[i]);
+                } else {
+                    dstScaleFactor[i] =
+                        ((float) ((1 << dstSM.getSampleSize(i)) - 1)) /
+                        (dstMaxVals[i] - dstMinVals[i]);
+                }
+            }
+        }
+        int ys = src.getMinY();
+        int yd = dst.getMinY();
+        int xs, xd;
+        float sample;
+        float[] color = new float[srcNumBands];
+        float[] tmpColor;
+        ColorSpace srcColorSpace = CSList[0];
+        ColorSpace dstColorSpace = CSList[1];
+        // process each pixel
+        for (int y = 0; y < h; y++, ys++, yd++) {
+            // get src scanline
+            xs = src.getMinX();
+            xd = dst.getMinX();
+            for (int x = 0; x < w; x++, xs++, xd++) {
+                for (int i = 0; i < srcNumBands; i++) {
+                    sample = src.getSampleFloat(xs, ys, i);
+                    if (!srcIsFloat) {
+                        sample = sample * srcScaleFactor[i] + srcMinVals[i];
+                    }
+                    color[i] = sample;
+                }
+                tmpColor = srcColorSpace.toCIEXYZ(color);
+                tmpColor = dstColorSpace.fromCIEXYZ(tmpColor);
+                for (int i = 0; i < dstNumBands; i++) {
+                    sample = tmpColor[i];
+                    if (!dstIsFloat) {
+                        sample = (sample - dstMinVals[i]) * dstScaleFactor[i];
+                    }
+                    dst.setSample(xd, yd, i, sample);
+                }
+            }
+        }
+        return dst;
+    }
+
+    private void getMinMaxValsFromProfiles(ICC_Profile srcProfile,
+                                           ICC_Profile dstProfile) {
+        int type = srcProfile.getColorSpaceType();
+        int nc = srcProfile.getNumComponents();
+        srcMinVals = new float[nc];
+        srcMaxVals = new float[nc];
+        setMinMax(type, nc, srcMinVals, srcMaxVals);
+        type = dstProfile.getColorSpaceType();
+        nc = dstProfile.getNumComponents();
+        dstMinVals = new float[nc];
+        dstMaxVals = new float[nc];
+        setMinMax(type, nc, dstMinVals, dstMaxVals);
+    }
+
+    private void setMinMax(int type, int nc, float[] minVals, float[] maxVals) {
+        if (type == ColorSpace.TYPE_Lab) {
+            minVals[0] = 0.0f;    // L
+            maxVals[0] = 100.0f;
+            minVals[1] = -128.0f; // a
+            maxVals[1] = 127.0f;
+            minVals[2] = -128.0f; // b
+            maxVals[2] = 127.0f;
+        } else if (type == ColorSpace.TYPE_XYZ) {
+            minVals[0] = minVals[1] = minVals[2] = 0.0f; // X, Y, Z
+            maxVals[0] = maxVals[1] = maxVals[2] = 1.0f + (32767.0f/ 32768.0f);
+        } else {
+            for (int i = 0; i < nc; i++) {
+                minVals[i] = 0.0f;
+                maxVals[i] = 1.0f;
+            }
+        }
+    }
+
+    private void getMinMaxValsFromColorSpaces(ColorSpace srcCspace,
+                                              ColorSpace dstCspace) {
+        int nc = srcCspace.getNumComponents();
+        srcMinVals = new float[nc];
+        srcMaxVals = new float[nc];
+        for (int i = 0; i < nc; i++) {
+            srcMinVals[i] = srcCspace.getMinValue(i);
+            srcMaxVals[i] = srcCspace.getMaxValue(i);
+        }
+        nc = dstCspace.getNumComponents();
+        dstMinVals = new float[nc];
+        dstMaxVals = new float[nc];
+        for (int i = 0; i < nc; i++) {
+            dstMinVals[i] = dstCspace.getMinValue(i);
+            dstMaxVals[i] = dstCspace.getMaxValue(i);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/awt/image/ComponentSampleModel.java	Thu Apr 10 16:28:45 2008 -0700
@@ -0,0 +1,1202 @@
+/*
+ * Portions Copyright 1997-2006 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* ****************************************************************
+ ******************************************************************
+ ******************************************************************
+ *** COPYRIGHT (c) Eastman Kodak Company, 1997
+ *** As  an unpublished  work pursuant to Title 17 of the United
+ *** States Code.  All rights reserved.
+ ******************************************************************
+ ******************************************************************
+ ******************************************************************/
+
+package java.awt.image;
+
+import java.util.Arrays;
+
+/**
+ *  This class represents image data which is stored such that each sample
+ *  of a pixel occupies one data element of the DataBuffer.  It stores the
+ *  N samples which make up a pixel in N separate data array elements.
+ *  Different bands may be in different banks of the DataBuffer.
+ *  Accessor methods are provided so that image data can be manipulated
+ *  directly. This class can support different kinds of interleaving, e.g.
+ *  band interleaving, scanline interleaving, and pixel interleaving.
+ *  Pixel stride is the number of data array elements between two samples
+ *  for the same band on the same scanline. Scanline stride is the number
+ *  of data array elements between a given sample and the corresponding sample
+ *  in the same column of the next scanline.  Band offsets denote the number
+ *  of data array elements from the first data array element of the bank
+ *  of the DataBuffer holding each band to the first sample of the band.
+ *  The bands are numbered from 0 to N-1.  This class can represent image
+ *  data for which each sample is an unsigned integral number which can be
+ *  stored in 8, 16, or 32 bits (using <code>DataBuffer.TYPE_BYTE</code>,
+ *  <code>DataBuffer.TYPE_USHORT</code>, or <code>DataBuffer.TYPE_INT</code>,
+ *  respectively), data for which each sample is a signed integral number
+ *  which can be stored in 16 bits (using <code>DataBuffer.TYPE_SHORT</code>),
+ *  or data for which each sample is a signed float or double quantity
+ *  (using <code>DataBuffer.TYPE_FLOAT</code> or
+ *  <code>DataBuffer.TYPE_DOUBLE</code>, respectively).
+ *  All samples of a given ComponentSampleModel
+ *  are stored with the same precision.  All strides and offsets must be
+ *  non-negative.  This class supports
+ *  {@link DataBuffer#TYPE_BYTE TYPE_BYTE},
+ *  {@link DataBuffer#TYPE_USHORT TYPE_USHORT},
+ *  {@link DataBuffer#TYPE_SHORT TYPE_SHORT},
+ *  {@link DataBuffer#TYPE_INT TYPE_INT},
+ *  {@link DataBuffer#TYPE_FLOAT TYPE_FLOAT},
+ *  {@link DataBuffer#TYPE_DOUBLE TYPE_DOUBLE},
+ *  @see java.awt.image.PixelInterleavedSampleModel
+ *  @see java.awt.image.BandedSampleModel
+ */
+
+public class ComponentSampleModel extends SampleModel
+{
+    /** Offsets for all bands in data array elements. */
+    protected int bandOffsets[];
+
+    /** Index for each bank storing a band of image data. */
+    protected int[] bankIndices;
+
+    /**
+     * The number of bands in this
+     * <code>ComponentSampleModel</code>.
+     */
+    protected int numBands = 1;
+
+    /**
+     * The number of banks in this
+     * <code>ComponentSampleModel</code>.
+     */
+    protected int numBanks = 1;
+
+    /**
+     *  Line stride (in data array elements) of the region of image
+     *  data described by this ComponentSampleModel.
+     */
+    protected int scanlineStride;
+
+    /** Pixel stride (in data array elements) of the region of image
+     *  data described by this ComponentSampleModel.
+     */
+    protected int pixelStride;
+
+    static private native void initIDs();
+    static {
+        ColorModel.loadLibraries();
+        initIDs();
+    }
+
+    /**
+     * Constructs a ComponentSampleModel with the specified parameters.
+     * The number of bands will be given by the length of the bandOffsets array.
+     * All bands will be stored in the first bank of the DataBuffer.
+     * @param dataType  the data type for storing samples
+     * @param w         the width (in pixels) of the region of
+     *     image data described
+     * @param h         the height (in pixels) of the region of
+     *     image data described
+     * @param pixelStride the pixel stride of the region of image
+     *     data described
+     * @param scanlineStride the line stride of the region of image
+     *     data described
+     * @param bandOffsets the offsets of all bands
+     * @throws IllegalArgumentException if <code>w</code> or
+     *         <code>h</code> is not greater than 0
+     * @throws IllegalArgumentException if <code>pixelStride</code>
+     *         is less than 0
+     * @throws IllegalArgumentException if <code>scanlineStride</code>
+     *         is less than 0
+     * @throws IllegalArgumentException if <code>numBands</code>
+     *         is less than 1
+     * @throws IllegalArgumentException if the product of <code>w</code>
+     *         and <code>h</code> is greater than
+     *         <code>Integer.MAX_VALUE</code>
+     * @throws IllegalArgumentException if <code>dataType</code> is not
+     *         one of the supported data types
+     */
+    public ComponentSampleModel(int dataType,
+                                int w, int h,
+                                int pixelStride,
+                                int scanlineStride,
+                                int bandOffsets[]) {
+        super(dataType, w, h, bandOffsets.length);
+        this.dataType = dataType;
+        this.pixelStride = pixelStride;
+        this.scanlineStride  = scanlineStride;
+        this.bandOffsets = (int[])bandOffsets.clone();
+        numBands = bandOffsets.length;
+        if (pixelStride < 0) {
+            throw new IllegalArgumentException("Pixel stride must be >= 0");
+        }
+        // TODO - bug 4296691 - remove this check
+        if (scanlineStride < 0) {
+            throw new IllegalArgumentException("Scanline stride must be >= 0");
+        }
+        if (numBands < 1) {
+            throw new IllegalArgumentException("Must have at least one band.");
+        }
+        if ((dataType < DataBuffer.TYPE_BYTE) ||
+            (dataType > DataBuffer.TYPE_DOUBLE)) {
+            throw new IllegalArgumentException("Unsupported dataType.");
+        }
+        bankIndices = new int[numBands];
+        for (int i=0; i<numBands; i++) {
+            bankIndices[i] = 0;
+        }
+    }
+
+
+    /**
+     * Constructs a ComponentSampleModel with the specified parameters.
+     * The number of bands will be given by the length of the bandOffsets array.
+     * Different bands may be stored in different banks of the DataBuffer.
+     *
+     * @param dataType  the data type for storing samples
+     * @param w         the width (in pixels) of the region of
+     *     image data described
+     * @param h         the height (in pixels) of the region of
+     *     image data described
+     * @param pixelStride the pixel stride of the region of image
+     *     data described
+     * @param scanlineStride The line stride of the region of image
+     *     data described
+     * @param bankIndices the bank indices of all bands
+     * @param bandOffsets the band offsets of all bands
+     * @throws IllegalArgumentException if <code>w</code> or
+     *         <code>h</code> is not greater than 0
+     * @throws IllegalArgumentException if <code>pixelStride</code>
+     *         is less than 0
+     * @throws IllegalArgumentException if <code>scanlineStride</code>
+     *         is less than 0
+     * @throws IllegalArgumentException if the length of
+     *         <code>bankIndices</code> does not equal the length of
+     *         <code>bankOffsets</code>
+     * @throws IllegalArgumentException if any of the bank indices
+     *         of <code>bandIndices</code> is less than 0
+     * @throws IllegalArgumentException if <code>dataType</code> is not
+     *         one of the supported data types
+     */
+    public ComponentSampleModel(int dataType,
+                                int w, int h,
+                                int pixelStride,
+                                int scanlineStride,
+                                int bankIndices[],
+                                int bandOffsets[]) {
+        super(dataType, w, h, bandOffsets.length);
+        this.dataType = dataType;
+        this.pixelStride = pixelStride;
+        this.scanlineStride  = scanlineStride;
+        this.bandOffsets = (int[])bandOffsets.clone();
+        this.bankIndices = (int[]) bankIndices.clone();
+        if (pixelStride < 0) {
+            throw new IllegalArgumentException("Pixel stride must be >= 0");
+        }
+        // TODO - bug 4296691 - remove this check
+        if (scanlineStride < 0) {
+            throw new IllegalArgumentException("Scanline stride must be >= 0");
+        }
+        if ((dataType < DataBuffer.TYPE_BYTE) ||
+            (dataType > DataBuffer.TYPE_DOUBLE)) {
+            throw new IllegalArgumentException("Unsupported dataType.");
+        }
+        int maxBank = bankIndices[0];
+        if (maxBank < 0) {
+            throw new IllegalArgumentException("Index of bank 0 is less than "+
+                                               "0 ("+maxBank+")");
+        }
+        for (int i=1; i < bankIndices.length; i++) {
+            if (bankIndices[i] > maxBank) {
+                maxBank = bankIndices[i];
+            }
+            else if (bankIndices[i] < 0) {
+                throw new IllegalArgumentException("Index of bank "+i+
+                                                   " is less than 0 ("+
+                                                   maxBank+")");
+            }
+        }
+        numBanks         = maxBank+1;
+        numBands         = bandOffsets.length;
+        if (bandOffsets.length != bankIndices.length) {
+            throw new IllegalArgumentException("Length of bandOffsets must "+
+                                               "equal length of bankIndices.");
+        }
+    }
+
+    /**
+     * Returns the size of the data buffer (in data elements) needed
+     * for a data buffer that matches this ComponentSampleModel.
+     */
+     private long getBufferSize() {
+         int maxBandOff=bandOffsets[0];
+         for (int i=1; i<bandOffsets.length; i++)
+             maxBandOff = Math.max(maxBandOff,bandOffsets[i]);
+
+         long size = 0;
+         if (maxBandOff >= 0)
+             size += maxBandOff+1;
+         if (pixelStride > 0)
+             size += pixelStride * (width-1);
+         if (scanlineStride > 0)
+             size += scanlineStride*(height-1);
+         return size;
+     }
+
+     /**
+      * Preserves band ordering with new step factor...
+      */
+    int []orderBands(int orig[], int step) {
+        int map[] = new int[orig.length];
+        int ret[] = new int[orig.length];
+
+        for (int i=0; i<map.length; i++) map[i] = i;
+
+        for (int i = 0; i < ret.length; i++) {
+            int index = i;
+            for (int j = i+1; j < ret.length; j++) {
+                if (orig[map[index]] > orig[map[j]]) {
+                    index = j;
+                }
+            }
+            ret[map[index]] = i*step;
+            map[index]  = map[i];
+        }
+        return ret;
+    }
+
+    /**
+     * Creates a new <code>ComponentSampleModel</code> with the specified
+     * width and height.  The new <code>SampleModel</code> will have the same
+     * number of bands, storage data type, interleaving scheme, and
+     * pixel stride as this <code>SampleModel</code>.
+     * @param w the width of the resulting <code>SampleModel</code>
+     * @param h the height of the resulting <code>SampleModel</code>
+     * @return a new <code>ComponentSampleModel</code> with the specified size
+     * @throws IllegalArgumentException if <code>w</code> or
+     *         <code>h</code> is not greater than 0
+     */
+    public SampleModel createCompatibleSampleModel(int w, int h) {
+        SampleModel ret=null;
+        long size;
+        int minBandOff=bandOffsets[0];
+        int maxBandOff=bandOffsets[0];
+        for (int i=1; i<bandOffsets.length; i++) {
+            minBandOff = Math.min(minBandOff,bandOffsets[i]);
+            maxBandOff = Math.max(maxBandOff,bandOffsets[i]);
+        }
+        maxBandOff -= minBandOff;
+
+        int bands   = bandOffsets.length;
+        int bandOff[];
+        int pStride = Math.abs(pixelStride);
+        int lStride = Math.abs(scanlineStride);
+        int bStride = Math.abs(maxBandOff);
+
+        if (pStride > lStride) {
+            if (pStride > bStride) {
+                if (lStride > bStride) { // pix > line > band
+                    bandOff = new int[bandOffsets.length];
+                    for (int i=0; i<bands; i++)
+                        bandOff[i] = bandOffsets[i]-minBandOff;
+                    lStride = bStride+1;
+                    pStride = lStride*h;
+                } else { // pix > band > line
+                    bandOff = orderBands(bandOffsets,lStride*h);
+                    pStride = bands*lStride*h;
+                }
+            } else { // band > pix > line
+                pStride = lStride*h;
+                bandOff = orderBands(bandOffsets,pStride*w);
+            }
+        } else {
+            if (pStride > bStride) { // line > pix > band
+                bandOff = new int[bandOffsets.length];
+                for (int i=0; i<bands; i++)
+                    bandOff[i] = bandOffsets[i]-minBandOff;
+                pStride = bStride+1;
+                lStride = pStride*w;
+            } else {
+                if (lStride > bStride) { // line > band > pix
+                    bandOff = orderBands(bandOffsets,pStride*w);
+                    lStride = bands*pStride*w;
+                } else { // band > line > pix
+                    lStride = pStride*w;
+                    bandOff = orderBands(bandOffsets,lStride*h);
+                }
+            }
+        }
+
+        // make sure we make room for negative offsets...
+        int base = 0;
+        if (scanlineStride < 0) {
+            base += lStride*h;
+            lStride *= -1;
+        }
+        if (pixelStride    < 0) {
+            base += pStride*w;
+            pStride *= -1;
+        }
+
+        for (int i=0; i<bands; i++)
+            bandOff[i] += base;
+        return new ComponentSampleModel(dataType, w, h, pStride,
+                                        lStride, bankIndices, bandOff);
+    }
+
+    /**
+     * Creates a new ComponentSampleModel with a subset of the bands
+     * of this ComponentSampleModel.  The new ComponentSampleModel can be
+     * used with any DataBuffer that the existing ComponentSampleModel
+     * can be used with.  The new ComponentSampleModel/DataBuffer
+     * combination will represent an image with a subset of the bands
+     * of the original ComponentSampleModel/DataBuffer combination.
+     * @param bands a subset of bands from this
+     *              <code>ComponentSampleModel</code>
+     * @return a <code>ComponentSampleModel</code> created with a subset
+     *          of bands from this <code>ComponentSampleModel</code>.
+     */
+    public SampleModel createSubsetSampleModel(int bands[]) {
+       if (bands.length > bankIndices.length)
+            throw new RasterFormatException("There are only " +
+                                            bankIndices.length +
+                                            " bands");
+        int newBankIndices[] = new int[bands.length];
+        int newBandOffsets[] = new int[bands.length];
+
+        for (int i=0; i<bands.length; i++) {
+            newBankIndices[i] = bankIndices[bands[i]];
+            newBandOffsets[i] = bandOffsets[bands[i]];
+        }
+
+        return new ComponentSampleModel(this.dataType, width, height,
+                                        this.pixelStride,
+                                        this.scanlineStride,
+                                        newBankIndices, newBandOffsets);
+    }
+
+    /**
+     * Creates a <code>DataBuffer</code> that corresponds to this
+     * <code>ComponentSampleModel</code>.
+     * The <code>DataBuffer</code> object's data type, number of banks,
+     * and size are be consistent with this <code>ComponentSampleModel</code>.
+     * @return a <code>DataBuffer</code> whose data type, number of banks
+     *         and size are consistent with this
+     *         <code>ComponentSampleModel</code>.
+     */
+    public DataBuffer createDataBuffer() {
+        DataBuffer dataBuffer = null;
+
+        int size = (int)getBufferSize();
+        switch (dataType) {
+        case DataBuffer.TYPE_BYTE:
+            dataBuffer = new DataBufferByte(size, numBanks);
+            break;
+        case DataBuffer.TYPE_USHORT:
+            dataBuffer = new DataBufferUShort(size, numBanks);
+            break;
+        case DataBuffer.TYPE_SHORT:
+            dataBuffer = new DataBufferShort(size, numBanks);
+            break;
+        case DataBuffer.TYPE_INT:
+            dataBuffer = new DataBufferInt(size, numBanks);
+            break;
+        case DataBuffer.TYPE_FLOAT:
+            dataBuffer = new DataBufferFloat(size, numBanks);
+            break;
+        case DataBuffer.TYPE_DOUBLE:
+            dataBuffer = new DataBufferDouble(size, numBanks);
+            break;
+        }
+
+        return dataBuffer;
+    }
+
+
+    /** Gets the offset for the first band of pixel (x,y).
+     *  A sample of the first band can be retrieved from a
+     * <code>DataBuffer</code>
+     *  <code>data</code> with a <code>ComponentSampleModel</code>
+     * <code>csm</code> as
+     * <pre>
+     *        data.getElem(csm.getOffset(x, y));
+     * </pre>
+     * @param x the X location of the pixel
+     * @param y the Y location of the pixel
+     * @return the offset for the first band of the specified pixel.
+     */
+    public int getOffset(int x, int y) {
+        int offset = y*scanlineStride + x*pixelStride + bandOffsets[0];
+        return offset;
+    }
+
+    /** Gets the offset for band b of pixel (x,y).
+     *  A sample of band <code>b</code> can be retrieved from a
+     *  <code>DataBuffer</code> <code>data</code>
+     *  with a <code>ComponentSampleModel</code> <code>csm</code> as
+     * <pre>
+     *       data.getElem(csm.getOffset(x, y, b));
+     * </pre>
+     * @param x the X location of the specified pixel
+     * @param y the Y location of the specified pixel
+     * @param b the specified band
+     * @return the offset for the specified band of the specified pixel.
+     */
+    public int getOffset(int x, int y, int b) {
+        int offset = y*scanlineStride + x*pixelStride + bandOffsets[b];
+        return offset;
+    }
+
+    /** Returns the number of bits per sample for all bands.
+     *  @return an array containing the number of bits per sample
+     *          for all bands, where each element in the array
+     *          represents a band.
+     */
+    public final int[] getSampleSize() {
+        int sampleSize[] = new int [numBands];
+        int sizeInBits = getSampleSize(0);
+
+        for (int i=0; i<numBands; i++)
+            sampleSize[i] = sizeInBits;
+
+        return sampleSize;
+    }
+
+    /** Returns the number of bits per sample for the specified band.
+     *  @param band the specified band
+     *  @return the number of bits per sample for the specified band.
+     */
+    public final int getSampleSize(int band) {
+        return DataBuffer.getDataTypeSize(dataType);
+    }
+
+    /** Returns the bank indices for all bands.
+     *  @return the bank indices for all bands.
+     */
+    public final int [] getBankIndices() {
+        return (int[]) bankIndices.clone();
+    }
+
+    /** Returns the band offset for all bands.
+     *  @return the band offsets for all bands.
+     */
+    public final int [] getBandOffsets() {
+        return (int[])bandOffsets.clone();
+    }
+
+    /** Returns the scanline stride of this ComponentSampleModel.
+     *  @return the scanline stride of this <code>ComponentSampleModel</code>.
+     */
+    public final int getScanlineStride() {
+        return scanlineStride;
+    }
+
+    /** Returns the pixel stride of this ComponentSampleModel.
+     *  @return the pixel stride of this <code>ComponentSampleModel</code>.
+     */
+    public final int getPixelStride() {
+        return pixelStride;
+    }
+
+    /**
+     * Returns the number of data elements needed to transfer a pixel
+     * with the
+     * {@link #getDataElements(int, int, Object, DataBuffer) } and
+     * {@link #setDataElements(int, int, Object, DataBuffer) }
+     * methods.
+     * For a <code>ComponentSampleModel</code>, this is identical to the
+     * number of bands.
+     * @return the number of data elements needed to transfer a pixel with
+     *         the <code>getDataElements</code> and
+     *         <code>setDataElements</code> methods.
+     * @see java.awt.image.SampleModel#getNumDataElements
+     * @see #getNumBands
+     */
+    public final int getNumDataElements() {
+        return getNumBands();
+    }
+
+    /**
+     * Returns data for a single pixel in a primitive array of type
+     * <code>TransferType</code>.  For a <code>ComponentSampleModel</code>,
+     * this is the same as the data type, and samples are returned
+     * one per array element.  Generally, <code>obj</code> should
+     * be passed in as <code>null</code>, so that the <code>Object</code>
+     * is created automatically and is the right primitive data type.
+     * <p>
+     * The following code illustrates transferring data for one pixel from
+     * <code>DataBuffer</code> <code>db1</code>, whose storage layout is
+     * described by <code>ComponentSampleModel</code> <code>csm1</code>,
+     * to <code>DataBuffer</code> <code>db2</code>, whose storage layout
+     * is described by <code>ComponentSampleModel</code> <code>csm2</code>.
+     * The transfer is usually more efficient than using
+     * <code>getPixel</code> and <code>setPixel</code>.
+     * <pre>
+     *       ComponentSampleModel csm1, csm2;
+     *       DataBufferInt db1, db2;
+     *       csm2.setDataElements(x, y,
+     *                            csm1.getDataElements(x, y, null, db1), db2);
+     * </pre>
+     *
+     * Using <code>getDataElements</code> and <code>setDataElements</code>
+     * to transfer between two <code>DataBuffer/SampleModel</code>
+     * pairs is legitimate if the <code>SampleModel</code> objects have
+     * the same number of bands, corresponding bands have the same number of
+     * bits per sample, and the <code>TransferType</code>s are the same.
+     * <p>
+     * If <code>obj</code> is not <code>null</code>, it should be a
+     * primitive array of type <code>TransferType</code>.
+     * Otherwise, a <code>ClassCastException</code> is thrown.  An
+     * <code>ArrayIndexOutOfBoundsException</code> might be thrown if the
+     * coordinates are not in bounds, or if <code>obj</code> is not
+     * <code>null</code> and is not large enough to hold
+     * the pixel data.
+     *
+     * @param x         the X coordinate of the pixel location
+     * @param y         the Y coordinate of the pixel location
+     * @param obj       if non-<code>null</code>, a primitive array
+     *                  in which to return the pixel data
+     * @param data      the <code>DataBuffer</code> containing the image data
+     * @return the data of the specified pixel
+     * @see #setDataElements(int, int, Object, DataBuffer)
+     *
+     * @throws NullPointerException if data is null.
+     * @throws ArrayIndexOutOfBoundsException if the coordinates are
+     * not in bounds, or if obj is too small to hold the ouput.
+     */
+    public Object getDataElements(int x, int y, Object obj, DataBuffer data) {
+        if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+
+        int type = getTransferType();
+        int numDataElems = getNumDataElements();
+        int pixelOffset = y*scanlineStride + x*pixelStride;
+
+        switch(type) {
+
+        case DataBuffer.TYPE_BYTE:
+
+            byte[] bdata;
+
+            if (obj == null)
+                bdata = new byte[numDataElems];
+            else
+                bdata = (byte[])obj;
+
+            for (int i=0; i<numDataElems; i++) {
+                bdata[i] = (byte)data.getElem(bankIndices[i],
+                                              pixelOffset + bandOffsets[i]);
+            }
+
+            obj = (Object)bdata;
+            break;
+
+        case DataBuffer.TYPE_USHORT:
+        case DataBuffer.TYPE_SHORT:
+
+            short[] sdata;
+
+            if (obj == null)
+                sdata = new short[numDataElems];
+            else
+                sdata = (short[])obj;
+
+            for (int i=0; i<numDataElems; i++) {
+                sdata[i] = (short)data.getElem(bankIndices[i],
+                                               pixelOffset + bandOffsets[i]);
+            }
+
+            obj = (Object)sdata;
+            break;
+
+        case DataBuffer.TYPE_INT:
+
+            int[] idata;
+
+            if (obj == null)
+                idata = new int[numDataElems];
+            else
+                idata = (int[])obj;
+
+            for (int i=0; i<numDataElems; i++) {
+                idata[i] = data.getElem(bankIndices[i],
+                                        pixelOffset + bandOffsets[i]);
+            }
+
+            obj = (Object)idata;
+            break;
+
+        case DataBuffer.TYPE_FLOAT:
+
+            float[] fdata;
+
+            if (obj == null)
+                fdata = new float[numDataElems];
+            else
+                fdata = (float[])obj;
+
+            for (int i=0; i<numDataElems; i++) {
+                fdata[i] = data.getElemFloat(bankIndices[i],
+                                             pixelOffset + bandOffsets[i]);
+            }
+
+            obj = (Object)fdata;
+            break;
+
+        case DataBuffer.TYPE_DOUBLE:
+
+            double[] ddata;
+
+            if (obj == null)
+                ddata = new double[numDataElems];
+            else
+                ddata = (double[])obj;
+
+            for (int i=0; i<numDataElems; i++) {
+                ddata[i] = data.getElemDouble(bankIndices[i],
+                                              pixelOffset + bandOffsets[i]);
+            }
+
+            obj = (Object)ddata;
+            break;
+        }
+
+        return obj;
+    }
+
+    /**
+     * Returns all samples for the specified pixel in an int array,
+     * one sample per array element.
+     * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if
+     * the coordinates are not in bounds.
+     * @param x         the X coordinate of the pixel location
+     * @param y         the Y coordinate of the pixel location
+     * @param iArray    If non-null, returns the samples in this array
+     * @param data      The DataBuffer containing the image data
+     * @return the samples of the specified pixel.
+     * @see #setPixel(int, int, int[], DataBuffer)
+     *
+     * @throws NullPointerException if data is null.
+     * @throws ArrayIndexOutOfBoundsException if the coordinates are
+     * not in bounds, or if iArray is too small to hold the output.
+     */
+    public int[] getPixel(int x, int y, int iArray[], DataBuffer data) {
+        if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+        int pixels[];
+        if (iArray != null) {
+           pixels = iArray;
+        } else {
+           pixels = new int [numBands];
+        }
+        int pixelOffset = y*scanlineStride + x*pixelStride;
+        for (int i=0; i<numBands; i++) {
+            pixels[i] = data.getElem(bankIndices[i],
+                                     pixelOffset + bandOffsets[i]);
+        }
+        return pixels;
+    }
+
+    /**
+     * Returns all samples for the specified rectangle of pixels in
+     * an int array, one sample per array element.
+     * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if
+     * the coordinates are not in bounds.
+     * @param x         The X coordinate of the upper left pixel location
+     * @param y         The Y coordinate of the upper left pixel location
+     * @param w         The width of the pixel rectangle
+     * @param h         The height of the pixel rectangle
+     * @param iArray    If non-null, returns the samples in this array
+     * @param data      The DataBuffer containing the image data
+     * @return the samples of the pixels within the specified region.
+     * @see #setPixels(int, int, int, int, int[], DataBuffer)
+     */
+    public int[] getPixels(int x, int y, int w, int h,
+                           int iArray[], DataBuffer data) {
+        if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+        int pixels[];
+        if (iArray != null) {
+           pixels = iArray;
+        } else {
+           pixels = new int [w*h*numBands];
+        }
+        int lineOffset = y*scanlineStride + x*pixelStride;
+        int srcOffset = 0;
+
+        for (int i = 0; i < h; i++) {
+           int pixelOffset = lineOffset;
+           for (int j = 0; j < w; j++) {
+              for (int k=0; k < numBands; k++) {
+                 pixels[srcOffset++] =
+                    data.getElem(bankIndices[k], pixelOffset + bandOffsets[k]);
+              }
+              pixelOffset += pixelStride;
+           }
+           lineOffset += scanlineStride;
+        }
+        return pixels;
+    }
+
+    /**
+     * Returns as int the sample in a specified band for the pixel
+     * located at (x,y).
+     * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if
+     * the coordinates are not in bounds.
+     * @param x         the X coordinate of the pixel location
+     * @param y         the Y coordinate of the pixel location
+     * @param b         the band to return
+     * @param data      the <code>DataBuffer</code> containing the image data
+     * @return the sample in a specified band for the specified pixel
+     * @see #setSample(int, int, int, int, DataBuffer)
+     */
+    public int getSample(int x, int y, int b, DataBuffer data) {
+        // Bounds check for 'b' will be performed automatically
+        if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+        int sample = data.getElem(bankIndices[b],
+                                  y*scanlineStride + x*pixelStride +
+                                  bandOffsets[b]);
+        return sample;
+    }
+
+    /**
+     * Returns the sample in a specified band
+     * for the pixel located at (x,y) as a float.
+     * An <code>ArrayIndexOutOfBoundsException</code> might be
+     * thrown if the coordinates are not in bounds.
+     * @param x         The X coordinate of the pixel location
+     * @param y         The Y coordinate of the pixel location
+     * @param b         The band to return
+     * @param data      The DataBuffer containing the image data
+     * @return a float value representing the sample in the specified
+     * band for the specified pixel.
+     */
+    public float getSampleFloat(int x, int y, int b, DataBuffer data) {
+        // Bounds check for 'b' will be performed automatically
+        if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+
+        float sample = data.getElemFloat(bankIndices[b],
+                                         y*scanlineStride + x*pixelStride +
+                                         bandOffsets[b]);
+        return sample;
+    }
+
+    /**
+     * Returns the sample in a specified band
+     * for a pixel located at (x,y) as a double.
+     * An <code>ArrayIndexOutOfBoundsException</code> might be
+     * thrown if the coordinates are not in bounds.
+     * @param x         The X coordinate of the pixel location
+     * @param y         The Y coordinate of the pixel location
+     * @param b         The band to return
+     * @param data      The DataBuffer containing the image data
+     * @return a double value representing the sample in the specified
+     * band for the specified pixel.
+     */
+    public double getSampleDouble(int x, int y, int b, DataBuffer data) {
+        // Bounds check for 'b' will be performed automatically
+        if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+
+        double sample = data.getElemDouble(bankIndices[b],
+                                           y*scanlineStride + x*pixelStride +
+                                           bandOffsets[b]);
+        return sample;
+    }
+
+    /**
+     * Returns the samples in a specified band for the specified rectangle
+     * of pixels in an int array, one sample per data array element.
+     * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if
+     * the coordinates are not in bounds.
+     * @param x         The X coordinate of the upper left pixel location
+     * @param y         The Y coordinate of the upper left pixel location
+     * @param w         the width of the pixel rectangle
+     * @param h         the height of the pixel rectangle
+     * @param b         the band to return
+     * @param iArray    if non-<code>null</code>, returns the samples
+     *                  in this array
+     * @param data      the <code>DataBuffer</code> containing the image data
+     * @return the samples in the specified band of the specified pixel
+     * @see #setSamples(int, int, int, int, int, int[], DataBuffer)
+     */
+    public int[] getSamples(int x, int y, int w, int h, int b,
+                            int iArray[], DataBuffer data) {
+        // Bounds check for 'b' will be performed automatically
+        if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+        int samples[];
+        if (iArray != null) {
+           samples = iArray;
+        } else {
+           samples = new int [w*h];
+        }
+        int lineOffset = y*scanlineStride + x*pixelStride +  bandOffsets[b];
+        int srcOffset = 0;
+
+        for (int i = 0; i < h; i++) {
+           int sampleOffset = lineOffset;
+           for (int j = 0; j < w; j++) {
+              samples[srcOffset++] = data.getElem(bankIndices[b],
+                                                  sampleOffset);
+              sampleOffset += pixelStride;
+           }
+           lineOffset += scanlineStride;
+        }
+        return samples;
+    }
+
+    /**
+     * Sets the data for a single pixel in the specified
+     * <code>DataBuffer</code> from a primitive array of type
+     * <code>TransferType</code>.  For a <code>ComponentSampleModel</code>,
+     * this is the same as the data type, and samples are transferred
+     * one per array element.
+     * <p>
+     * The following code illustrates transferring data for one pixel from
+     * <code>DataBuffer</code> <code>db1</code>, whose storage layout is
+     * described by <code>ComponentSampleModel</code> <code>csm1</code>,
+     * to <code>DataBuffer</code> <code>db2</code>, whose storage layout
+     * is described by <code>ComponentSampleModel</code> <code>csm2</code>.
+     * The transfer is usually more efficient than using
+     * <code>getPixel</code> and <code>setPixel</code>.
+     * <pre>
+     *       ComponentSampleModel csm1, csm2;
+     *       DataBufferInt db1, db2;
+     *       csm2.setDataElements(x, y, csm1.getDataElements(x, y, null, db1),
+     *                            db2);
+     * </pre>
+     * Using <code>getDataElements</code> and <code>setDataElements</code>
+     * to transfer between two <code>DataBuffer/SampleModel</code> pairs
+     * is legitimate if the <code>SampleModel</code> objects have
+     * the same number of bands, corresponding bands have the same number of
+     * bits per sample, and the <code>TransferType</code>s are the same.
+     * <p>
+     * A <code>ClassCastException</code> is thrown if <code>obj</code> is not
+     * a primitive array of type <code>TransferType</code>.
+     * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if
+     * the coordinates are not in bounds, or if <code>obj</code> is not large
+     * enough to hold the pixel data.
+     * @param x         the X coordinate of the pixel location
+     * @param y         the Y coordinate of the pixel location
+     * @param obj       a primitive array containing pixel data
+     * @param data      the DataBuffer containing the image data
+     * @see #getDataElements(int, int, Object, DataBuffer)
+     */
+    public void setDataElements(int x, int y, Object obj, DataBuffer data) {
+        if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+
+        int type = getTransferType();
+        int numDataElems = getNumDataElements();
+        int pixelOffset = y*scanlineStride + x*pixelStride;
+
+        switch(type) {
+
+        case DataBuffer.TYPE_BYTE:
+
+            byte[] barray = (byte[])obj;
+
+            for (int i=0; i<numDataElems; i++) {
+                data.setElem(bankIndices[i], pixelOffset + bandOffsets[i],
+                           ((int)barray[i])&0xff);
+            }
+            break;
+
+        case DataBuffer.TYPE_USHORT:
+        case DataBuffer.TYPE_SHORT:
+
+            short[] sarray = (short[])obj;
+
+            for (int i=0; i<numDataElems; i++) {
+                data.setElem(bankIndices[i], pixelOffset + bandOffsets[i],
+                           ((int)sarray[i])&0xffff);
+            }
+            break;
+
+        case DataBuffer.TYPE_INT:
+
+            int[] iarray = (int[])obj;
+
+            for (int i=0; i<numDataElems; i++) {
+                data.setElem(bankIndices[i],
+                             pixelOffset + bandOffsets[i], iarray[i]);
+            }
+            break;
+
+        case DataBuffer.TYPE_FLOAT:
+
+            float[] farray = (float[])obj;
+
+            for (int i=0; i<numDataElems; i++) {
+                data.setElemFloat(bankIndices[i],
+                             pixelOffset + bandOffsets[i], farray[i]);
+            }
+            break;
+
+        case DataBuffer.TYPE_DOUBLE:
+
+            double[] darray = (double[])obj;
+
+            for (int i=0; i<numDataElems; i++) {
+                data.setElemDouble(bankIndices[i],
+                             pixelOffset + bandOffsets[i], darray[i]);
+            }
+            break;
+
+        }
+    }
+
+    /**
+     * Sets a pixel in the <code>DataBuffer</code> using an int array of
+     * samples for input.  An <code>ArrayIndexOutOfBoundsException</code>
+     * might be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the pixel location
+     * @param y         The Y coordinate of the pixel location
+     * @param iArray    The input samples in an int array
+     * @param data      The DataBuffer containing the image data
+     * @see #getPixel(int, int, int[], DataBuffer)
+     */
+    public void setPixel(int x, int y, int iArray[], DataBuffer data) {
+        if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+       int pixelOffset = y*scanlineStride + x*pixelStride;
+       for (int i=0; i<numBands; i++) {
+           data.setElem(bankIndices[i],
+                        pixelOffset + bandOffsets[i],iArray[i]);
+       }
+    }
+
+    /**
+     * Sets all samples for a rectangle of pixels from an int array containing
+     * one sample per array element.
+     * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if the
+     * coordinates are not in bounds.
+     * @param x         The X coordinate of the upper left pixel location
+     * @param y         The Y coordinate of the upper left pixel location
+     * @param w         The width of the pixel rectangle
+     * @param h         The height of the pixel rectangle
+     * @param iArray    The input samples in an int array
+     * @param data      The DataBuffer containing the image data
+     * @see #getPixels(int, int, int, int, int[], DataBuffer)
+     */
+    public void setPixels(int x, int y, int w, int h,
+                          int iArray[], DataBuffer data) {
+        if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+
+        int lineOffset = y*scanlineStride + x*pixelStride;
+        int srcOffset = 0;
+
+        for (int i = 0; i < h; i++) {
+           int pixelOffset = lineOffset;
+           for (int j = 0; j < w; j++) {
+              for (int k=0; k < numBands; k++) {
+                 data.setElem(bankIndices[k], pixelOffset + bandOffsets[k],
+                              iArray[srcOffset++]);
+              }
+              pixelOffset += pixelStride;
+           }
+           lineOffset += scanlineStride;
+        }
+    }
+
+    /**
+     * Sets a sample in the specified band for the pixel located at (x,y)
+     * in the <code>DataBuffer</code> using an int for input.
+     * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if the
+     * coordinates are not in bounds.
+     * @param x         The X coordinate of the pixel location
+     * @param y         The Y coordinate of the pixel location
+     * @param b         the band to set
+     * @param s         the input sample as an int
+     * @param data      the DataBuffer containing the image data
+     * @see #getSample(int, int, int, DataBuffer)
+     */
+    public void setSample(int x, int y, int b, int s,
+                          DataBuffer data) {
+        // Bounds check for 'b' will be performed automatically
+        if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+        data.setElem(bankIndices[b],
+                     y*scanlineStride + x*pixelStride + bandOffsets[b], s);
+    }
+
+    /**
+     * Sets a sample in the specified band for the pixel located at (x,y)
+     * in the <code>DataBuffer</code> using a float for input.
+     * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if
+     * the coordinates are not in bounds.
+     * @param x         The X coordinate of the pixel location
+     * @param y         The Y coordinate of the pixel location
+     * @param b         The band to set
+     * @param s         The input sample as a float
+     * @param data      The DataBuffer containing the image data
+     * @see #getSample(int, int, int, DataBuffer)
+     */
+    public void setSample(int x, int y, int b,
+                          float s ,
+                          DataBuffer data) {
+        // Bounds check for 'b' will be performed automatically
+        if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+        data.setElemFloat(bankIndices[b],
+                          y*scanlineStride + x*pixelStride + bandOffsets[b],
+                          s);
+    }
+
+    /**
+     * Sets a sample in the specified band for the pixel located at (x,y)
+     * in the <code>DataBuffer</code> using a double for input.
+     * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if
+     * the coordinates are not in bounds.
+     * @param x         The X coordinate of the pixel location
+     * @param y         The Y coordinate of the pixel location
+     * @param b         The band to set
+     * @param s         The input sample as a double
+     * @param data      The DataBuffer containing the image data
+     * @see #getSample(int, int, int, DataBuffer)
+     */
+    public void setSample(int x, int y, int b,
+                          double s,
+                          DataBuffer data) {
+        // Bounds check for 'b' will be performed automatically
+        if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+        data.setElemDouble(bankIndices[b],
+                          y*scanlineStride + x*pixelStride + bandOffsets[b],
+                          s);
+    }
+
+    /**
+     * Sets the samples in the specified band for the specified rectangle
+     * of pixels from an int array containing one sample per data array element.
+     * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if the
+     * coordinates are not in bounds.
+     * @param x         The X coordinate of the upper left pixel location
+     * @param y         The Y coordinate of the upper left pixel location
+     * @param w         The width of the pixel rectangle
+     * @param h         The height of the pixel rectangle
+     * @param b         The band to set
+     * @param iArray    The input samples in an int array
+     * @param data      The DataBuffer containing the image data
+     * @see #getSamples(int, int, int, int, int, int[], DataBuffer)
+     */
+    public void setSamples(int x, int y, int w, int h, int b,
+                           int iArray[], DataBuffer data) {
+        // Bounds check for 'b' will be performed automatically
+        if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+        int lineOffset = y*scanlineStride + x*pixelStride + bandOffsets[b];
+        int srcOffset = 0;
+
+        for (int i = 0; i < h; i++) {
+           int sampleOffset = lineOffset;
+           for (int j = 0; j < w; j++) {
+              data.setElem(bankIndices[b], sampleOffset, iArray[srcOffset++]);
+              sampleOffset += pixelStride;
+           }
+           lineOffset += scanlineStride;
+        }
+    }
+
+    public boolean equals(Object o) {
+        if ((o == null) || !(o instanceof ComponentSampleModel)) {
+            return false;
+        }
+
+        ComponentSampleModel that = (ComponentSampleModel)o;
+        return this.width == that.width &&
+            this.height == that.height &&
+            this.numBands == that.numBands &&
+            this.dataType == that.dataType &&
+            Arrays.equals(this.bandOffsets, that.bandOffsets) &&
+            Arrays.equals(this.bankIndices, that.bankIndices) &&
+            this.numBands == that.numBands &&
+            this.numBanks == that.numBanks &&
+            this.scanlineStride == that.scanlineStride &&
+            this.pixelStride == that.pixelStride;
+    }
+
+    // If we implement equals() we must also implement hashCode
+    public int hashCode() {
+        int hash = 0;
+        hash = width;
+        hash <<= 8;
+        hash ^= height;
+        hash <<= 8;
+        hash ^= numBands;
+        hash <<= 8;
+        hash ^= dataType;
+        hash <<= 8;
+        for (int i = 0; i < bandOffsets.length; i++) {
+            hash ^= bandOffsets[i];
+            hash <<= 8;
+        }
+        for (int i = 0; i < bankIndices.length; i++) {
+            hash ^= bankIndices[i];
+            hash <<= 8;
+        }
+        hash ^= numBands;
+        hash <<= 8;
+        hash ^= numBanks;
+        hash <<= 8;
+        hash ^= scanlineStride;
+        hash <<= 8;
+        hash ^= pixelStride;
+        return hash;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/awt/image/DataBuffer.java	Thu Apr 10 16:28:45 2008 -0700
@@ -0,0 +1,535 @@
+/*
+ * Portions Copyright 1997-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* ****************************************************************
+ ******************************************************************
+ ******************************************************************
+ *** COPYRIGHT (c) Eastman Kodak Company, 1997
+ *** As  an unpublished  work pursuant to Title 17 of the United
+ *** States Code.  All rights reserved.
+ ******************************************************************
+ ******************************************************************
+ ******************************************************************/
+
+package java.awt.image;
+
+import sun.java2d.StateTrackable.State;
+import static sun.java2d.StateTrackable.State.*;
+import sun.java2d.StateTrackableDelegate;
+
+import sun.awt.image.SunWritableRaster;
+
+/**
+ * This class exists to wrap one or more data arrays.  Each data array in
+ * the DataBuffer is referred to as a bank.  Accessor methods for getting
+ * and setting elements of the DataBuffer's banks exist with and without
+ * a bank specifier.  The methods without a bank specifier use the default 0th
+ * bank.  The DataBuffer can optionally take an offset per bank, so that
+ * data in an existing array can be used even if the interesting data
+ * doesn't start at array location zero.  Getting or setting the 0th
+ * element of a bank, uses the (0+offset)th element of the array.  The
+ * size field specifies how much of the data array is available for
+ * use.  Size + offset for a given bank should never be greater
+ * than the length of the associated data array.  The data type of
+ * a data buffer indicates the type of the data array(s) and may also
+ * indicate additional semantics, e.g. storing unsigned 8-bit data
+ * in elements of a byte array.  The data type may be TYPE_UNDEFINED
+ * or one of the types defined below.  Other types may be added in
+ * the future.  Generally, an object of class DataBuffer will be cast down
+ * to one of its data type specific subclasses to access data type specific
+ * methods for improved performance.  Currently, the Java 2D(tm) API
+ * image classes use TYPE_BYTE, TYPE_USHORT, TYPE_INT, TYPE_SHORT,
+ * TYPE_FLOAT, and TYPE_DOUBLE DataBuffers to store image data.
+ * @see java.awt.image.Raster
+ * @see java.awt.image.SampleModel
+ */
+public abstract class DataBuffer {
+
+    /** Tag for unsigned byte data. */
+    public static final int TYPE_BYTE  = 0;
+
+    /** Tag for unsigned short data. */
+    public static final int TYPE_USHORT = 1;
+
+    /** Tag for signed short data.  Placeholder for future use. */
+    public static final int TYPE_SHORT = 2;
+
+    /** Tag for int data. */
+    public static final int TYPE_INT   = 3;
+
+    /** Tag for float data.  Placeholder for future use. */
+    public static final int TYPE_FLOAT  = 4;
+
+    /** Tag for double data.  Placeholder for future use. */
+    public static final int TYPE_DOUBLE  = 5;
+
+    /** Tag for undefined data. */
+    public static final int TYPE_UNDEFINED = 32;
+
+    /** The data type of this DataBuffer. */
+    protected int dataType;
+
+    /** The number of banks in this DataBuffer. */
+    protected int banks;
+
+    /** Offset into default (first) bank from which to get the first element. */
+    protected int offset;
+
+    /** Usable size of all banks. */
+    protected int size;
+
+    /** Offsets into all banks. */
+    protected int offsets[];
+
+    /* The current StateTrackable state. */
+    StateTrackableDelegate theTrackable;
+
+    /** Size of the data types indexed by DataType tags defined above. */
+    private static final int dataTypeSize[] = {8,16,16,32,32,64};
+
+    /** Returns the size (in bits) of the data type, given a datatype tag.
+      * @param type the value of one of the defined datatype tags
+      * @return the size of the data type
+      * @throws IllegalArgumentException if <code>type</code> is less than
+      *         zero or greater than {@link #TYPE_DOUBLE}
+      */
+    public static int getDataTypeSize(int type) {
+        if (type < TYPE_BYTE || type > TYPE_DOUBLE) {
+            throw new IllegalArgumentException("Unknown data type "+type);
+        }
+        return dataTypeSize[type];
+    }
+
+    /**
+     *  Constructs a DataBuffer containing one bank of the specified
+     *  data type and size.
+     *
+     *  @param dataType the data type of this <code>DataBuffer</code>
+     *  @param size the size of the banks
+     */
+    protected DataBuffer(int dataType, int size) {
+        this(UNTRACKABLE, dataType, size);
+    }
+
+    /**
+     *  Constructs a DataBuffer containing one bank of the specified
+     *  data type and size with the indicated initial {@link State State}.
+     *
+     *  @param initialState the initial {@link State State} state of the data
+     *  @param dataType the data type of this <code>DataBuffer</code>
+     *  @param size the size of the banks
+     *  @since 1.7
+     */
+    DataBuffer(State initialState,
+               int dataType, int size)
+    {
+        this.theTrackable = StateTrackableDelegate.createInstance(initialState);
+        this.dataType = dataType;
+        this.banks = 1;
+        this.size = size;
+        this.offset = 0;
+        this.offsets = new int[1];  // init to 0 by new
+    }
+
+    /**
+     *  Constructs a DataBuffer containing the specified number of
+     *  banks.  Each bank has the specified size and an offset of 0.
+     *
+     *  @param dataType the data type of this <code>DataBuffer</code>
+     *  @param size the size of the banks
+     *  @param numBanks the number of banks in this
+     *         <code>DataBuffer</code>
+     */
+    protected DataBuffer(int dataType, int size, int numBanks) {
+        this(UNTRACKABLE, dataType, size, numBanks);
+    }
+
+    /**
+     *  Constructs a DataBuffer containing the specified number of
+     *  banks with the indicated initial {@link State State}.
+     *  Each bank has the specified size and an offset of 0.
+     *
+     *  @param initialState the initial {@link State State} state of the data
+     *  @param dataType the data type of this <code>DataBuffer</code>
+     *  @param size the size of the banks
+     *  @param numBanks the number of banks in this
+     *         <code>DataBuffer</code>
+     *  @since 1.7
+     */
+    DataBuffer(State initialState,
+               int dataType, int size, int numBanks)
+    {
+        this.theTrackable = StateTrackableDelegate.createInstance(initialState);
+        this.dataType = dataType;
+        this.banks = numBanks;
+        this.size = size;
+        this.offset = 0;
+        this.offsets = new int[banks]; // init to 0 by new
+    }
+
+    /**
+     *  Constructs a DataBuffer that contains the specified number
+     *  of banks.  Each bank has the specified datatype, size and offset.
+     *
+     *  @param dataType the data type of this <code>DataBuffer</code>
+     *  @param size the size of the banks
+     *  @param numBanks the number of banks in this
+     *         <code>DataBuffer</code>
+     *  @param offset the offset for each bank
+     */
+    protected DataBuffer(int dataType, int size, int numBanks, int offset) {
+        this(UNTRACKABLE, dataType, size, numBanks, offset);
+    }
+
+    /**
+     *  Constructs a DataBuffer that contains the specified number
+     *  of banks with the indicated initial {@link State State}.
+     *  Each bank has the specified datatype, size and offset.
+     *
+     *  @param initialState the initial {@link State State} state of the data
+     *  @param dataType the data type of this <code>DataBuffer</code>
+     *  @param size the size of the banks
+     *  @param numBanks the number of banks in this
+     *         <code>DataBuffer</code>
+     *  @param offset the offset for each bank
+     *  @since 1.7
+     */
+    DataBuffer(State initialState,
+               int dataType, int size, int numBanks, int offset)
+    {
+        this.theTrackable = StateTrackableDelegate.createInstance(initialState);
+        this.dataType = dataType;
+        this.banks = numBanks;
+        this.size = size;
+        this.offset = offset;
+        this.offsets = new int[numBanks];
+        for (int i = 0; i < numBanks; i++) {
+            this.offsets[i] = offset;
+        }
+    }
+
+    /**
+     *  Constructs a DataBuffer which contains the specified number
+     *  of banks.  Each bank has the specified datatype and size.  The
+     *  offset for each bank is specified by its respective entry in
+     *  the offsets array.
+     *
+     *  @param dataType the data type of this <code>DataBuffer</code>
+     *  @param size the size of the banks
+     *  @param numBanks the number of banks in this
+     *         <code>DataBuffer</code>
+     *  @param offsets an array containing an offset for each bank.
+     *  @throws ArrayIndexOutOfBoundsException if <code>numBanks</code>
+     *          does not equal the length of <code>offsets</code>
+     */
+    protected DataBuffer(int dataType, int size, int numBanks, int offsets[]) {
+        this(UNTRACKABLE, dataType, size, numBanks, offsets);
+    }
+
+    /**
+     *  Constructs a DataBuffer which contains the specified number
+     *  of banks with the indicated initial {@link State State}.
+     *  Each bank has the specified datatype and size.  The
+     *  offset for each bank is specified by its respective entry in
+     *  the offsets array.
+     *
+     *  @param initialState the initial {@link State State} state of the data
+     *  @param dataType the data type of this <code>DataBuffer</code>
+     *  @param size the size of the banks
+     *  @param numBanks the number of banks in this
+     *         <code>DataBuffer</code>
+     *  @param offsets an array containing an offset for each bank.
+     *  @throws ArrayIndexOutOfBoundsException if <code>numBanks</code>
+     *          does not equal the length of <code>offsets</code>
+     *  @since 1.7
+     */
+    DataBuffer(State initialState,
+               int dataType, int size, int numBanks, int offsets[])
+    {
+        if (numBanks != offsets.length) {
+            throw new ArrayIndexOutOfBoundsException("Number of banks" +
+                 " does not match number of bank offsets");
+        }
+        this.theTrackable = StateTrackableDelegate.createInstance(initialState);
+        this.dataType = dataType;
+        this.banks = numBanks;
+        this.size = size;
+        this.offset = offsets[0];
+        this.offsets = (int[])offsets.clone();
+    }
+
+    /**  Returns the data type of this DataBuffer.
+     *   @return the data type of this <code>DataBuffer</code>.
+     */
+    public int getDataType() {
+        return dataType;
+    }
+
+    /**  Returns the size (in array elements) of all banks.
+     *   @return the size of all banks.
+     */
+    public int getSize() {
+        return size;
+    }
+
+    /** Returns the offset of the default bank in array elements.
+     *  @return the offset of the default bank.
+     */
+    public int getOffset() {
+        return offset;
+    }
+
+    /** Returns the offsets (in array elements) of all the banks.
+     *  @return the offsets of all banks.
+     */
+    public int[] getOffsets() {
+        return (int[])offsets.clone();
+    }
+
+    /** Returns the number of banks in this DataBuffer.
+     *  @return the number of banks.
+     */
+    public int getNumBanks() {
+        return banks;
+    }
+
+    /**
+     * Returns the requested data array element from the first (default) bank
+     * as an integer.
+     * @param i the index of the requested data array element
+     * @return the data array element at the specified index.
+     * @see #setElem(int, int)
+     * @see #setElem(int, int, int)
+     */
+    public int getElem(int i) {
+        return getElem(0,i);
+    }
+
+    /**
+     * Returns the requested data array element from the specified bank
+     * as an integer.
+     * @param bank the specified bank
+     * @param i the index of the requested data array element
+     * @return the data array element at the specified index from the
+     *         specified bank at the specified index.
+     * @see #setElem(int, int)
+     * @see #setElem(int, int, int)
+     */
+    public abstract int getElem(int bank, int i);
+
+    /**
+     * Sets the requested data array element in the first (default) bank
+     * from the given integer.
+     * @param i the specified index into the data array
+     * @param val the data to set the element at the specified index in
+     * the data array
+     * @see #getElem(int)
+     * @see #getElem(int, int)
+     */
+    public void  setElem(int i, int val) {
+        setElem(0,i,val);
+    }
+
+    /**
+     * Sets the requested data array element in the specified bank
+     * from the given integer.
+     * @param bank the specified bank
+     * @param i the specified index into the data array
+     * @param val  the data to set the element in the specified bank
+     * at the specified index in the data array
+     * @see #getElem(int)
+     * @see #getElem(int, int)
+     */
+    public abstract void setElem(int bank, int i, int val);
+
+    /**
+     * Returns the requested data array element from the first (default) bank
+     * as a float.  The implementation in this class is to cast getElem(i)
+     * to a float.  Subclasses may override this method if another
+     * implementation is needed.
+     * @param i the index of the requested data array element
+     * @return a float value representing the data array element at the
+     *  specified index.
+     * @see #setElemFloat(int, float)
+     * @see #setElemFloat(int, int, float)
+     */
+    public float getElemFloat(int i) {
+        return (float)getElem(i);
+    }
+
+    /**
+     * Returns the requested data array element from the specified bank
+     * as a float.  The implementation in this class is to cast
+     * {@link #getElem(int, int)}
+     * to a float.  Subclasses can override this method if another
+     * implementation is needed.
+     * @param bank the specified bank
+     * @param i the index of the requested data array element
+     * @return a float value representing the data array element from the
+     * specified bank at the specified index.
+     * @see #setElemFloat(int, float)
+     * @see #setElemFloat(int, int, float)
+     */
+    public float getElemFloat(int bank, int i) {
+        return (float)getElem(bank,i);
+    }
+
+    /**
+     * Sets the requested data array element in the first (default) bank
+     * from the given float.  The implementation in this class is to cast
+     * val to an int and call {@link #setElem(int, int)}.  Subclasses
+     * can override this method if another implementation is needed.
+     * @param i the specified index
+     * @param val the value to set the element at the specified index in
+     * the data array
+     * @see #getElemFloat(int)
+     * @see #getElemFloat(int, int)
+     */
+    public void setElemFloat(int i, float val) {
+        setElem(i,(int)val);
+    }
+
+    /**
+     * Sets the requested data array element in the specified bank
+     * from the given float.  The implementation in this class is to cast
+     * val to an int and call {@link #setElem(int, int)}.  Subclasses can
+     * override this method if another implementation is needed.
+     * @param bank the specified bank
+     * @param i the specified index
+     * @param val the value to set the element in the specified bank at
+     * the specified index in the data array
+     * @see #getElemFloat(int)
+     * @see #getElemFloat(int, int)
+     */
+    public void setElemFloat(int bank, int i, float val) {
+        setElem(bank,i,(int)val);
+    }
+
+    /**
+     * Returns the requested data array element from the first (default) bank
+     * as a double.  The implementation in this class is to cast
+     * {@link #getElem(int)}
+     * to a double.  Subclasses can override this method if another
+     * implementation is needed.
+     * @param i the specified index
+     * @return a double value representing the element at the specified
+     * index in the data array.
+     * @see #setElemDouble(int, double)
+     * @see #setElemDouble(int, int, double)
+     */
+    public double getElemDouble(int i) {
+        return (double)getElem(i);
+    }
+
+    /**
+     * Returns the requested data array element from the specified bank as
+     * a double.  The implementation in this class is to cast getElem(bank, i)
+     * to a double.  Subclasses may override this method if another
+     * implementation is needed.
+     * @param bank the specified bank
+     * @param i the specified index
+     * @return a double value representing the element from the specified
+     * bank at the specified index in the data array.
+     * @see #setElemDouble(int, double)
+     * @see #setElemDouble(int, int, double)
+     */
+    public double getElemDouble(int bank, int i) {
+        return (double)getElem(bank,i);
+    }
+
+    /**
+     * Sets the requested data array element in the first (default) bank
+     * from the given double.  The implementation in this class is to cast
+     * val to an int and call {@link #setElem(int, int)}.  Subclasses can
+     * override this method if another implementation is needed.
+     * @param i the specified index
+     * @param val the value to set the element at the specified index
+     * in the data array
+     * @see #getElemDouble(int)
+     * @see #getElemDouble(int, int)
+     */
+    public void setElemDouble(int i, double val) {
+        setElem(i,(int)val);
+    }
+
+    /**
+     * Sets the requested data array element in the specified bank
+     * from the given double.  The implementation in this class is to cast
+     * val to an int and call {@link #setElem(int, int)}.  Subclasses can
+     * override this method if another implementation is needed.
+     * @param bank the specified bank
+     * @param i the specified index
+     * @param val the value to set the element in the specified bank
+     * at the specified index of the data array
+     * @see #getElemDouble(int)
+     * @see #getElemDouble(int, int)
+     */
+    public void setElemDouble(int bank, int i, double val) {
+        setElem(bank,i,(int)val);
+    }
+
+    static int[] toIntArray(Object obj) {
+        if (obj instanceof int[]) {
+            return (int[])obj;
+        } else if (obj == null) {
+            return null;
+        } else if (obj instanceof short[]) {
+            short sdata[] = (short[])obj;
+            int idata[] = new int[sdata.length];
+            for (int i = 0; i < sdata.length; i++) {
+                idata[i] = (int)sdata[i] & 0xffff;
+            }
+            return idata;
+        } else if (obj instanceof byte[]) {
+            byte bdata[] = (byte[])obj;
+            int idata[] = new int[bdata.length];
+            for (int i = 0; i < bdata.length; i++) {
+                idata[i] = 0xff & (int)bdata[i];
+            }
+            return idata;
+        }
+        return null;
+    }
+
+    static {
+        SunWritableRaster.setDataStealer(new SunWritableRaster.DataStealer() {
+            public byte[] getData(DataBufferByte dbb, int bank) {
+                return dbb.bankdata[bank];
+            }
+
+            public short[] getData(DataBufferUShort dbus, int bank) {
+                return dbus.bankdata[bank];
+            }
+
+            public int[] getData(DataBufferInt dbi, int bank) {
+                return dbi.bankdata[bank];
+            }
+
+            public StateTrackableDelegate getTrackable(DataBuffer db) {
+                return db.theTrackable;
+            }
+        });
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/awt/image/DataBufferByte.java	Thu Apr 10 16:28:45 2008 -0700
@@ -0,0 +1,286 @@
+/*
+ * Portions Copyright 1997-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* ****************************************************************
+ ******************************************************************
+ ******************************************************************
+ *** COPYRIGHT (c) Eastman Kodak Company, 1997
+ *** As  an unpublished  work pursuant to Title 17 of the United
+ *** States Code.  All rights reserved.
+ ******************************************************************
+ ******************************************************************
+ ******************************************************************/
+
+package java.awt.image;
+
+import static sun.java2d.StateTrackable.State.*;
+
+/**
+ * This class extends <CODE>DataBuffer</CODE> and stores data internally as bytes.
+ * Values stored in the byte array(s) of this <CODE>DataBuffer</CODE> are treated as
+ * unsigned values.
+ * <p>
+ * <a name="optimizations">
+ * Note that some implementations may function more efficiently
+ * if they can maintain control over how the data for an image is
+ * stored.
+ * For example, optimizations such as caching an image in video
+ * memory require that the implementation track all modifications
+ * to that data.
+ * Other implementations may operate better if they can store the
+ * data in locations other than a Java array.
+ * To maintain optimum compatibility with various optimizations
+ * it is best to avoid constructors and methods which expose the
+ * underlying storage as a Java array, as noted below in the
+ * documentation for those methods.
+ * </a>
+ */
+public final class DataBufferByte extends DataBuffer
+{
+    /** The default data bank. */
+    byte data[];
+
+    /** All data banks */
+    byte bankdata[][];
+
+    /**
+     * Constructs a byte-based <CODE>DataBuffer</CODE> with a single bank and the
+     * specified size.
+     *
+     * @param size The size of the <CODE>DataBuffer</CODE>.
+     */
+    public DataBufferByte(int size) {
+      super(STABLE, TYPE_BYTE, size);
+      data = new byte[size];
+      bankdata = new byte[1][];
+      bankdata[0] = data;
+    }
+
+    /**
+     * Constructs a byte based <CODE>DataBuffer</CODE> with the specified number of
+     * banks all of which are the specified size.
+     *
+     * @param size The size of the banks in the <CODE>DataBuffer</CODE>.
+     * @param numBanks The number of banks in the a<CODE>DataBuffer</CODE>.
+     */
+    public DataBufferByte(int size, int numBanks) {
+        super(STABLE, TYPE_BYTE, size, numBanks);
+        bankdata = new byte[numBanks][];
+        for (int i= 0; i < numBanks; i++) {
+            bankdata[i] = new byte[size];
+        }
+        data = bankdata[0];
+    }
+
+    /**
+     * Constructs a byte-based <CODE>DataBuffer</CODE> with a single bank using the
+     * specified array.
+     * Only the first <CODE>size</CODE> elements should be used by accessors of
+     * this <CODE>DataBuffer</CODE>.  <CODE>dataArray</CODE> must be large enough to
+     * hold <CODE>size</CODE> elements.
+     * <p>
+     * Note that {@code DataBuffer} objects created by this constructor
+     * may be incompatible with <a href="#optimizations">performance
+     * optimizations</a> used by some implementations (such as caching
+     * an associated image in video memory).
+     *
+     * @param dataArray The byte array for the <CODE>DataBuffer</CODE>.
+     * @param size The size of the <CODE>DataBuffer</CODE> bank.
+     */
+    public DataBufferByte(byte dataArray[], int size) {
+        super(UNTRACKABLE, TYPE_BYTE, size);
+        data = dataArray;
+        bankdata = new byte[1][];
+        bankdata[0] = data;
+    }
+
+    /**
+     * Constructs a byte-based <CODE>DataBuffer</CODE> with a single bank using the
+     * specified array, size, and offset.  <CODE>dataArray</CODE> must have at least
+     * <CODE>offset</CODE> + <CODE>size</CODE> elements.  Only elements <CODE>offset</CODE>
+     * through <CODE>offset</CODE> + <CODE>size</CODE> - 1
+     * should be used by accessors of this <CODE>DataBuffer</CODE>.
+     * <p>
+     * Note that {@code DataBuffer} objects created by this constructor
+     * may be incompatible with <a href="#optimizations">performance
+     * optimizations</a> used by some implementations (such as caching
+     * an associated image in video memory).
+     *
+     * @param dataArray The byte array for the <CODE>DataBuffer</CODE>.
+     * @param size The size of the <CODE>DataBuffer</CODE> bank.
+     * @param offset The offset into the <CODE>dataArray</CODE>. <CODE>dataArray</CODE>
+     * must have at least <CODE>offset</CODE> + <CODE>size</CODE> elements.
+     */
+    public DataBufferByte(byte dataArray[], int size, int offset){
+        super(UNTRACKABLE, TYPE_BYTE, size, 1, offset);
+        data = dataArray;
+        bankdata = new byte[1][];
+        bankdata[0] = data;
+    }
+
+    /**
+     * Constructs a byte-based <CODE>DataBuffer</CODE> with the specified arrays.
+     * The number of banks is equal to <CODE>dataArray.length</CODE>.
+     * Only the first <CODE>size</CODE> elements of each array should be used by
+     * accessors of this <CODE>DataBuffer</CODE>.
+     * <p>
+     * Note that {@code DataBuffer} objects created by this constructor
+     * may be incompatible with <a href="#optimizations">performance
+     * optimizations</a> used by some implementations (such as caching
+     * an associated image in video memory).
+     *
+     * @param dataArray The byte arrays for the <CODE>DataBuffer</CODE>.
+     * @param size The size of the banks in the <CODE>DataBuffer</CODE>.
+     */
+    public DataBufferByte(byte dataArray[][], int size) {
+        super(UNTRACKABLE, TYPE_BYTE, size, dataArray.length);
+        bankdata = (byte[][]) dataArray.clone();
+        data = bankdata[0];
+    }
+
+    /**
+     * Constructs a byte-based <CODE>DataBuffer</CODE> with the specified arrays, size,
+     * and offsets.
+     * The number of banks is equal to <CODE>dataArray.length</CODE>.  Each array must
+     * be at least as large as <CODE>size</CODE> + the corresponding <CODE>offset</CODE>.
+     * There must be an entry in the <CODE>offset</CODE> array for each <CODE>dataArray</CODE>
+     * entry.  For each bank, only elements <CODE>offset</CODE> through
+     * <CODE>offset</CODE> + <CODE>size</CODE> - 1 should be used by accessors of this
+     * <CODE>DataBuffer</CODE>.
+     * <p>
+     * Note that {@code DataBuffer} objects created by this constructor
+     * may be incompatible with <a href="#optimizations">performance
+     * optimizations</a> used by some implementations (such as caching
+     * an associated image in video memory).
+     *
+     * @param dataArray The byte arrays for the <CODE>DataBuffer</CODE>.
+     * @param size The size of the banks in the <CODE>DataBuffer</CODE>.
+     * @param offsets The offsets into each array.
+     */
+    public DataBufferByte(byte dataArray[][], int size, int offsets[]) {
+        super(UNTRACKABLE, TYPE_BYTE, size, dataArray.length, offsets);
+        bankdata = (byte[][]) dataArray.clone();
+        data = bankdata[0];
+    }
+
+    /**
+     * Returns the default (first) byte data array.
+     * <p>
+     * Note that calling this method may cause this {@code DataBuffer}
+     * object to be incompatible with <a href="#optimizations">performance
+     * optimizations</a> used by some implementations (such as caching
+     * an associated image in video memory).
+     *
+     * @return The first byte data array.
+     */
+    public byte[] getData() {
+        theTrackable.setUntrackable();
+        return data;
+    }
+
+    /**
+     * Returns the data array for the specified bank.
+     * <p>
+     * Note that calling this method may cause this {@code DataBuffer}
+     * object to be incompatible with <a href="#optimizations">performance
+     * optimizations</a> used by some implementations (such as caching
+     * an associated image in video memory).
+     *
+     * @param bank The bank whose data array you want to get.
+     * @return The data array for the specified bank.
+     */
+    public byte[] getData(int bank) {
+        theTrackable.setUntrackable();
+        return bankdata[bank];
+    }
+
+    /**
+     * Returns the data arrays for all banks.
+     * <p>
+     * Note that calling this method may cause this {@code DataBuffer}
+     * object to be incompatible with <a href="#optimizations">performance
+     * optimizations</a> used by some implementations (such as caching
+     * an associated image in video memory).
+     *
+     * @return All of the data arrays.
+     */
+    public byte[][] getBankData() {
+        theTrackable.setUntrackable();
+        return (byte[][]) bankdata.clone();
+    }
+
+    /**
+     * Returns the requested data array element from the first (default) bank.
+     *
+     * @param i The data array element you want to get.
+     * @return The requested data array element as an integer.
+     * @see #setElem(int, int)
+     * @see #setElem(int, int, int)
+     */
+    public int getElem(int i) {
+        return (int)(data[i+offset]) & 0xff;
+    }
+
+    /**
+     * Returns the requested data array element from the specified bank.
+     *
+     * @param bank The bank from which you want to get a data array element.
+     * @param i The data array element you want to get.
+     * @return The requested data array element as an integer.
+     * @see #setElem(int, int)
+     * @see #setElem(int, int, int)
+     */
+    public int getElem(int bank, int i) {
+        return (int)(bankdata[bank][i+offsets[bank]]) & 0xff;
+    }
+
+    /**
+     * Sets the requested data array element in the first (default) bank
+     * to the specified value.
+     *
+     * @param i The data array element you want to set.
+     * @param val The integer value to which you want to set the data array element.
+     * @see #getElem(int)
+     * @see #getElem(int, int)
+     */
+    public void setElem(int i, int val) {
+        data[i+offset] = (byte)val;
+        theTrackable.markDirty();
+    }
+
+    /**
+     * Sets the requested data array element in the specified bank
+     * from the given integer.
+     * @param bank The bank in which you want to set the data array element.
+     * @param i The data array element you want to set.
+     * @param val The integer value to which you want to set the specified data array element.
+     * @see #getElem(int)
+     * @see #getElem(int, int)
+     */
+    public void setElem(int bank, int i, int val) {
+        bankdata[bank][i+offsets[bank]] = (byte)val;
+        theTrackable.markDirty();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/awt/image/DataBufferInt.java	Thu Apr 10 16:28:45 2008 -0700
@@ -0,0 +1,284 @@
+/*
+ * Portions Copyright 1997-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* ****************************************************************
+ ******************************************************************
+ ******************************************************************
+ *** COPYRIGHT (c) Eastman Kodak Company, 1997
+ *** As  an unpublished  work pursuant to Title 17 of the United
+ *** States Code.  All rights reserved.
+ ******************************************************************
+ ******************************************************************
+ ******************************************************************/
+
+package java.awt.image;
+
+import static sun.java2d.StateTrackable.State.*;
+
+/**
+ * This class extends <CODE>DataBuffer</CODE> and stores data internally
+ * as integers.
+ * <p>
+ * <a name="optimizations">
+ * Note that some implementations may function more efficiently
+ * if they can maintain control over how the data for an image is
+ * stored.
+ * For example, optimizations such as caching an image in video
+ * memory require that the implementation track all modifications
+ * to that data.
+ * Other implementations may operate better if they can store the
+ * data in locations other than a Java array.
+ * To maintain optimum compatibility with various optimizations
+ * it is best to avoid constructors and methods which expose the
+ * underlying storage as a Java array as noted below in the
+ * documentation for those methods.
+ * </a>
+ */
+public final class DataBufferInt extends DataBuffer
+{
+    /** The default data bank. */
+    int data[];
+
+    /** All data banks */
+    int bankdata[][];
+
+    /**
+     * Constructs an integer-based <CODE>DataBuffer</CODE> with a single bank
+     * and the specified size.
+     *
+     * @param size The size of the <CODE>DataBuffer</CODE>.
+     */
+    public DataBufferInt(int size) {
+        super(STABLE, TYPE_INT, size);
+        data = new int[size];
+        bankdata = new int[1][];
+        bankdata[0] = data;
+    }
+
+    /**
+     * Constructs an integer-based <CODE>DataBuffer</CODE> with the specified number of
+     * banks, all of which are the specified size.
+     *
+     * @param size The size of the banks in the <CODE>DataBuffer</CODE>.
+     * @param numBanks The number of banks in the a<CODE>DataBuffer</CODE>.
+     */
+    public DataBufferInt(int size, int numBanks) {
+        super(STABLE, TYPE_INT, size, numBanks);
+        bankdata = new int[numBanks][];
+        for (int i= 0; i < numBanks; i++) {
+            bankdata[i] = new int[size];
+        }
+        data = bankdata[0];
+    }
+
+    /**
+     * Constructs an integer-based <CODE>DataBuffer</CODE> with a single bank using the
+     * specified array.
+     * Only the first <CODE>size</CODE> elements should be used by accessors of
+     * this <CODE>DataBuffer</CODE>.  <CODE>dataArray</CODE> must be large enough to
+     * hold <CODE>size</CODE> elements.
+     * <p>
+     * Note that {@code DataBuffer} objects created by this constructor
+     * may be incompatible with <a href="#optimizations">performance
+     * optimizations</a> used by some implementations (such as caching
+     * an associated image in video memory).
+     *
+     * @param dataArray The integer array for the <CODE>DataBuffer</CODE>.
+     * @param size The size of the <CODE>DataBuffer</CODE> bank.
+     */
+    public DataBufferInt(int dataArray[], int size) {
+        super(UNTRACKABLE, TYPE_INT, size);
+        data = dataArray;
+        bankdata = new int[1][];
+        bankdata[0] = data;
+    }
+
+    /**
+     * Constructs an integer-based <CODE>DataBuffer</CODE> with a single bank using the
+     * specified array, size, and offset.  <CODE>dataArray</CODE> must have at least
+     * <CODE>offset</CODE> + <CODE>size</CODE> elements.  Only elements <CODE>offset</CODE>
+     * through <CODE>offset</CODE> + <CODE>size</CODE> - 1
+     * should be used by accessors of this <CODE>DataBuffer</CODE>.
+     * <p>
+     * Note that {@code DataBuffer} objects created by this constructor
+     * may be incompatible with <a href="#optimizations">performance
+     * optimizations</a> used by some implementations (such as caching
+     * an associated image in video memory).
+     *
+     * @param dataArray The integer array for the <CODE>DataBuffer</CODE>.
+     * @param size The size of the <CODE>DataBuffer</CODE> bank.
+     * @param offset The offset into the <CODE>dataArray</CODE>.
+     */
+    public DataBufferInt(int dataArray[], int size, int offset) {
+        super(UNTRACKABLE, TYPE_INT, size, 1, offset);
+        data = dataArray;
+        bankdata = new int[1][];
+        bankdata[0] = data;
+    }
+
+    /**
+     * Constructs an integer-based <CODE>DataBuffer</CODE> with the specified arrays.
+     * The number of banks will be equal to <CODE>dataArray.length</CODE>.
+     * Only the first <CODE>size</CODE> elements of each array should be used by
+     * accessors of this <CODE>DataBuffer</CODE>.
+     * <p>
+     * Note that {@code DataBuffer} objects created by this constructor
+     * may be incompatible with <a href="#optimizations">performance
+     * optimizations</a> used by some implementations (such as caching
+     * an associated image in video memory).
+     *
+     * @param dataArray The integer arrays for the <CODE>DataBuffer</CODE>.
+     * @param size The size of the banks in the <CODE>DataBuffer</CODE>.
+     */
+    public DataBufferInt(int dataArray[][], int size) {
+        super(UNTRACKABLE, TYPE_INT, size, dataArray.length);
+        bankdata = (int [][]) dataArray.clone();
+        data = bankdata[0];
+    }
+
+    /**
+     * Constructs an integer-based <CODE>DataBuffer</CODE> with the specified arrays, size,
+     * and offsets.
+     * The number of banks is equal to <CODE>dataArray.length</CODE>.  Each array must
+     * be at least as large as <CODE>size</CODE> + the corresponding offset.   There must
+     * be an entry in the offset array for each <CODE>dataArray</CODE> entry.  For each
+     * bank, only elements <CODE>offset</CODE> through
+     * <CODE>offset</CODE> + <CODE>size</CODE> - 1 should be
+     * used by accessors of this <CODE>DataBuffer</CODE>.
+     * <p>
+     * Note that {@code DataBuffer} objects created by this constructor
+     * may be incompatible with <a href="#optimizations">performance
+     * optimizations</a> used by some implementations (such as caching
+     * an associated image in video memory).
+     *
+     * @param dataArray The integer arrays for the <CODE>DataBuffer</CODE>.
+     * @param size The size of the banks in the <CODE>DataBuffer</CODE>.
+     * @param offsets The offsets into each array.
+     */
+    public DataBufferInt(int dataArray[][], int size, int offsets[]) {
+        super(UNTRACKABLE, TYPE_INT, size, dataArray.length, offsets);
+        bankdata = (int [][]) dataArray.clone();
+        data = bankdata[0];
+    }
+
+    /**
+     * Returns the default (first) int data array in <CODE>DataBuffer</CODE>.
+     * <p>
+     * Note that calling this method may cause this {@code DataBuffer}
+     * object to be incompatible with <a href="#optimizations">performance
+     * optimizations</a> used by some implementations (such as caching
+     * an associated image in video memory).
+     *
+     * @return The first integer data array.
+     */
+    public int[] getData() {
+        theTrackable.setUntrackable();
+        return data;
+    }
+
+    /**
+     * Returns the data array for the specified bank.
+     * <p>
+     * Note that calling this method may cause this {@code DataBuffer}
+     * object to be incompatible with <a href="#optimizations">performance
+     * optimizations</a> used by some implementations (such as caching
+     * an associated image in video memory).
+     *
+     * @param bank The bank whose data array you want to get.
+     * @return The data array for the specified bank.
+     */
+    public int[] getData(int bank) {
+        theTrackable.setUntrackable();
+        return bankdata[bank];
+    }
+
+    /**
+     * Returns the data arrays for all banks.
+     * <p>
+     * Note that calling this method may cause this {@code DataBuffer}
+     * object to be incompatible with <a href="#optimizations">performance
+     * optimizations</a> used by some implementations (such as caching
+     * an associated image in video memory).
+     *
+     * @return All of the data arrays.
+     */
+    public int[][] getBankData() {
+        theTrackable.setUntrackable();
+        return (int [][]) bankdata.clone();
+    }
+
+    /**
+     * Returns the requested data array element from the first (default) bank.
+     *
+     * @param i The data array element you want to get.
+     * @return The requested data array element as an integer.
+     * @see #setElem(int, int)
+     * @see #setElem(int, int, int)
+     */
+    public int getElem(int i) {
+        return data[i+offset];
+    }
+
+    /**
+     * Returns the requested data array element from the specified bank.
+     *
+     * @param bank The bank from which you want to get a data array element.
+     * @param i The data array element you want to get.
+     * @return The requested data array element as an integer.
+     * @see #setElem(int, int)
+     * @see #setElem(int, int, int)
+     */
+    public int getElem(int bank, int i) {
+        return bankdata[bank][i+offsets[bank]];
+    }
+
+    /**
+     * Sets the requested data array element in the first (default) bank
+     * to the specified value.
+     *
+     * @param i The data array element you want to set.
+     * @param val The integer value to which you want to set the data array element.
+     * @see #getElem(int)
+     * @see #getElem(int, int)
+     */
+    public void setElem(int i, int val) {
+        data[i+offset] = val;
+        theTrackable.markDirty();
+    }
+
+    /**
+     * Sets the requested data array element in the specified bank
+     * to the integer value <CODE>i</CODE>.
+     * @param bank The bank in which you want to set the data array element.
+     * @param i The data array element you want to set.
+     * @param val The integer value to which you want to set the specified data array element.
+     * @see #getElem(int)
+     * @see #getElem(int, int)
+     */
+    public void setElem(int bank, int i, int val) {
+        bankdata[bank][i+offsets[bank]] = (int)val;
+        theTrackable.markDirty();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/awt/image/DataBufferShort.java	Thu Apr 10 16:28:45 2008 -0700
@@ -0,0 +1,283 @@
+/*
+ * Portions Copyright 1997-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* ****************************************************************
+ ******************************************************************
+ ******************************************************************
+ *** COPYRIGHT (c) Eastman Kodak Company, 1997
+ *** As  an unpublished  work pursuant to Title 17 of the United
+ *** States Code.  All rights reserved.
+ ******************************************************************
+ ******************************************************************
+ ******************************************************************/
+
+package java.awt.image;
+
+import static sun.java2d.StateTrackable.State.*;
+
+/**
+ * This class extends <CODE>DataBuffer</CODE> and stores data internally as shorts.
+ * <p>
+ * <a name="optimizations">
+ * Note that some implementations may function more efficiently
+ * if they can maintain control over how the data for an image is
+ * stored.
+ * For example, optimizations such as caching an image in video
+ * memory require that the implementation track all modifications
+ * to that data.
+ * Other implementations may operate better if they can store the
+ * data in locations other than a Java array.
+ * To maintain optimum compatibility with various optimizations
+ * it is best to avoid constructors and methods which expose the
+ * underlying storage as a Java array as noted below in the
+ * documentation for those methods.
+ * </a>
+ */
+public final class DataBufferShort extends DataBuffer
+{
+    /** The default data bank. */
+    short data[];
+
+    /** All data banks */
+    short bankdata[][];
+
+    /**
+     * Constructs a short-based <CODE>DataBuffer</CODE> with a single bank and the
+     * specified size.
+     *
+     * @param size The size of the <CODE>DataBuffer</CODE>.
+     */
+    public DataBufferShort(int size) {
+        super(STABLE, TYPE_SHORT,size);
+        data = new short[size];
+        bankdata = new short[1][];
+        bankdata[0] = data;
+    }
+
+    /**
+     * Constructs a short-based <CODE>DataBuffer</CODE> with the specified number of
+     * banks all of which are the specified size.
+     *
+     * @param size The size of the banks in the <CODE>DataBuffer</CODE>.
+     * @param numBanks The number of banks in the a<CODE>DataBuffer</CODE>.
+     */
+    public DataBufferShort(int size, int numBanks) {
+        super(STABLE, TYPE_SHORT,size,numBanks);
+        bankdata = new short[numBanks][];
+        for (int i= 0; i < numBanks; i++) {
+            bankdata[i] = new short[size];
+        }
+        data = bankdata[0];
+    }
+
+    /**
+     * Constructs a short-based <CODE>DataBuffer</CODE> with a single bank using the
+     * specified array.
+     * Only the first <CODE>size</CODE> elements should be used by accessors of
+     * this <CODE>DataBuffer</CODE>.  <CODE>dataArray</CODE> must be large enough to
+     * hold <CODE>size</CODE> elements.
+     * <p>
+     * Note that {@code DataBuffer} objects created by this constructor
+     * may be incompatible with <a href="#optimizations">performance
+     * optimizations</a> used by some implementations (such as caching
+     * an associated image in video memory).
+     *
+     * @param dataArray The short array for the <CODE>DataBuffer</CODE>.
+     * @param size The size of the <CODE>DataBuffer</CODE> bank.
+     */
+    public DataBufferShort(short dataArray[], int size) {
+        super(UNTRACKABLE, TYPE_SHORT, size);
+        data = dataArray;
+        bankdata = new short[1][];
+        bankdata[0] = data;
+    }
+
+    /**
+     * Constructs a short-based <CODE>DataBuffer</CODE> with a single bank using the
+     * specified array, size, and offset.  <CODE>dataArray</CODE> must have at least
+     * <CODE>offset</CODE> + <CODE>size</CODE> elements.  Only elements <CODE>offset</CODE>
+     * through <CODE>offset</CODE> + <CODE>size</CODE> - 1
+     * should be used by accessors of this <CODE>DataBuffer</CODE>.
+     * <p>
+     * Note that {@code DataBuffer} objects created by this constructor
+     * may be incompatible with <a href="#optimizations">performance
+     * optimizations</a> used by some implementations (such as caching
+     * an associated image in video memory).
+     *
+     * @param dataArray The short array for the <CODE>DataBuffer</CODE>.
+     * @param size The size of the <CODE>DataBuffer</CODE> bank.
+     * @param offset The offset into the <CODE>dataArray</CODE>.
+     */
+    public DataBufferShort(short dataArray[], int size, int offset) {
+        super(UNTRACKABLE, TYPE_SHORT, size, 1, offset);
+        data = dataArray;
+        bankdata = new short[1][];
+        bankdata[0] = data;
+    }
+
+    /**
+     * Constructs a short-based <CODE>DataBuffer</CODE> with the specified arrays.
+     * The number of banks will be equal to <CODE>dataArray.length</CODE>.
+     * Only the first <CODE>size</CODE> elements of each array should be used by
+     * accessors of this <CODE>DataBuffer</CODE>.
+     * <p>
+     * Note that {@code DataBuffer} objects created by this constructor
+     * may be incompatible with <a href="#optimizations">performance
+     * optimizations</a> used by some implementations (such as caching
+     * an associated image in video memory).
+     *
+     * @param dataArray The short arrays for the <CODE>DataBuffer</CODE>.
+     * @param size The size of the banks in the <CODE>DataBuffer</CODE>.
+     */
+    public DataBufferShort(short dataArray[][], int size) {
+        super(UNTRACKABLE, TYPE_SHORT, size, dataArray.length);
+        bankdata = (short[][]) dataArray.clone();
+        data = bankdata[0];
+    }
+
+    /**
+     * Constructs a short-based <CODE>DataBuffer</CODE> with the specified arrays, size,
+     * and offsets.
+     * The number of banks is equal to <CODE>dataArray.length</CODE>.  Each array must
+     * be at least as large as <CODE>size</CODE> + the corresponding offset.   There must
+     * be an entry in the offset array for each <CODE>dataArray</CODE> entry.  For each
+     * bank, only elements <CODE>offset</CODE> through
+     * <CODE>offset</CODE> + <CODE>size</CODE> - 1 should be
+     * used by accessors of this <CODE>DataBuffer</CODE>.
+     * <p>
+     * Note that {@code DataBuffer} objects created by this constructor
+     * may be incompatible with <a href="#optimizations">performance
+     * optimizations</a> used by some implementations (such as caching
+     * an associated image in video memory).
+     *
+     * @param dataArray The short arrays for the <CODE>DataBuffer</CODE>.
+     * @param size The size of the banks in the <CODE>DataBuffer</CODE>.
+     * @param offsets The offsets into each array.
+     */
+    public DataBufferShort(short dataArray[][], int size, int offsets[]) {
+        super(UNTRACKABLE, TYPE_SHORT, size, dataArray.length, offsets);
+        bankdata = (short[][]) dataArray.clone();
+        data = bankdata[0];
+    }
+
+    /**
+     * Returns the default (first) byte data array.
+     * <p>
+     * Note that calling this method may cause this {@code DataBuffer}
+     * object to be incompatible with <a href="#optimizations">performance
+     * optimizations</a> used by some implementations (such as caching
+     * an associated image in video memory).
+     *
+     * @return The first short data array.
+     */
+    public short[] getData() {
+        theTrackable.setUntrackable();
+        return data;
+    }
+
+    /**
+     * Returns the data array for the specified bank.
+     * <p>
+     * Note that calling this method may cause this {@code DataBuffer}
+     * object to be incompatible with <a href="#optimizations">performance
+     * optimizations</a> used by some implementations (such as caching
+     * an associated image in video memory).
+     *
+     * @param bank The bank whose data array you want to get.
+     * @return The data array for the specified bank.
+     */
+    public short[] getData(int bank) {
+        theTrackable.setUntrackable();
+        return bankdata[bank];
+    }
+
+    /**
+     * Returns the data arrays for all banks.
+     * <p>
+     * Note that calling this method may cause this {@code DataBuffer}
+     * object to be incompatible with <a href="#optimizations">performance
+     * optimizations</a> used by some implementations (such as caching
+     * an associated image in video memory).
+     *
+     * @return All of the data arrays.
+     */
+    public short[][] getBankData() {
+        theTrackable.setUntrackable();
+        return (short[][]) bankdata.clone();
+    }
+
+    /**
+     * Returns the requested data array element from the first (default) bank.
+     *
+     * @param i The data array element you want to get.
+     * @return The requested data array element as an integer.
+     * @see #setElem(int, int)
+     * @see #setElem(int, int, int)
+     */
+    public int getElem(int i) {
+        return (int)(data[i+offset]);
+    }
+
+    /**
+     * Returns the requested data array element from the specified bank.
+     *
+     * @param bank The bank from which you want to get a data array element.
+     * @param i The data array element you want to get.
+     * @return The requested data array element as an integer.
+     * @see #setElem(int, int)
+     * @see #setElem(int, int, int)
+     */
+    public int getElem(int bank, int i) {
+        return (int)(bankdata[bank][i+offsets[bank]]);
+    }
+
+    /**
+     * Sets the requested data array element in the first (default) bank
+     * to the specified value.
+     *
+     * @param i The data array element you want to set.
+     * @param val The integer value to which you want to set the data array element.
+     * @see #getElem(int)
+     * @see #getElem(int, int)
+     */
+    public void setElem(int i, int val) {
+        data[i+offset] = (short)val;
+        theTrackable.markDirty();
+    }
+
+    /**
+     * Sets the requested data array element in the specified bank
+     * from the given integer.
+     * @param bank The bank in which you want to set the data array element.
+     * @param i The data array element you want to set.
+     * @param val The integer value to which you want to set the specified data array element.
+     * @see #getElem(int)
+     * @see #getElem(int, int)
+     */
+    public void setElem(int bank, int i, int val) {
+        bankdata[bank][i+offsets[bank]] = (short)val;
+        theTrackable.markDirty();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/awt/image/DataBufferUShort.java	Thu Apr 10 16:28:45 2008 -0700
@@ -0,0 +1,318 @@
+/*
+ * Portions Copyright 1997-2006 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* ****************************************************************
+ ******************************************************************
+ ******************************************************************
+ *** COPYRIGHT (c) Eastman Kodak Company, 1997
+ *** As  an unpublished  work pursuant to Title 17 of the United
+ *** States Code.  All rights reserved.
+ ******************************************************************
+ ******************************************************************
+ ******************************************************************/
+
+package java.awt.image;
+
+import static sun.java2d.StateTrackable.State.*;
+
+/**
+ * This class extends <CODE>DataBuffer</CODE> and stores data internally as
+ * shorts.  Values stored in the short array(s) of this <CODE>DataBuffer</CODE>
+ * are treated as unsigned values.
+ * <p>
+ * <a name="optimizations">
+ * Note that some implementations may function more efficiently
+ * if they can maintain control over how the data for an image is
+ * stored.
+ * For example, optimizations such as caching an image in video
+ * memory require that the implementation track all modifications
+ * to that data.
+ * Other implementations may operate better if they can store the
+ * data in locations other than a Java array.
+ * To maintain optimum compatibility with various optimizations
+ * it is best to avoid constructors and methods which expose the
+ * underlying storage as a Java array as noted below in the
+ * documentation for those methods.
+ * </a>
+ */
+public final class DataBufferUShort extends DataBuffer
+{
+    /** The default data bank. */
+    short data[];
+
+    /** All data banks */
+    short bankdata[][];
+
+    /**
+     * Constructs an unsigned-short based <CODE>DataBuffer</CODE> with a single bank and the
+     * specified size.
+     *
+     * @param size The size of the <CODE>DataBuffer</CODE>.
+     */
+    public DataBufferUShort(int size) {
+        super(STABLE, TYPE_USHORT, size);
+        data = new short[size];
+        bankdata = new short[1][];
+        bankdata[0] = data;
+    }
+
+    /**
+     * Constructs an unsigned-short based <CODE>DataBuffer</CODE> with the specified number of
+     * banks, all of which are the specified size.
+     *
+     * @param size The size of the banks in the <CODE>DataBuffer</CODE>.
+     * @param numBanks The number of banks in the a<CODE>DataBuffer</CODE>.
+    */
+    public DataBufferUShort(int size, int numBanks) {
+        super(STABLE, TYPE_USHORT, size, numBanks);
+        bankdata = new short[numBanks][];
+        for (int i= 0; i < numBanks; i++) {
+            bankdata[i] = new short[size];
+        }
+        data = bankdata[0];
+    }
+
+    /**
+     * Constructs an unsigned-short based <CODE>DataBuffer</CODE> with a single bank
+     * using the specified array.
+     * Only the first <CODE>size</CODE> elements should be used by accessors of
+     * this <CODE>DataBuffer</CODE>.  <CODE>dataArray</CODE> must be large enough to
+     * hold <CODE>size</CODE> elements.
+     * <p>
+     * Note that {@code DataBuffer} objects created by this constructor
+     * may be incompatible with <a href="#optimizations">performance
+     * optimizations</a> used by some implementations (such as caching
+     * an associated image in video memory).
+     *
+     * @param dataArray The unsigned-short array for the <CODE>DataBuffer</CODE>.
+     * @param size The size of the <CODE>DataBuffer</CODE> bank.
+     */
+    public DataBufferUShort(short dataArray[], int size) {
+        super(UNTRACKABLE, TYPE_USHORT, size);
+        if (dataArray == null) {
+            throw new NullPointerException("dataArray is null");
+        }
+        data = dataArray;
+        bankdata = new short[1][];
+        bankdata[0] = data;
+    }
+
+    /**
+     * Constructs an unsigned-short based <CODE>DataBuffer</CODE> with a single bank
+     * using the specified array, size, and offset.  <CODE>dataArray</CODE> must have at
+     * least <CODE>offset</CODE> + <CODE>size</CODE> elements.  Only elements
+     * <CODE>offset</CODE> through <CODE>offset</CODE> + <CODE>size</CODE> - 1 should
+     * be used by accessors of this <CODE>DataBuffer</CODE>.
+     * <p>
+     * Note that {@code DataBuffer} objects created by this constructor
+     * may be incompatible with <a href="#optimizations">performance
+     * optimizations</a> used by some implementations (such as caching
+     * an associated image in video memory).
+     *
+     * @param dataArray The unsigned-short array for the <CODE>DataBuffer</CODE>.
+     * @param size The size of the <CODE>DataBuffer</CODE> bank.
+     * @param offset The offset into the <CODE>dataArray</CODE>.
+     */
+    public DataBufferUShort(short dataArray[], int size, int offset) {
+        super(UNTRACKABLE, TYPE_USHORT, size, 1, offset);
+        if (dataArray == null) {
+            throw new NullPointerException("dataArray is null");
+        }
+        if ((size+offset) > dataArray.length) {
+            throw new IllegalArgumentException("Length of dataArray is less "+
+                                               " than size+offset.");
+        }
+        data = dataArray;
+        bankdata = new short[1][];
+        bankdata[0] = data;
+    }
+
+    /**
+     * Constructs an unsigned-short based <CODE>DataBuffer</CODE> with the specified arrays.
+     * The number of banks will be equal to <CODE>dataArray.length</CODE>.
+     * Only the first <CODE>size</CODE> elements of each array should be used by
+     * accessors of this <CODE>DataBuffer</CODE>.
+     * <p>
+     * Note that {@code DataBuffer} objects created by this constructor
+     * may be incompatible with <a href="#optimizations">performance
+     * optimizations</a> used by some implementations (such as caching
+     * an associated image in video memory).
+     *
+     * @param dataArray The unsigned-short arrays for the <CODE>DataBuffer</CODE>.
+     * @param size The size of the banks in the <CODE>DataBuffer</CODE>.
+     */
+    public DataBufferUShort(short dataArray[][], int size) {
+        super(UNTRACKABLE, TYPE_USHORT, size, dataArray.length);
+        if (dataArray == null) {
+            throw new NullPointerException("dataArray is null");
+        }
+        for (int i=0; i < dataArray.length; i++) {
+            if (dataArray[i] == null) {
+                throw new NullPointerException("dataArray["+i+"] is null");
+            }
+        }
+
+        bankdata = (short[][]) dataArray.clone();
+        data = bankdata[0];
+    }
+
+    /**
+     * Constructs an unsigned-short based <CODE>DataBuffer</CODE> with specified arrays,
+     * size, and offsets.
+     * The number of banks is equal to <CODE>dataArray.length</CODE>.  Each array must
+     * be at least as large as <CODE>size</CODE> + the corresponding offset.   There must
+     * be an entry in the offset array for each <CODE>dataArray</CODE> entry.  For each
+     * bank, only elements <CODE>offset</CODE> through
+     * <CODE>offset</CODE> + <CODE>size</CODE> - 1 should be
+     * used by accessors of this <CODE>DataBuffer</CODE>.
+     * <p>
+     * Note that {@code DataBuffer} objects created by this constructor
+     * may be incompatible with <a href="#optimizations">performance
+     * optimizations</a> used by some implementations (such as caching
+     * an associated image in video memory).
+     *
+     * @param dataArray The unsigned-short arrays for the <CODE>DataBuffer</CODE>.
+     * @param size The size of the banks in the <CODE>DataBuffer</CODE>.
+     * @param offsets The offsets into each array.
+     */
+    public DataBufferUShort(short dataArray[][], int size, int offsets[]) {
+        super(UNTRACKABLE, TYPE_USHORT, size, dataArray.length, offsets);
+        if (dataArray == null) {
+            throw new NullPointerException("dataArray is null");
+        }
+        for (int i=0; i < dataArray.length; i++) {
+            if (dataArray[i] == null) {
+                throw new NullPointerException("dataArray["+i+"] is null");
+            }
+            if ((size+offsets[i]) > dataArray[i].length) {
+                throw new IllegalArgumentException("Length of dataArray["+i+
+                                                   "] is less than size+"+
+                                                   "offsets["+i+"].");
+            }
+
+        }
+        bankdata = (short[][]) dataArray.clone();
+        data = bankdata[0];
+    }
+
+    /**
+     * Returns the default (first) unsigned-short data array.
+     * <p>
+     * Note that calling this method may cause this {@code DataBuffer}
+     * object to be incompatible with <a href="#optimizations">performance
+     * optimizations</a> used by some implementations (such as caching
+     * an associated image in video memory).
+     *
+     * @return The first unsigned-short data array.
+     */
+    public short[] getData() {
+        theTrackable.setUntrackable();
+        return data;
+    }
+
+    /**
+     * Returns the data array for the specified bank.
+     * <p>
+     * Note that calling this method may cause this {@code DataBuffer}
+     * object to be incompatible with <a href="#optimizations">performance
+     * optimizations</a> used by some implementations (such as caching
+     * an associated image in video memory).
+     *
+     * @param bank The bank whose data array you want to get.
+     * @return The data array for the specified bank.
+     */
+    public short[] getData(int bank) {
+        theTrackable.setUntrackable();
+        return bankdata[bank];
+    }
+
+    /**
+     * Returns the data arrays for all banks.
+     * <p>
+     * Note that calling this method may cause this {@code DataBuffer}
+     * object to be incompatible with <a href="#optimizations">performance
+     * optimizations</a> used by some implementations (such as caching
+     * an associated image in video memory).
+     *
+     * @return All of the data arrays.
+     */
+    public short[][] getBankData() {
+        theTrackable.setUntrackable();
+        return (short[][]) bankdata.clone();
+    }
+
+    /**
+     * Returns the requested data array element from the first (default) bank.
+     *
+     * @param i The data array element you want to get.
+     * @return The requested data array element as an integer.
+     * @see #setElem(int, int)
+     * @see #setElem(int, int, int)
+     */
+    public int getElem(int i) {
+        return (int)(data[i+offset]&0xffff);
+    }
+
+    /**
+     * Returns the requested data array element from the specified bank.
+     *
+     * @param bank The bank from which you want to get a data array element.
+     * @param i The data array element you want to get.
+     * @return The requested data array element as an integer.
+     * @see #setElem(int, int)
+     * @see #setElem(int, int, int)
+     */
+    public int getElem(int bank, int i) {
+        return (int)(bankdata[bank][i+offsets[bank]]&0xffff);
+    }
+
+    /**
+     * Sets the requested data array element in the first (default) bank
+     * to the specified value.
+     *
+     * @param i The data array element you want to set.
+     * @param val The integer value to which you want to set the data array element.
+     * @see #getElem(int)
+     * @see #getElem(int, int)
+     */
+    public void setElem(int i, int val) {
+        data[i+offset] = (short)(val&0xffff);
+        theTrackable.markDirty();
+    }
+
+    /**
+     * Sets the requested data array element in the specified bank
+     * from the given integer.
+     * @param bank The bank in which you want to set the data array element.
+     * @param i The data array element you want to set.
+     * @param val The integer value to which you want to set the specified data array element.
+     * @see #getElem(int)
+     * @see #getElem(int, int)
+     */
+    public void setElem(int bank, int i, int val) {
+        bankdata[bank][i+offsets[bank]] = (short)(val&0xffff);
+        theTrackable.markDirty();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/awt/image/MultiPixelPackedSampleModel.java	Thu Apr 10 16:28:45 2008 -0700
@@ -0,0 +1,699 @@
+/*
+ * Portions Copyright 1997-2006 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* ****************************************************************
+ ******************************************************************
+ ******************************************************************
+ *** COPYRIGHT (c) Eastman Kodak Company, 1997
+ *** As  an unpublished  work pursuant to Title 17 of the United
+ *** States Code.  All rights reserved.
+ ******************************************************************
+ ******************************************************************
+ ******************************************************************/
+
+package java.awt.image;
+
+/**
+ * The <code>MultiPixelPackedSampleModel</code> class represents
+ * one-banded images and can pack multiple one-sample
+ * pixels into one data element.  Pixels are not allowed to span data elements.
+ * The data type can be DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
+ * or DataBuffer.TYPE_INT.  Each pixel must be a power of 2 number of bits
+ * and a power of 2 number of pixels must fit exactly in one data element.
+ * Pixel bit stride is equal to the number of bits per pixel.  Scanline
+ * stride is in data elements and the last several data elements might be
+ * padded with unused pixels.  Data bit offset is the offset in bits from
+ * the beginning of the {@link DataBuffer} to the first pixel and must be
+ * a multiple of pixel bit stride.
+ * <p>
+ * The following code illustrates extracting the bits for pixel
+ * <code>x,&nbsp;y</code> from <code>DataBuffer</code> <code>data</code>
+ * and storing the pixel data in data elements of type
+ * <code>dataType</code>:
+ * <pre>
+ *      int dataElementSize = DataBuffer.getDataTypeSize(dataType);
+ *      int bitnum = dataBitOffset + x*pixelBitStride;
+ *      int element = data.getElem(y*scanlineStride + bitnum/dataElementSize);
+ *      int shift = dataElementSize - (bitnum & (dataElementSize-1))
+ *                  - pixelBitStride;
+ *      int pixel = (element >> shift) & ((1 << pixelBitStride) - 1);
+ * </pre>
+ */
+
+public class MultiPixelPackedSampleModel extends SampleModel
+{
+    /** The number of bits from one pixel to the next. */
+    int pixelBitStride;
+
+    /** Bitmask that extracts the rightmost pixel of a data element. */
+    int bitMask;
+
+    /**
+      * The number of pixels that fit in a data element.  Also used
+      * as the number of bits per pixel.
+      */
+    int pixelsPerDataElement;
+
+    /** The size of a data element in bits. */
+    int dataElementSize;
+
+    /** The bit offset into the data array where the first pixel begins.
+     */
+    int dataBitOffset;
+
+    /** ScanlineStride of the data buffer described in data array elements. */
+    int scanlineStride;
+
+    /**
+     * Constructs a <code>MultiPixelPackedSampleModel</code> with the
+     * specified data type, width, height and number of bits per pixel.
+     * @param dataType  the data type for storing samples
+     * @param w         the width, in pixels, of the region of
+     *                  image data described
+     * @param h         the height, in pixels, of the region of
+     *                  image data described
+     * @param numberOfBits the number of bits per pixel
+     * @throws IllegalArgumentException if <code>dataType</code> is not
+     *         either <code>DataBuffer.TYPE_BYTE</code>,
+     *         <code>DataBuffer.TYPE_USHORT</code>, or
+     *         <code>DataBuffer.TYPE_INT</code>
+     */
+    public MultiPixelPackedSampleModel(int dataType,
+                                       int w,
+                                       int h,
+                                       int numberOfBits) {
+        this(dataType,w,h,
+             numberOfBits,
+            (w*numberOfBits+DataBuffer.getDataTypeSize(dataType)-1)/
+                DataBuffer.getDataTypeSize(dataType),
+             0);
+        if (dataType != DataBuffer.TYPE_BYTE &&
+            dataType != DataBuffer.TYPE_USHORT &&
+            dataType != DataBuffer.TYPE_INT) {
+            throw new IllegalArgumentException("Unsupported data type "+
+                                               dataType);
+        }
+    }
+
+    /**
+     * Constructs a <code>MultiPixelPackedSampleModel</code> with
+     * specified data type, width, height, number of bits per pixel,
+     * scanline stride and data bit offset.
+     * @param dataType  the data type for storing samples
+     * @param w         the width, in pixels, of the region of
+     *                  image data described
+     * @param h         the height, in pixels, of the region of
+     *                  image data described
+     * @param numberOfBits the number of bits per pixel
+     * @param scanlineStride the line stride of the image data
+     * @param dataBitOffset the data bit offset for the region of image
+     *                  data described
+     * @exception RasterFormatException if the number of bits per pixel
+     *                  is not a power of 2 or if a power of 2 number of
+     *                  pixels do not fit in one data element.
+     * @throws IllegalArgumentException if <code>w</code> or
+     *         <code>h</code> is not greater than 0
+     * @throws IllegalArgumentException if <code>dataType</code> is not
+     *         either <code>DataBuffer.TYPE_BYTE</code>,
+     *         <code>DataBuffer.TYPE_USHORT</code>, or
+     *         <code>DataBuffer.TYPE_INT</code>
+     */
+    public MultiPixelPackedSampleModel(int dataType, int w, int h,
+                                       int numberOfBits,
+                                       int scanlineStride,
+                                       int dataBitOffset) {
+        super(dataType, w, h, 1);
+        if (dataType != DataBuffer.TYPE_BYTE &&
+            dataType != DataBuffer.TYPE_USHORT &&
+            dataType != DataBuffer.TYPE_INT) {
+            throw new IllegalArgumentException("Unsupported data type "+
+                                               dataType);
+        }
+        this.dataType = dataType;
+        this.pixelBitStride = numberOfBits;
+        this.scanlineStride = scanlineStride;
+        this.dataBitOffset = dataBitOffset;
+        this.dataElementSize = DataBuffer.getDataTypeSize(dataType);
+        this.pixelsPerDataElement = dataElementSize/numberOfBits;
+        if (pixelsPerDataElement*numberOfBits != dataElementSize) {
+           throw new RasterFormatException("MultiPixelPackedSampleModel " +
+                                             "does not allow pixels to " +
+                                             "span data element boundaries");
+        }
+        this.bitMask = (1 << numberOfBits) - 1;
+    }
+
+
+    /**
+     * Creates a new <code>MultiPixelPackedSampleModel</code> with the
+     * specified width and height.  The new
+     * <code>MultiPixelPackedSampleModel</code> has the
+     * same storage data type and number of bits per pixel as this
+     * <code>MultiPixelPackedSampleModel</code>.
+     * @param w the specified width
+     * @param h the specified height
+     * @return a {@link SampleModel} with the specified width and height
+     * and with the same storage data type and number of bits per pixel
+     * as this <code>MultiPixelPackedSampleModel</code>.
+     * @throws IllegalArgumentException if <code>w</code> or
+     *         <code>h</code> is not greater than 0
+     */
+    public SampleModel createCompatibleSampleModel(int w, int h) {
+      SampleModel sampleModel =
+            new MultiPixelPackedSampleModel(dataType, w, h, pixelBitStride);
+      return sampleModel;
+    }
+
+    /**
+     * Creates a <code>DataBuffer</code> that corresponds to this
+     * <code>MultiPixelPackedSampleModel</code>.  The
+     * <code>DataBuffer</code> object's data type and size
+     * is consistent with this <code>MultiPixelPackedSampleModel</code>.
+     * The <code>DataBuffer</code> has a single bank.
+     * @return a <code>DataBuffer</code> with the same data type and
+     * size as this <code>MultiPixelPackedSampleModel</code>.
+     */
+    public DataBuffer createDataBuffer() {
+        DataBuffer dataBuffer = null;
+
+        int size = (int)scanlineStride*height;
+        switch (dataType) {
+        case DataBuffer.TYPE_BYTE:
+            dataBuffer = new DataBufferByte(size+(dataBitOffset+7)/8);
+            break;
+        case DataBuffer.TYPE_USHORT:
+            dataBuffer = new DataBufferUShort(size+(dataBitOffset+15)/16);
+            break;
+        case DataBuffer.TYPE_INT:
+            dataBuffer = new DataBufferInt(size+(dataBitOffset+31)/32);
+            break;
+        }
+        return dataBuffer;
+    }
+
+    /**
+     * Returns the number of data elements needed to transfer one pixel
+     * via the {@link #getDataElements} and {@link #setDataElements}
+     * methods.  For a <code>MultiPixelPackedSampleModel</code>, this is
+     * one.
+     * @return the number of data elements.
+     */
+    public int getNumDataElements() {
+        return 1;
+    }
+
+    /**
+     * Returns the number of bits per sample for all bands.
+     * @return the number of bits per sample.
+     */
+    public int[] getSampleSize() {
+        int sampleSize[] = {pixelBitStride};
+        return sampleSize;
+    }
+
+    /**
+     * Returns the number of bits per sample for the specified band.
+     * @param band the specified band
+     * @return the number of bits per sample for the specified band.
+     */
+    public int getSampleSize(int band) {
+        return pixelBitStride;
+    }
+
+    /**
+     * Returns the offset of pixel (x,&nbsp;y) in data array elements.
+     * @param x the X coordinate of the specified pixel
+     * @param y the Y coordinate of the specified pixel
+     * @return the offset of the specified pixel.
+     */
+    public int getOffset(int x, int y) {
+        int offset = y * scanlineStride;
+        offset +=  (x*pixelBitStride+dataBitOffset)/dataElementSize;
+        return offset;
+    }
+
+    /**
+     *  Returns the offset, in bits, into the data element in which it is
+     *  stored for the <code>x</code>th pixel of a scanline.
+     *  This offset is the same for all scanlines.
+     *  @param x the specified pixel
+     *  @return the bit offset of the specified pixel.
+     */
+    public int getBitOffset(int x){
+       return  (x*pixelBitStride+dataBitOffset)%dataElementSize;
+    }
+
+    /**
+     * Returns the scanline stride.
+     * @return the scanline stride of this
+     * <code>MultiPixelPackedSampleModel</code>.
+     */
+    public int getScanlineStride() {
+        return scanlineStride;
+    }
+
+    /**
+     * Returns the pixel bit stride in bits.  This value is the same as
+     * the number of bits per pixel.
+     * @return the <code>pixelBitStride</code> of this
+     * <code>MultiPixelPackedSampleModel</code>.
+     */
+    public int getPixelBitStride() {
+        return pixelBitStride;
+    }
+
+    /**
+     * Returns the data bit offset in bits.
+     * @return the <code>dataBitOffset</code> of this
+     * <code>MultiPixelPackedSampleModel</code>.
+     */
+    public int getDataBitOffset() {
+        return dataBitOffset;
+    }
+
+    /**
+     *  Returns the TransferType used to transfer pixels by way of the
+     *  <code>getDataElements</code> and <code>setDataElements</code>
+     *  methods. The TransferType might or might not be the same as the
+     *  storage DataType.  The TransferType is one of
+     *  DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
+     *  or DataBuffer.TYPE_INT.
+     *  @return the transfertype.
+     */
+    public int getTransferType() {
+        if (pixelBitStride > 16)
+            return DataBuffer.TYPE_INT;
+        else if (pixelBitStride > 8)
+            return DataBuffer.TYPE_USHORT;
+        else
+            return DataBuffer.TYPE_BYTE;
+    }
+
+    /**
+     * Creates a new <code>MultiPixelPackedSampleModel</code> with a
+     * subset of the bands of this
+     * <code>MultiPixelPackedSampleModel</code>.  Since a
+     * <code>MultiPixelPackedSampleModel</code> only has one band, the
+     * bands argument must have a length of one and indicate the zeroth
+     * band.
+     * @param bands the specified bands
+     * @return a new <code>SampleModel</code> with a subset of bands of
+     * this <code>MultiPixelPackedSampleModel</code>.
+     * @exception RasterFormatException if the number of bands requested
+     * is not one.
+     * @throws IllegalArgumentException if <code>w</code> or
+     *         <code>h</code> is not greater than 0
+     */
+    public SampleModel createSubsetSampleModel(int bands[]) {
+        if (bands != null) {
+           if (bands.length != 1)
+            throw new RasterFormatException("MultiPixelPackedSampleModel has "
+                                            + "only one band.");
+        }
+        SampleModel sm = createCompatibleSampleModel(width, height);
+        return sm;
+    }
+
+    /**
+     * Returns as <code>int</code> the sample in a specified band for the
+     * pixel located at (x,&nbsp;y).  An
+     * <code>ArrayIndexOutOfBoundsException</code> is thrown if the
+     * coordinates are not in bounds.
+     * @param x         the X coordinate of the specified pixel
+     * @param y         the Y coordinate of the specified pixel
+     * @param b         the band to return, which is assumed to be 0
+     * @param data      the <code>DataBuffer</code> containing the image
+     *                  data
+     * @return the specified band containing the sample of the specified
+     * pixel.
+     * @exception ArrayIndexOutOfBoundException if the specified
+     *          coordinates are not in bounds.
+     * @see #setSample(int, int, int, int, DataBuffer)
+     */
+    public int getSample(int x, int y, int b, DataBuffer data) {
+        // 'b' must be 0
+        if ((x < 0) || (y < 0) || (x >= width) || (y >= height) ||
+            (b != 0)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+        int bitnum = dataBitOffset + x*pixelBitStride;
+        int element = data.getElem(y*scanlineStride + bitnum/dataElementSize);
+        int shift = dataElementSize - (bitnum & (dataElementSize-1))
+                    - pixelBitStride;
+        return (element >> shift) & bitMask;
+    }
+
+    /**
+     * Sets a sample in the specified band for the pixel located at
+     * (x,&nbsp;y) in the <code>DataBuffer</code> using an
+     * <code>int</code> for input.
+     * An <code>ArrayIndexOutOfBoundsException</code> is thrown if the
+     * coordinates are not in bounds.
+     * @param x the X coordinate of the specified pixel
+     * @param y the Y coordinate of the specified pixel
+     * @param b the band to return, which is assumed to be 0
+     * @param s the input sample as an <code>int</code>
+     * @param data the <code>DataBuffer</code> where image data is stored
+     * @exception ArrayIndexOutOfBoundsException if the coordinates are
+     * not in bounds.
+     * @see #getSample(int, int, int, DataBuffer)
+     */
+    public void setSample(int x, int y, int b, int s,
+                          DataBuffer data) {
+        // 'b' must be 0
+        if ((x < 0) || (y < 0) || (x >= width) || (y >= height) ||
+            (b != 0)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+        int bitnum = dataBitOffset + x * pixelBitStride;
+        int index = y * scanlineStride + (bitnum / dataElementSize);
+        int shift = dataElementSize - (bitnum & (dataElementSize-1))
+                    - pixelBitStride;
+        int element = data.getElem(index);
+        element &= ~(bitMask << shift);
+        element |= (s & bitMask) << shift;
+        data.setElem(index,element);
+    }
+
+    /**
+     * Returns data for a single pixel in a primitive array of type
+     * TransferType.  For a <code>MultiPixelPackedSampleModel</code>,
+     * the array has one element, and the type is the smallest of
+     * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT
+     * that can hold a single pixel.  Generally, <code>obj</code>
+     * should be passed in as <code>null</code>, so that the
+     * <code>Object</code> is created automatically and is the
+     * correct primitive data type.
+     * <p>
+     * The following code illustrates transferring data for one pixel from
+     * <code>DataBuffer</code> <code>db1</code>, whose storage layout is
+     * described by <code>MultiPixelPackedSampleModel</code>
+     * <code>mppsm1</code>, to <code>DataBuffer</code> <code>db2</code>,
+     * whose storage layout is described by
+     * <code>MultiPixelPackedSampleModel</code> <code>mppsm2</code>.
+     * The transfer is generally more efficient than using
+     * <code>getPixel</code> or <code>setPixel</code>.
+     * <pre>
+     *       MultiPixelPackedSampleModel mppsm1, mppsm2;
+     *       DataBufferInt db1, db2;
+     *       mppsm2.setDataElements(x, y, mppsm1.getDataElements(x, y, null,
+     *                              db1), db2);
+     * </pre>
+     * Using <code>getDataElements</code> or <code>setDataElements</code>
+     * to transfer between two <code>DataBuffer/SampleModel</code> pairs
+     * is legitimate if the <code>SampleModels</code> have the same number
+     * of bands, corresponding bands have the same number of
+     * bits per sample, and the TransferTypes are the same.
+     * <p>
+     * If <code>obj</code> is not <code>null</code>, it should be a
+     * primitive array of type TransferType.  Otherwise, a
+     * <code>ClassCastException</code> is thrown.  An
+     * <code>ArrayIndexOutOfBoundsException</code> is thrown if the
+     * coordinates are not in bounds, or if <code>obj</code> is not
+     * <code>null</code> and is not large enough to hold the pixel data.
+     * @param x the X coordinate of the specified pixel
+     * @param y the Y coordinate of the specified pixel
+     * @param obj a primitive array in which to return the pixel data or
+     *          <code>null</code>.
+     * @param data the <code>DataBuffer</code> containing the image data.
+     * @return an <code>Object</code> containing data for the specified
+     *  pixel.
+     * @exception ClassCastException if <code>obj</code> is not a
+     *  primitive array of type TransferType or is not <code>null</code>
+     * @exception ArrayIndexOutOfBoundsException if the coordinates are
+     * not in bounds, or if <code>obj</code> is not <code>null</code> or
+     * not large enough to hold the pixel data
+     * @see #setDataElements(int, int, Object, DataBuffer)
+     */
+    public Object getDataElements(int x, int y, Object obj, DataBuffer data) {
+        if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+
+        int type = getTransferType();
+        int bitnum = dataBitOffset + x*pixelBitStride;
+        int shift = dataElementSize - (bitnum & (dataElementSize-1))
+                    - pixelBitStride;
+        int element = 0;
+
+        switch(type) {
+
+        case DataBuffer.TYPE_BYTE:
+
+            byte[] bdata;
+
+            if (obj == null)
+                bdata = new byte[1];
+            else
+                bdata = (byte[])obj;
+
+            element = data.getElem(y*scanlineStride +
+                                    bitnum/dataElementSize);
+            bdata[0] = (byte)((element >> shift) & bitMask);
+
+            obj = (Object)bdata;
+            break;
+
+        case DataBuffer.TYPE_USHORT:
+
+            short[] sdata;
+
+            if (obj == null)
+                sdata = new short[1];
+            else
+                sdata = (short[])obj;
+
+            element = data.getElem(y*scanlineStride +
+                                   bitnum/dataElementSize);
+            sdata[0] = (short)((element >> shift) & bitMask);
+
+            obj = (Object)sdata;
+            break;
+
+        case DataBuffer.TYPE_INT:
+
+            int[] idata;
+
+            if (obj == null)
+                idata = new int[1];
+            else
+                idata = (int[])obj;
+
+            element = data.getElem(y*scanlineStride +
+                                   bitnum/dataElementSize);
+            idata[0] = (element >> shift) & bitMask;
+
+            obj = (Object)idata;
+            break;
+        }
+
+        return obj;
+    }
+
+    /**
+     * Returns the specified single band pixel in the first element
+     * of an <code>int</code> array.
+     * <code>ArrayIndexOutOfBoundsException</code> is thrown if the
+     * coordinates are not in bounds.
+     * @param x the X coordinate of the specified pixel
+     * @param y the Y coordinate of the specified pixel
+     * @param iArray the array containing the pixel to be returned or
+     *  <code>null</code>
+     * @param data the <code>DataBuffer</code> where image data is stored
+     * @return an array containing the specified pixel.
+     * @exception ArrayIndexOutOfBoundsException if the coordinates
+     *  are not in bounds
+     * @see #setPixel(int, int, int[], DataBuffer)
+     */
+    public int[] getPixel(int x, int y, int iArray[], DataBuffer data) {
+        if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+        int pixels[];
+        if (iArray != null) {
+           pixels = iArray;
+        } else {
+           pixels = new int [numBands];
+        }
+        int bitnum = dataBitOffset + x*pixelBitStride;
+        int element = data.getElem(y*scanlineStride + bitnum/dataElementSize);
+        int shift = dataElementSize - (bitnum & (dataElementSize-1))
+                    - pixelBitStride;
+        pixels[0] = (element >> shift) & bitMask;
+        return pixels;
+    }
+
+    /**
+     * Sets the data for a single pixel in the specified
+     * <code>DataBuffer</code> from a primitive array of type
+     * TransferType.  For a <code>MultiPixelPackedSampleModel</code>,
+     * only the first element of the array holds valid data,
+     * and the type must be the smallest of
+     * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT
+     * that can hold a single pixel.
+     * <p>
+     * The following code illustrates transferring data for one pixel from
+     * <code>DataBuffer</code> <code>db1</code>, whose storage layout is
+     * described by <code>MultiPixelPackedSampleModel</code>
+     * <code>mppsm1</code>, to <code>DataBuffer</code> <code>db2</code>,
+     * whose storage layout is described by
+     * <code>MultiPixelPackedSampleModel</code> <code>mppsm2</code>.
+     * The transfer is generally more efficient than using
+     * <code>getPixel</code> or <code>setPixel</code>.
+     * <pre>
+     *       MultiPixelPackedSampleModel mppsm1, mppsm2;
+     *       DataBufferInt db1, db2;
+     *       mppsm2.setDataElements(x, y, mppsm1.getDataElements(x, y, null,
+     *                              db1), db2);
+     * </pre>
+     * Using <code>getDataElements</code> or <code>setDataElements</code> to
+     * transfer between two <code>DataBuffer/SampleModel</code> pairs is
+     * legitimate if the <code>SampleModel</code> objects have
+     * the same number of bands, corresponding bands have the same number of
+     * bits per sample, and the TransferTypes are the same.
+     * <p>
+     * <code>obj</code> must be a primitive array of type TransferType.
+     * Otherwise, a <code>ClassCastException</code> is thrown.  An
+     * <code>ArrayIndexOutOfBoundsException</code> is thrown if the
+     * coordinates are not in bounds, or if <code>obj</code> is not large
+     * enough to hold the pixel data.
+     * @param x the X coordinate of the pixel location
+     * @param y the Y coordinate of the pixel location
+     * @param obj a primitive array containing pixel data
+     * @param data the <code>DataBuffer</code> containing the image data
+     * @see #getDataElements(int, int, Object, DataBuffer)
+     */
+    public void setDataElements(int x, int y, Object obj, DataBuffer data) {
+        if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+
+        int type = getTransferType();
+        int bitnum = dataBitOffset + x * pixelBitStride;
+        int index = y * scanlineStride + (bitnum / dataElementSize);
+        int shift = dataElementSize - (bitnum & (dataElementSize-1))
+                    - pixelBitStride;
+        int element = data.getElem(index);
+        element &= ~(bitMask << shift);
+
+        switch(type) {
+
+        case DataBuffer.TYPE_BYTE:
+
+            byte[] barray = (byte[])obj;
+            element |= ( ((int)(barray[0])&0xff) & bitMask) << shift;
+            data.setElem(index, element);
+            break;
+
+        case DataBuffer.TYPE_USHORT:
+
+            short[] sarray = (short[])obj;
+            element |= ( ((int)(sarray[0])&0xffff) & bitMask) << shift;
+            data.setElem(index, element);
+            break;
+
+        case DataBuffer.TYPE_INT:
+
+            int[] iarray = (int[])obj;
+            element |= (iarray[0] & bitMask) << shift;
+            data.setElem(index, element);
+            break;
+        }
+    }
+
+    /**
+     * Sets a pixel in the <code>DataBuffer</code> using an
+     * <code>int</code> array for input.
+     * <code>ArrayIndexOutOfBoundsException</code> is thrown if
+     * the coordinates are not in bounds.
+     * @param x the X coordinate of the pixel location
+     * @param y the Y coordinate of the pixel location
+     * @param iArray the input pixel in an <code>int</code> array
+     * @param data the <code>DataBuffer</code> containing the image data
+     * @see #getPixel(int, int, int[], DataBuffer)
+     */
+    public void setPixel(int x, int y, int[] iArray, DataBuffer data) {
+        if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+        int bitnum = dataBitOffset + x * pixelBitStride;
+        int index = y * scanlineStride + (bitnum / dataElementSize);
+        int shift = dataElementSize - (bitnum & (dataElementSize-1))
+                    - pixelBitStride;
+        int element = data.getElem(index);
+        element &= ~(bitMask << shift);
+        element |= (iArray[0] & bitMask) << shift;
+        data.setElem(index,element);
+    }
+
+    public boolean equals(Object o) {
+        if ((o == null) || !(o instanceof MultiPixelPackedSampleModel)) {
+            return false;
+        }
+
+        MultiPixelPackedSampleModel that = (MultiPixelPackedSampleModel)o;
+        return this.width == that.width &&
+            this.height == that.height &&
+            this.numBands == that.numBands &&
+            this.dataType == that.dataType &&
+            this.pixelBitStride == that.pixelBitStride &&
+            this.bitMask == that.bitMask &&
+            this.pixelsPerDataElement == that.pixelsPerDataElement &&
+            this.dataElementSize == that.dataElementSize &&
+            this.dataBitOffset == that.dataBitOffset &&
+            this.scanlineStride == that.scanlineStride;
+    }
+
+    // If we implement equals() we must also implement hashCode
+    public int hashCode() {
+        int hash = 0;
+        hash = width;
+        hash <<= 8;
+        hash ^= height;
+        hash <<= 8;
+        hash ^= numBands;
+        hash <<= 8;
+        hash ^= dataType;
+        hash <<= 8;
+        hash ^= pixelBitStride;
+        hash <<= 8;
+        hash ^= bitMask;
+        hash <<= 8;
+        hash ^= pixelsPerDataElement;
+        hash <<= 8;
+        hash ^= dataElementSize;
+        hash <<= 8;
+        hash ^= dataBitOffset;
+        hash <<= 8;
+        hash ^= scanlineStride;
+        return hash;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/awt/image/Raster.java	Thu Apr 10 16:28:45 2008 -0700
@@ -0,0 +1,1777 @@
+/*
+ * Portions Copyright 1997-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* ****************************************************************
+ ******************************************************************
+ ******************************************************************
+ *** COPYRIGHT (c) Eastman Kodak Company, 1997
+ *** As  an unpublished  work pursuant to Title 17 of the United
+ *** States Code.  All rights reserved.
+ ******************************************************************
+ ******************************************************************
+ ******************************************************************/
+
+
+package java.awt.image;
+import java.awt.Rectangle;
+import java.awt.Point;
+
+import sun.awt.image.ByteInterleavedRaster;
+import sun.awt.image.ShortInterleavedRaster;
+import sun.awt.image.IntegerInterleavedRaster;
+import sun.awt.image.ByteBandedRaster;
+import sun.awt.image.ShortBandedRaster;
+import sun.awt.image.BytePackedRaster;
+import sun.awt.image.SunWritableRaster;
+
+/**
+ * A class representing a rectangular array of pixels.  A Raster
+ * encapsulates a DataBuffer that stores the sample values and a
+ * SampleModel that describes how to locate a given sample value in a
+ * DataBuffer.
+ * <p>
+ * A Raster defines values for pixels occupying a particular
+ * rectangular area of the plane, not necessarily including (0, 0).
+ * The rectangle, known as the Raster's bounding rectangle and
+ * available by means of the getBounds method, is defined by minX,
+ * minY, width, and height values.  The minX and minY values define
+ * the coordinate of the upper left corner of the Raster.  References
+ * to pixels outside of the bounding rectangle may result in an
+ * exception being thrown, or may result in references to unintended
+ * elements of the Raster's associated DataBuffer.  It is the user's
+ * responsibility to avoid accessing such pixels.
+ * <p>
+ * A SampleModel describes how samples of a Raster
+ * are stored in the primitive array elements of a DataBuffer.
+ * Samples may be stored one per data element, as in a
+ * PixelInterleavedSampleModel or BandedSampleModel, or packed several to
+ * an element, as in a SinglePixelPackedSampleModel or
+ * MultiPixelPackedSampleModel.  The SampleModel is also
+ * controls whether samples are sign extended, allowing unsigned
+ * data to be stored in signed Java data types such as byte, short, and
+ * int.
+ * <p>
+ * Although a Raster may live anywhere in the plane, a SampleModel
+ * makes use of a simple coordinate system that starts at (0, 0).  A
+ * Raster therefore contains a translation factor that allows pixel
+ * locations to be mapped between the Raster's coordinate system and
+ * that of the SampleModel.  The translation from the SampleModel
+ * coordinate system to that of the Raster may be obtained by the
+ * getSampleModelTranslateX and getSampleModelTranslateY methods.
+ * <p>
+ * A Raster may share a DataBuffer with another Raster either by
+ * explicit construction or by the use of the createChild and
+ * createTranslatedChild methods.  Rasters created by these methods
+ * can return a reference to the Raster they were created from by
+ * means of the getParent method.  For a Raster that was not
+ * constructed by means of a call to createTranslatedChild or
+ * createChild, getParent will return null.
+ * <p>
+ * The createTranslatedChild method returns a new Raster that
+ * shares all of the data of the current Raster, but occupies a
+ * bounding rectangle of the same width and height but with a
+ * different starting point.  For example, if the parent Raster
+ * occupied the region (10, 10) to (100, 100), and the translated
+ * Raster was defined to start at (50, 50), then pixel (20, 20) of the
+ * parent and pixel (60, 60) of the child occupy the same location in
+ * the DataBuffer shared by the two Rasters.  In the first case, (-10,
+ * -10) should be added to a pixel coordinate to obtain the
+ * corresponding SampleModel coordinate, and in the second case (-50,
+ * -50) should be added.
+ * <p>
+ * The translation between a parent and child Raster may be
+ * determined by subtracting the child's sampleModelTranslateX and
+ * sampleModelTranslateY values from those of the parent.
+ * <p>
+ * The createChild method may be used to create a new Raster
+ * occupying only a subset of its parent's bounding rectangle
+ * (with the same or a translated coordinate system) or
+ * with a subset of the bands of its parent.
+ * <p>
+ * All constructors are protected.  The correct way to create a
+ * Raster is to use one of the static create methods defined in this
+ * class.  These methods create instances of Raster that use the
+ * standard Interleaved, Banded, and Packed SampleModels and that may
+ * be processed more efficiently than a Raster created by combining
+ * an externally generated SampleModel and DataBuffer.
+ * @see java.awt.image.DataBuffer
+ * @see java.awt.image.SampleModel
+ * @see java.awt.image.PixelInterleavedSampleModel
+ * @see java.awt.image.BandedSampleModel
+ * @see java.awt.image.SinglePixelPackedSampleModel
+ * @see java.awt.image.MultiPixelPackedSampleModel
+ */
+public class Raster {
+
+    /**
+     * The SampleModel that describes how pixels from this Raster
+     * are stored in the DataBuffer.
+     */
+    protected SampleModel sampleModel;
+
+    /** The DataBuffer that stores the image data. */
+    protected DataBuffer dataBuffer;
+
+    /** The X coordinate of the upper-left pixel of this Raster. */
+    protected int minX;
+
+    /** The Y coordinate of the upper-left pixel of this Raster. */
+    protected int minY;
+
+    /** The width of this Raster. */
+    protected int width;
+
+    /** The height of this Raster. */
+    protected int height;
+
+    /**
+     * The X translation from the coordinate space of the
+     * Raster's SampleModel to that of the Raster.
+     */
+    protected int sampleModelTranslateX;
+
+    /**
+     * The Y translation from the coordinate space of the
+     * Raster's SampleModel to that of the Raster.
+     */
+    protected int sampleModelTranslateY;
+
+    /** The number of bands in the Raster. */
+    protected int numBands;
+
+    /** The number of DataBuffer data elements per pixel. */
+    protected int numDataElements;
+
+    /** The parent of this Raster, or null. */
+    protected Raster parent;
+
+    static private native void initIDs();
+    static {
+        ColorModel.loadLibraries();
+        initIDs();
+    }
+
+    /**
+     * Creates a Raster based on a PixelInterleavedSampleModel with the
+     * specified data type, width, height, and number of bands.
+     *
+     * <p> The upper left corner of the Raster is given by the
+     * location argument.  If location is null, (0, 0) will be used.
+     * The dataType parameter should be one of the enumerated values
+     * defined in the DataBuffer class.
+     *
+     * <p> Note that interleaved <code>DataBuffer.TYPE_INT</code>
+     * Rasters are not supported.  To create a 1-band Raster of type
+     * <code>DataBuffer.TYPE_INT</code>, use
+     * Raster.createPackedRaster().
+     * <p> The only dataTypes supported currently are TYPE_BYTE
+     * and TYPE_USHORT.
+     * @param dataType  the data type for storing samples
+     * @param w         the width in pixels of the image data
+     * @param h         the height in pixels of the image data
+     * @param bands     the number of bands
+     * @param location  the upper-left corner of the <code>Raster</code>
+     * @return a WritableRaster object with the specified data type,
+     *         width, height and number of bands.
+     * @throws RasterFormatException if <code>w</code> or <code>h</code>
+     *         is less than or equal to zero, or computing either
+     *         <code>location.x + w</code> or
+     *         <code>location.y + h</code> results in integer
+     *         overflow
+     */
+    public static WritableRaster createInterleavedRaster(int dataType,
+                                                         int w, int h,
+                                                         int bands,
+                                                         Point location) {
+        int[] bandOffsets = new int[bands];
+        for (int i = 0; i < bands; i++) {
+            bandOffsets[i] = i;
+        }
+        return createInterleavedRaster(dataType, w, h, w*bands, bands,
+                                       bandOffsets, location);
+    }
+
+    /**
+     * Creates a Raster based on a PixelInterleavedSampleModel with the
+     * specified data type, width, height, scanline stride, pixel
+     * stride, and band offsets.  The number of bands is inferred from
+     * bandOffsets.length.
+     *
+     * <p> The upper left corner of the Raster is given by the
+     * location argument.  If location is null, (0, 0) will be used.
+     * The dataType parameter should be one of the enumerated values
+     * defined in the DataBuffer class.
+     *
+     * <p> Note that interleaved <code>DataBuffer.TYPE_INT</code>
+     * Rasters are not supported.  To create a 1-band Raster of type
+     * <code>DataBuffer.TYPE_INT</code>, use
+     * Raster.createPackedRaster().
+     * <p> The only dataTypes supported currently are TYPE_BYTE
+     * and TYPE_USHORT.
+     * @param dataType  the data type for storing samples
+     * @param w         the width in pixels of the image data
+     * @param h         the height in pixels of the image data
+     * @param scanlineStride the line stride of the image data
+     * @param pixelStride the pixel stride of the image data
+     * @param bandOffsets the offsets of all bands
+     * @param location  the upper-left corner of the <code>Raster</code>
+     * @return a WritableRaster object with the specified data type,
+     *         width, height, scanline stride, pixel stride and band
+     *         offsets.
+     * @throws RasterFormatException if <code>w</code> or <code>h</code>
+     *         is less than or equal to zero, or computing either
+     *         <code>location.x + w</code> or
+     *         <code>location.y + h</code> results in integer
+     *         overflow
+     * @throws IllegalArgumentException if <code>dataType</code> is not
+     *         one of the supported data types, which are
+     *         <code>DataBuffer.TYPE_BYTE</code>, or
+     *         <code>DataBuffer.TYPE_USHORT</code>.
+     */
+    public static WritableRaster createInterleavedRaster(int dataType,
+                                                         int w, int h,
+                                                         int scanlineStride,
+                                                         int pixelStride,
+                                                         int bandOffsets[],
+                                                         Point location) {
+        DataBuffer d;
+        int bands = bandOffsets.length;
+
+        int maxBandOff = bandOffsets[0];
+        for (int i=1; i < bands; i++) {
+            if (bandOffsets[i] > maxBandOff) {
+                maxBandOff = bandOffsets[i];
+            }
+        }
+        int size = maxBandOff + scanlineStride*(h-1) + pixelStride*(w-1) + 1;
+        switch(dataType) {
+        case DataBuffer.TYPE_BYTE:
+            d = new DataBufferByte(size);
+            break;
+
+        case DataBuffer.TYPE_USHORT:
+            d = new DataBufferUShort(size);
+            break;
+
+        default:
+            throw new IllegalArgumentException("Unsupported data type " +
+                                                dataType);
+        }
+
+        return createInterleavedRaster(d, w, h, scanlineStride,
+                                       pixelStride, bandOffsets, location);
+    }
+
+    /**
+     * Creates a Raster based on a BandedSampleModel with the
+     * specified data type, width, height, and number of bands.
+     *
+     * <p> The upper left corner of the Raster is given by the
+     * location argument.  If location is null, (0, 0) will be used.
+     * The dataType parameter should be one of the enumerated values
+     * defined in the DataBuffer class.
+     *
+     * <p> The only dataTypes supported currently are TYPE_BYTE, TYPE_USHORT,
+     * and TYPE_INT.
+     * @param dataType  the data type for storing samples
+     * @param w         the width in pixels of the image data
+     * @param h         the height in pixels of the image data
+     * @param bands     the number of bands
+     * @param location  the upper-left corner of the <code>Raster</code>
+     * @return a WritableRaster object with the specified data type,
+     *         width, height and number of bands.
+     * @throws RasterFormatException if <code>w</code> or <code>h</code>
+     *         is less than or equal to zero, or computing either
+     *         <code>location.x + w</code> or
+     *         <code>location.y + h</code> results in integer
+     *         overflow
+     * @throws ArrayIndexOutOfBoundsException if <code>bands</code>
+     *         is less than 1
+     */
+    public static WritableRaster createBandedRaster(int dataType,
+                                                    int w, int h,
+                                                    int bands,
+                                                    Point location) {
+        if (bands < 1) {
+            throw new ArrayIndexOutOfBoundsException("Number of bands ("+
+                                                     bands+") must"+
+                                                     " be greater than 0");
+        }
+        int[] bankIndices = new int[bands];
+        int[] bandOffsets = new int[bands];
+        for (int i = 0; i < bands; i++) {
+            bankIndices[i] = i;
+            bandOffsets[i] = 0;
+        }
+
+        return createBandedRaster(dataType, w, h, w,
+                                  bankIndices, bandOffsets,
+                                  location);
+    }
+
+    /**
+     * Creates a Raster based on a BandedSampleModel with the
+     * specified data type, width, height, scanline stride, bank
+     * indices and band offsets.  The number of bands is inferred from
+     * bankIndices.length and bandOffsets.length, which must be the
+     * same.
+     *
+     * <p> The upper left corner of the Raster is given by the
+     * location argument.  The dataType parameter should be one of the
+     * enumerated values defined in the DataBuffer class.
+     *
+     * <p> The only dataTypes supported currently are TYPE_BYTE, TYPE_USHORT,
+     * and TYPE_INT.
+     * @param dataType  the data type for storing samples
+     * @param w         the width in pixels of the image data
+     * @param h         the height in pixels of the image data
+     * @param scanlineStride the line stride of the image data
+     * @param bankIndices the bank indices for each band
+     * @param bandOffsets the offsets of all bands
+     * @param location  the upper-left corner of the <code>Raster</code>
+     * @return a WritableRaster object with the specified data type,
+     *         width, height, scanline stride, bank indices and band
+     *         offsets.
+     * @throws RasterFormatException if <code>w</code> or <code>h</code>
+     *         is less than or equal to zero, or computing either
+     *         <code>location.x + w</code> or
+     *         <code>location.y + h</code> results in integer
+     *         overflow
+     * @throws IllegalArgumentException if <code>dataType</code> is not
+     *         one of the supported data types, which are
+     *         <code>DataBuffer.TYPE_BYTE</code>,
+     *         <code>DataBuffer.TYPE_USHORT</code>
+     *         or <code>DataBuffer.TYPE_INT</code>
+     * @throws ArrayIndexOutOfBoundsException if <code>bankIndices</code>
+     *         or <code>bandOffsets</code> is <code>null</code>
+     */
+    public static WritableRaster createBandedRaster(int dataType,
+                                                    int w, int h,
+                                                    int scanlineStride,
+                                                    int bankIndices[],
+                                                    int bandOffsets[],
+                                                    Point location) {
+        DataBuffer d;
+        int bands = bandOffsets.length;
+
+        if (bankIndices == null) {
+            throw new
+                ArrayIndexOutOfBoundsException("Bank indices array is null");
+        }
+        if (bandOffsets == null) {
+            throw new
+                ArrayIndexOutOfBoundsException("Band offsets array is null");
+        }
+
+        // Figure out the #banks and the largest band offset
+        int maxBank = bankIndices[0];
+        int maxBandOff = bandOffsets[0];
+        for (int i = 1; i < bands; i++) {
+            if (bankIndices[i] > maxBank) {
+                maxBank = bankIndices[i];
+            }
+            if (bandOffsets[i] > maxBandOff) {
+                maxBandOff = bandOffsets[i];
+            }
+        }
+        int banks = maxBank + 1;
+        int size = maxBandOff + scanlineStride*(h-1) + (w-1) + 1;
+
+        switch(dataType) {
+        case DataBuffer.TYPE_BYTE:
+            d = new DataBufferByte(size, banks);
+            break;
+
+        case DataBuffer.TYPE_USHORT:
+            d = new DataBufferUShort(size, banks);
+            break;
+
+        case DataBuffer.TYPE_INT:
+            d = new DataBufferInt(size, banks);
+            break;
+
+        default:
+            throw new IllegalArgumentException("Unsupported data type " +
+                                                dataType);
+        }
+
+        return createBandedRaster(d, w, h, scanlineStride,
+                                  bankIndices, bandOffsets, location);
+    }
+
+    /**
+     * Creates a Raster based on a SinglePixelPackedSampleModel with
+     * the specified data type, width, height, and band masks.
+     * The number of bands is inferred from bandMasks.length.
+     *
+     * <p> The upper left corner of the Raster is given by the
+     * location argument.  If location is null, (0, 0) will be used.
+     * The dataType parameter should be one of the enumerated values
+     * defined in the DataBuffer class.
+     *
+     * <p> The only dataTypes supported currently are TYPE_BYTE, TYPE_USHORT,
+     * and TYPE_INT.
+     * @param dataType  the data type for storing samples
+     * @param w         the width in pixels of the image data
+     * @param h         the height in pixels of the image data
+     * @param bandMasks an array containing an entry for each band
+     * @param location  the upper-left corner of the <code>Raster</code>
+     * @return a WritableRaster object with the specified data type,
+     *         width, height, and band masks.
+     * @throws RasterFormatException if <code>w</code> or <code>h</code>
+     *         is less than or equal to zero, or computing either
+     *         <code>location.x + w</code> or
+     *         <code>location.y + h</code> results in integer
+     *         overflow
+     * @throws IllegalArgumentException if <code>dataType</code> is not
+     *         one of the supported data types, which are
+     *         <code>DataBuffer.TYPE_BYTE</code>,
+     *         <code>DataBuffer.TYPE_USHORT</code>
+     *         or <code>DataBuffer.TYPE_INT</code>
+     */
+    public static WritableRaster createPackedRaster(int dataType,
+                                                    int w, int h,
+                                                    int bandMasks[],
+                                                    Point location) {
+        DataBuffer d;
+
+        switch(dataType) {
+        case DataBuffer.TYPE_BYTE:
+            d = new DataBufferByte(w*h);
+            break;
+
+        case DataBuffer.TYPE_USHORT:
+            d = new DataBufferUShort(w*h);
+            break;
+
+        case DataBuffer.TYPE_INT:
+            d = new DataBufferInt(w*h);
+            break;
+
+        default:
+            throw new IllegalArgumentException("Unsupported data type " +
+                                                dataType);
+        }
+
+        return createPackedRaster(d, w, h, w, bandMasks, location);
+    }
+
+    /**
+     * Creates a Raster based on a packed SampleModel with the
+     * specified data type, width, height, number of bands, and bits
+     * per band.  If the number of bands is one, the SampleModel will
+     * be a MultiPixelPackedSampleModel.
+     *
+     * <p> If the number of bands is more than one, the SampleModel
+     * will be a SinglePixelPackedSampleModel, with each band having
+     * bitsPerBand bits.  In either case, the requirements on dataType
+     * and bitsPerBand imposed by the corresponding SampleModel must
+     * be met.
+     *
+     * <p> The upper left corner of the Raster is given by the
+     * location argument.  If location is null, (0, 0) will be used.
+     * The dataType parameter should be one of the enumerated values
+     * defined in the DataBuffer class.
+     *
+     * <p> The only dataTypes supported currently are TYPE_BYTE, TYPE_USHORT,
+     * and TYPE_INT.
+     * @param dataType  the data type for storing samples
+     * @param w         the width in pixels of the image data
+     * @param h         the height in pixels of the image data
+     * @param bands     the number of bands
+     * @param bitsPerBand the number of bits per band
+     * @param location  the upper-left corner of the <code>Raster</code>
+     * @return a WritableRaster object with the specified data type,
+     *         width, height, number of bands, and bits per band.
+     * @throws RasterFormatException if <code>w</code> or <code>h</code>
+     *         is less than or equal to zero, or computing either
+     *         <code>location.x + w</code> or
+     *         <code>location.y + h</code> results in integer
+     *         overflow
+     * @throws IllegalArgumentException if the product of
+     *         <code>bitsPerBand</code> and <code>bands</code> is
+     *         greater than the number of bits held by
+     *         <code>dataType</code>
+     * @throws IllegalArgumentException if <code>bitsPerBand</code> or
+     *         <code>bands</code> is not greater than zero
+     * @throws IllegalArgumentException if <code>dataType</code> is not
+     *         one of the supported data types, which are
+     *         <code>DataBuffer.TYPE_BYTE</code>,
+     *         <code>DataBuffer.TYPE_USHORT</code>
+     *         or <code>DataBuffer.TYPE_INT</code>
+     */
+    public static WritableRaster createPackedRaster(int dataType,
+                                                    int w, int h,
+                                                    int bands,
+                                                    int bitsPerBand,
+                                                    Point location) {
+        DataBuffer d;
+
+        if (bands <= 0) {
+            throw new IllegalArgumentException("Number of bands ("+bands+
+                                               ") must be greater than 0");
+        }
+
+        if (bitsPerBand <= 0) {
+            throw new IllegalArgumentException("Bits per band ("+bitsPerBand+
+                                               ") must be greater than 0");
+        }
+
+        if (bands != 1) {
+            int[] masks = new int[bands];
+            int mask = (1 << bitsPerBand) - 1;
+            int shift = (bands-1)*bitsPerBand;
+
+            /* Make sure the total mask size will fit in the data type */
+            if (shift+bitsPerBand > DataBuffer.getDataTypeSize(dataType)) {
+                throw new IllegalArgumentException("bitsPerBand("+
+                                                   bitsPerBand+") * bands is "+
+                                                   " greater than data type "+
+                                                   "size.");
+            }
+            switch(dataType) {
+            case DataBuffer.TYPE_BYTE:
+            case DataBuffer.TYPE_USHORT:
+            case DataBuffer.TYPE_INT:
+                break;
+            default:
+                throw new IllegalArgumentException("Unsupported data type " +
+                                                    dataType);
+            }
+
+            for (int i = 0; i < bands; i++) {
+                masks[i] = mask << shift;
+                shift = shift - bitsPerBand;
+            }
+
+            return createPackedRaster(dataType, w, h, masks, location);
+        }
+        else {
+            double fw = w;
+            switch(dataType) {
+            case DataBuffer.TYPE_BYTE:
+                d = new DataBufferByte((int)(Math.ceil(fw/(8/bitsPerBand)))*h);
+                break;
+
+            case DataBuffer.TYPE_USHORT:
+                d = new DataBufferUShort((int)(Math.ceil(fw/(16/bitsPerBand)))*h);
+                break;
+
+            case DataBuffer.TYPE_INT:
+                d = new DataBufferInt((int)(Math.ceil(fw/(32/bitsPerBand)))*h);
+                break;
+
+            default:
+                throw new IllegalArgumentException("Unsupported data type " +
+                                                   dataType);
+            }
+
+            return createPackedRaster(d, w, h, bitsPerBand, location);
+        }
+    }
+
+    /**
+     * Creates a Raster based on a PixelInterleavedSampleModel with the
+     * specified DataBuffer, width, height, scanline stride, pixel
+     * stride, and band offsets.  The number of bands is inferred from
+     * bandOffsets.length.  The upper left corner of the Raster
+     * is given by the location argument.  If location is null, (0, 0)
+     * will be used.
+     * <p> Note that interleaved <code>DataBuffer.TYPE_INT</code>
+     * Rasters are not supported.  To create a 1-band Raster of type
+     * <code>DataBuffer.TYPE_INT</code>, use
+     * Raster.createPackedRaster().
+     * @param dataBuffer the <code>DataBuffer</code> that contains the
+     *        image data
+     * @param w         the width in pixels of the image data
+     * @param h         the height in pixels of the image data
+     * @param scanlineStride the line stride of the image data
+     * @param pixelStride the pixel stride of the image data
+     * @param bandOffsets the offsets of all bands
+     * @param location  the upper-left corner of the <code>Raster</code>
+     * @return a WritableRaster object with the specified
+     *         <code>DataBuffer</code>, width, height, scanline stride,
+     *         pixel stride and band offsets.
+     * @throws RasterFormatException if <code>w</code> or <code>h</code>
+     *         is less than or equal to zero, or computing either
+     *         <code>location.x + w</code> or
+     *         <code>location.y + h</code> results in integer
+     *         overflow
+     * @throws IllegalArgumentException if <code>dataType</code> is not
+     *         one of the supported data types, which are
+     *         <code>DataBuffer.TYPE_BYTE</code>,
+     *         <code>DataBuffer.TYPE_USHORT</code>
+     * @throws RasterFormatException if <code>dataBuffer</code> has more
+     *         than one bank.
+     * @throws NullPointerException if <code>dataBuffer</code> is null
+     */
+    public static WritableRaster createInterleavedRaster(DataBuffer dataBuffer,
+                                                         int w, int h,
+                                                         int scanlineStride,
+                                                         int pixelStride,
+                                                         int bandOffsets[],
+                                                         Point location) {
+        if (dataBuffer == null) {
+            throw new NullPointerException("DataBuffer cannot be null");
+        }
+        if (location == null) {
+            location = new Point(0, 0);
+        }
+        int dataType = dataBuffer.getDataType();
+
+        PixelInterleavedSampleModel csm =
+            new PixelInterleavedSampleModel(dataType, w, h,
+                                            pixelStride,
+                                            scanlineStride,
+                                            bandOffsets);
+        switch(dataType) {
+        case DataBuffer.TYPE_BYTE:
+            return new ByteInterleavedRaster(csm, dataBuffer, location);
+
+        case DataBuffer.TYPE_USHORT:
+            return new ShortInterleavedRaster(csm, dataBuffer, location);
+
+        default:
+            throw new IllegalArgumentException("Unsupported data type " +
+                                                dataType);
+        }
+    }
+
+    /**
+     * Creates a Raster based on a BandedSampleModel with the
+     * specified DataBuffer, width, height, scanline stride, bank
+     * indices, and band offsets.  The number of bands is inferred
+     * from bankIndices.length and bandOffsets.length, which must be
+     * the same.  The upper left corner of the Raster is given by the
+     * location argument.  If location is null, (0, 0) will be used.
+     * @param dataBuffer the <code>DataBuffer</code> that contains the
+     *        image data
+     * @param w         the width in pixels of the image data
+     * @param h         the height in pixels of the image data
+     * @param scanlineStride the line stride of the image data
+     * @param bankIndices the bank indices for each band
+     * @param bandOffsets the offsets of all bands
+     * @param location  the upper-left corner of the <code>Raster</code>
+     * @return a WritableRaster object with the specified
+     *         <code>DataBuffer</code>, width, height, scanline stride,
+     *         bank indices and band offsets.
+     * @throws RasterFormatException if <code>w</code> or <code>h</code>
+     *         is less than or equal to zero, or computing either
+     *         <code>location.x + w</code> or
+     *         <code>location.y + h</code> results in integer
+     *         overflow
+     * @throws IllegalArgumentException if <code>dataType</code> is not
+     *         one of the supported data types, which are
+     *         <code>DataBuffer.TYPE_BYTE</code>,
+     *         <code>DataBuffer.TYPE_USHORT</code>
+     *         or <code>DataBuffer.TYPE_INT</code>
+     * @throws NullPointerException if <code>dataBuffer</code> is null
+     */
+    public static WritableRaster createBandedRaster(DataBuffer dataBuffer,
+                                                    int w, int h,
+                                                    int scanlineStride,
+                                                    int bankIndices[],
+                                                    int bandOffsets[],
+                                                    Point location) {
+        if (dataBuffer == null) {
+            throw new NullPointerException("DataBuffer cannot be null");
+        }
+        if (location == null) {
+           location = new Point(0,0);
+        }
+        int dataType = dataBuffer.getDataType();
+
+        int bands = bankIndices.length;
+        if (bandOffsets.length != bands) {
+            throw new IllegalArgumentException(
+                                   "bankIndices.length != bandOffsets.length");
+        }
+
+        BandedSampleModel bsm =
+            new BandedSampleModel(dataType, w, h,
+                                  scanlineStride,
+                                  bankIndices, bandOffsets);
+
+        switch(dataType) {
+        case DataBuffer.TYPE_BYTE:
+            return new ByteBandedRaster(bsm, dataBuffer, location);
+
+        case DataBuffer.TYPE_USHORT:
+            return new ShortBandedRaster(bsm, dataBuffer, location);
+
+        case DataBuffer.TYPE_INT:
+            return new SunWritableRaster(bsm, dataBuffer, location);
+
+        default:
+            throw new IllegalArgumentException("Unsupported data type " +
+                                                dataType);
+        }
+    }
+
+    /**
+     * Creates a Raster based on a SinglePixelPackedSampleModel with
+     * the specified DataBuffer, width, height, scanline stride, and
+     * band masks.  The number of bands is inferred from bandMasks.length.
+     * The upper left corner of the Raster is given by
+     * the location argument.  If location is null, (0, 0) will be used.
+     * @param dataBuffer the <code>DataBuffer</code> that contains the
+     *        image data
+     * @param w         the width in pixels of the image data
+     * @param h         the height in pixels of the image data
+     * @param scanlineStride the line stride of the image data
+     * @param bandMasks an array containing an entry for each band
+     * @param location  the upper-left corner of the <code>Raster</code>
+     * @return a WritableRaster object with the specified
+     *         <code>DataBuffer</code>, width, height, scanline stride,
+     *         and band masks.
+     * @throws RasterFormatException if <code>w</code> or <code>h</code>
+     *         is less than or equal to zero, or computing either
+     *         <code>location.x + w</code> or
+     *         <code>location.y + h</code> results in integer
+     *         overflow
+     * @throws IllegalArgumentException if <code>dataType</code> is not
+     *         one of the supported data types, which are
+     *         <code>DataBuffer.TYPE_BYTE</code>,
+     *         <code>DataBuffer.TYPE_USHORT</code>
+     *         or <code>DataBuffer.TYPE_INT</code>
+     * @throws RasterFormatException if <code>dataBuffer</code> has more
+     *         than one bank.
+     * @throws NullPointerException if <code>dataBuffer</code> is null
+     */
+    public static WritableRaster createPackedRaster(DataBuffer dataBuffer,
+                                                    int w, int h,
+                                                    int scanlineStride,
+                                                    int bandMasks[],
+                                                    Point location) {
+        if (dataBuffer == null) {
+            throw new NullPointerException("DataBuffer cannot be null");
+        }
+        if (location == null) {
+           location = new Point(0,0);
+        }
+        int dataType = dataBuffer.getDataType();
+
+        SinglePixelPackedSampleModel sppsm =
+            new SinglePixelPackedSampleModel(dataType, w, h, scanlineStride,
+                                             bandMasks);
+
+        switch(dataType) {
+        case DataBuffer.TYPE_BYTE:
+            return new ByteInterleavedRaster(sppsm, dataBuffer, location);
+
+        case DataBuffer.TYPE_USHORT:
+            return new ShortInterleavedRaster(sppsm, dataBuffer, location);
+
+        case DataBuffer.TYPE_INT:
+            return new IntegerInterleavedRaster(sppsm, dataBuffer, location);
+
+        default:
+            throw new IllegalArgumentException("Unsupported data type " +
+                                                dataType);
+        }
+    }
+
+    /**
+     * Creates a Raster based on a MultiPixelPackedSampleModel with the
+     * specified DataBuffer, width, height, and bits per pixel.  The upper
+     * left corner of the Raster is given by the location argument.  If
+     * location is null, (0, 0) will be used.
+     * @param dataBuffer the <code>DataBuffer</code> that contains the
+     *        image data
+     * @param w         the width in pixels of the image data
+     * @param h         the height in pixels of the image data
+     * @param bitsPerPixel the number of bits for each pixel
+     * @param location  the upper-left corner of the <code>Raster</code>
+     * @return a WritableRaster object with the specified
+     *         <code>DataBuffer</code>, width, height, and
+     *         bits per pixel.
+     * @throws RasterFormatException if <code>w</code> or <code>h</code>
+     *         is less than or equal to zero, or computing either
+     *         <code>location.x + w</code> or
+     *         <code>location.y + h</code> results in integer
+     *         overflow
+     * @throws IllegalArgumentException if <code>dataType</code> is not
+     *         one of the supported data types, which are
+     *         <code>DataBuffer.TYPE_BYTE</code>,
+     *         <code>DataBuffer.TYPE_USHORT</code>
+     *         or <code>DataBuffer.TYPE_INT</code>
+     * @throws RasterFormatException if <code>dataBuffer</code> has more
+     *         than one bank.
+     * @throws NullPointerException if <code>dataBuffer</code> is null
+     */
+    public static WritableRaster createPackedRaster(DataBuffer dataBuffer,
+                                                    int w, int h,
+                                                    int bitsPerPixel,
+                                                    Point location) {
+        if (dataBuffer == null) {
+            throw new NullPointerException("DataBuffer cannot be null");
+        }
+        if (location == null) {
+           location = new Point(0,0);
+        }
+        int dataType = dataBuffer.getDataType();
+
+        if (dataType != DataBuffer.TYPE_BYTE &&
+            dataType != DataBuffer.TYPE_USHORT &&
+            dataType != DataBuffer.TYPE_INT) {
+            throw new IllegalArgumentException("Unsupported data type " +
+                                               dataType);
+        }
+
+        if (dataBuffer.getNumBanks() != 1) {
+            throw new
+                RasterFormatException("DataBuffer for packed Rasters"+
+                                      " must only have 1 bank.");
+        }
+
+        MultiPixelPackedSampleModel mppsm =
+                new MultiPixelPackedSampleModel(dataType, w, h, bitsPerPixel);
+
+        if (dataType == DataBuffer.TYPE_BYTE &&
+            (bitsPerPixel == 1 || bitsPerPixel == 2 || bitsPerPixel == 4)) {
+            return new BytePackedRaster(mppsm, dataBuffer, location);
+        } else {
+            return new SunWritableRaster(mppsm, dataBuffer, location);
+        }
+    }
+
+
+    /**
+     *  Creates a Raster with the specified SampleModel and DataBuffer.
+     *  The upper left corner of the Raster is given by the location argument.
+     *  If location is null, (0, 0) will be used.
+     *  @param sm the specified <code>SampleModel</code>
+     *  @param db the specified <code>DataBuffer</code>
+     *  @param location the upper-left corner of the <code>Raster</code>
+     *  @return a <code>Raster</code> with the specified
+     *          <code>SampleModel</code>, <code>DataBuffer</code>, and
+     *          location.
+     * @throws RasterFormatException if computing either
+     *         <code>location.x + sm.getWidth()</code> or
+     *         <code>location.y + sm.getHeight()</code> results in integer
+     *         overflow
+     * @throws RasterFormatException if <code>db</code> has more
+     *         than one bank and <code>sm</code> is a
+     *         PixelInterleavedSampleModel, SinglePixelPackedSampleModel,
+     *         or MultiPixelPackedSampleModel.
+     *  @throws NullPointerException if either SampleModel or DataBuffer is
+     *          null
+     */
+    public static Raster createRaster(SampleModel sm,
+                                      DataBuffer db,
+                                      Point location) {
+        if ((sm == null) || (db == null)) {
+            throw new NullPointerException("SampleModel and DataBuffer cannot be null");
+        }
+
+        if (location == null) {
+           location = new Point(0,0);
+        }
+        int dataType = sm.getDataType();
+
+        if (sm instanceof PixelInterleavedSampleModel) {
+            switch(dataType) {
+                case DataBuffer.TYPE_BYTE:
+                    return new ByteInterleavedRaster(sm, db, location);
+
+                case DataBuffer.TYPE_USHORT:
+                    return new ShortInterleavedRaster(sm, db, location);
+            }
+        } else if (sm instanceof SinglePixelPackedSampleModel) {
+            switch(dataType) {
+                case DataBuffer.TYPE_BYTE:
+                    return new ByteInterleavedRaster(sm, db, location);
+
+                case DataBuffer.TYPE_USHORT:
+                    return new ShortInterleavedRaster(sm, db, location);
+
+                case DataBuffer.TYPE_INT:
+                    return new IntegerInterleavedRaster(sm, db, location);
+            }
+        } else if (sm instanceof MultiPixelPackedSampleModel &&
+                   dataType == DataBuffer.TYPE_BYTE &&
+                   sm.getSampleSize(0) < 8) {
+            return new BytePackedRaster(sm, db, location);
+        }
+
+        // we couldn't do anything special - do the generic thing
+
+        return new Raster(sm,db,location);
+    }
+
+    /**
+     *  Creates a WritableRaster with the specified SampleModel.
+     *  The upper left corner of the Raster is given by the location argument.
+     *  If location is null, (0, 0) will be used.
+     *  @param sm the specified <code>SampleModel</code>
+     *  @param location the upper-left corner of the
+     *         <code>WritableRaster</code>
+     *  @return a <code>WritableRaster</code> with the specified
+     *          <code>SampleModel</code> and location.
+     *  @throws RasterFormatException if computing either
+     *          <code>location.x + sm.getWidth()</code> or
+     *          <code>location.y + sm.getHeight()</code> results in integer
+     *          overflow
+     */
+    public static WritableRaster createWritableRaster(SampleModel sm,
+                                                      Point location) {
+        if (location == null) {
+           location = new Point(0,0);
+        }
+
+        return createWritableRaster(sm, sm.createDataBuffer(), location);
+    }
+
+    /**
+     *  Creates a WritableRaster with the specified SampleModel and DataBuffer.
+     *  The upper left corner of the Raster is given by the location argument.
+     *  If location is null, (0, 0) will be used.
+     *  @param sm the specified <code>SampleModel</code>
+     *  @param db the specified <code>DataBuffer</code>
+     *  @param location the upper-left corner of the
+     *         <code>WritableRaster</code>
+     *  @return a <code>WritableRaster</code> with the specified
+     *          <code>SampleModel</code>, <code>DataBuffer</code>, and
+     *          location.
+     * @throws RasterFormatException if computing either
+     *         <code>location.x + sm.getWidth()</code> or
+     *         <code>location.y + sm.getHeight()</code> results in integer
+     *         overflow
+     * @throws RasterFormatException if <code>db</code> has more
+     *         than one bank and <code>sm</code> is a
+     *         PixelInterleavedSampleModel, SinglePixelPackedSampleModel,
+     *         or MultiPixelPackedSampleModel.
+     * @throws NullPointerException if either SampleModel or DataBuffer is null
+     */
+    public static WritableRaster createWritableRaster(SampleModel sm,
+                                                      DataBuffer db,
+                                                      Point location) {
+        if ((sm == null) || (db == null)) {
+            throw new NullPointerException("SampleModel and DataBuffer cannot be null");
+        }
+        if (location == null) {
+           location = new Point(0,0);
+        }
+
+        int dataType = sm.getDataType();
+
+        if (sm instanceof PixelInterleavedSampleModel) {
+            switch(dataType) {
+                case DataBuffer.TYPE_BYTE:
+                    return new ByteInterleavedRaster(sm, db, location);
+
+                case DataBuffer.TYPE_USHORT:
+                    return new ShortInterleavedRaster(sm, db, location);
+            }
+        } else if (sm instanceof SinglePixelPackedSampleModel) {
+            switch(dataType) {
+                case DataBuffer.TYPE_BYTE:
+                    return new ByteInterleavedRaster(sm, db, location);
+
+                case DataBuffer.TYPE_USHORT:
+                    return new ShortInterleavedRaster(sm, db, location);
+
+                case DataBuffer.TYPE_INT:
+                    return new IntegerInterleavedRaster(sm, db, location);
+            }
+        } else if (sm instanceof MultiPixelPackedSampleModel &&
+                   dataType == DataBuffer.TYPE_BYTE &&
+                   sm.getSampleSize(0) < 8) {
+            return new BytePackedRaster(sm, db, location);
+        }
+
+        // we couldn't do anything special - do the generic thing
+
+        return new SunWritableRaster(sm,db,location);
+    }
+
+    /**
+     *  Constructs a Raster with the given SampleModel.  The Raster's
+     *  upper left corner is origin and it is the same size as the
+     *  SampleModel.  A DataBuffer large enough to describe the
+     *  Raster is automatically created.
+     *  @param sampleModel     The SampleModel that specifies the layout
+     *  @param origin          The Point that specified the origin
+     *  @throws RasterFormatException if computing either
+     *          <code>origin.x + sampleModel.getWidth()</code> or
+     *          <code>origin.y + sampleModel.getHeight()</code> results in
+     *          integer overflow
+     *  @throws NullPointerException either <code>sampleModel</code> or
+     *          <code>origin</code> is null
+     */
+    protected Raster(SampleModel sampleModel,
+                     Point origin) {
+        this(sampleModel,
+             sampleModel.createDataBuffer(),
+             new Rectangle(origin.x,
+                           origin.y,
+                           sampleModel.getWidth(),
+                           sampleModel.getHeight()),
+             origin,
+             null);
+    }
+
+    /**
+     *  Constructs a Raster with the given SampleModel and DataBuffer.
+     *  The Raster's upper left corner is origin and it is the same size
+     *  as the SampleModel.  The DataBuffer is not initialized and must
+     *  be compatible with SampleModel.
+     *  @param sampleModel     The SampleModel that specifies the layout
+     *  @param dataBuffer      The DataBuffer that contains the image data
+     *  @param origin          The Point that specifies the origin
+     *  @throws RasterFormatException if computing either
+     *          <code>origin.x + sampleModel.getWidth()</code> or
+     *          <code>origin.y + sampleModel.getHeight()</code> results in
+     *          integer overflow
+     *  @throws NullPointerException either <code>sampleModel</code> or
+     *          <code>origin</code> is null
+     */
+    protected Raster(SampleModel sampleModel,
+                     DataBuffer dataBuffer,
+                     Point origin) {
+        this(sampleModel,
+             dataBuffer,
+             new Rectangle(origin.x,
+                           origin.y,
+                           sampleModel.getWidth(),
+                           sampleModel.getHeight()),
+             origin,
+             null);
+    }
+
+    /**
+     * Constructs a Raster with the given SampleModel, DataBuffer, and
+     * parent.  aRegion specifies the bounding rectangle of the new
+     * Raster.  When translated into the base Raster's coordinate
+     * system, aRegion must be contained by the base Raster.
+     * (The base Raster is the Raster's ancestor which has no parent.)
+     * sampleModelTranslate specifies the sampleModelTranslateX and
+     * sampleModelTranslateY values of the new Raster.
+     *
+     * Note that this constructor should generally be called by other
+     * constructors or create methods, it should not be used directly.
+     * @param sampleModel     The SampleModel that specifies the layout
+     * @param dataBuffer      The DataBuffer that contains the image data
+     * @param aRegion         The Rectangle that specifies the image area
+     * @param sampleModelTranslate  The Point that specifies the translation
+     *                        from SampleModel to Raster coordinates
+     * @param parent          The parent (if any) of this raster
+     * @throws NullPointerException if any of <code>sampleModel</code>,
+     *         <code>dataBuffer</code>, <code>aRegion</code> or
+     *         <code>sampleModelTranslate</code> is null
+     * @throws RasterFormatException if <code>aRegion</code> has width
+     *         or height less than or equal to zero, or computing either
+     *         <code>aRegion.x + aRegion.width</code> or
+     *         <code>aRegion.y + aRegion.height</code> results in integer
+     *         overflow
+     */
+    protected Raster(SampleModel sampleModel,
+                     DataBuffer dataBuffer,
+                     Rectangle aRegion,
+                     Point sampleModelTranslate,
+                     Raster parent) {
+
+        if ((sampleModel == null) || (dataBuffer == null) ||
+            (aRegion == null) || (sampleModelTranslate == null)) {
+            throw new NullPointerException("SampleModel, dataBuffer, aRegion and " +
+                                           "sampleModelTranslate cannot be null");
+        }
+       this.sampleModel = sampleModel;
+       this.dataBuffer = dataBuffer;
+       minX = aRegion.x;
+       minY = aRegion.y;
+       width = aRegion.width;
+       height = aRegion.height;
+       if (width <= 0 || height <= 0) {
+           throw new RasterFormatException("negative or zero " +
+               ((width <= 0) ? "width" : "height"));
+       }
+       if ((minX + width) < minX) {
+           throw new RasterFormatException(
+               "overflow condition for X coordinates of Raster");
+       }
+       if ((minY + height) < minY) {
+           throw new RasterFormatException(
+               "overflow condition for Y coordinates of Raster");
+       }
+
+       sampleModelTranslateX = sampleModelTranslate.x;
+       sampleModelTranslateY = sampleModelTranslate.y;
+
+       numBands = sampleModel.getNumBands();
+       numDataElements = sampleModel.getNumDataElements();
+       this.parent = parent;
+    }
+
+
+    /**
+     * Returns the parent Raster (if any) of this Raster or null.
+     * @return the parent Raster or <code>null</code>.
+     */
+    public Raster getParent() {
+        return parent;
+    }
+
+    /**
+     * Returns the X translation from the coordinate system of the
+     * SampleModel to that of the Raster.  To convert a pixel's X
+     * coordinate from the Raster coordinate system to the SampleModel
+     * coordinate system, this value must be subtracted.
+     * @return the X translation from the coordinate space of the
+     *         Raster's SampleModel to that of the Raster.
+     */
+    final public int getSampleModelTranslateX() {
+        return sampleModelTranslateX;
+    }
+
+    /**
+     * Returns the Y translation from the coordinate system of the
+     * SampleModel to that of the Raster.  To convert a pixel's Y
+     * coordinate from the Raster coordinate system to the SampleModel
+     * coordinate system, this value must be subtracted.
+     * @return the Y translation from the coordinate space of the
+     *         Raster's SampleModel to that of the Raster.
+     */
+    final public int getSampleModelTranslateY() {
+        return sampleModelTranslateY;
+    }
+
+    /**
+     * Create a compatible WritableRaster the same size as this Raster with
+     * the same SampleModel and a new initialized DataBuffer.
+     * @return a compatible <code>WritableRaster</code> with the same sample
+     *         model and a new data buffer.
+     */
+    public WritableRaster createCompatibleWritableRaster() {
+        return new SunWritableRaster(sampleModel, new Point(0,0));
+    }
+
+    /**
+     * Create a compatible WritableRaster with the specified size, a new
+     * SampleModel, and a new initialized DataBuffer.
+     * @param w the specified width of the new <code>WritableRaster</code>
+     * @param h the specified height of the new <code>WritableRaster</code>
+     * @return a compatible <code>WritableRaster</code> with the specified
+     *         size and a new sample model and data buffer.
+     * @exception RasterFormatException if the width or height is less than
+     *                               or equal to zero.
+     */
+    public WritableRaster createCompatibleWritableRaster(int w, int h) {
+        if (w <= 0 || h <=0) {
+            throw new RasterFormatException("negative " +
+                                          ((w <= 0) ? "width" : "height"));
+        }
+
+        SampleModel sm = sampleModel.createCompatibleSampleModel(w,h);
+
+        return new SunWritableRaster(sm, new Point(0,0));
+    }
+
+    /**
+     * Create a compatible WritableRaster with location (minX, minY)
+     * and size (width, height) specified by rect, a
+     * new SampleModel, and a new initialized DataBuffer.
+     * @param rect a <code>Rectangle</code> that specifies the size and
+     *        location of the <code>WritableRaster</code>
+     * @return a compatible <code>WritableRaster</code> with the specified
+     *         size and location and a new sample model and data buffer.
+     * @throws RasterFormatException if <code>rect</code> has width
+     *         or height less than or equal to zero, or computing either
+     *         <code>rect.x + rect.width</code> or
+     *         <code>rect.y + rect.height</code> results in integer
+     *         overflow
+     * @throws NullPointerException if <code>rect</code> is null
+     */
+    public WritableRaster createCompatibleWritableRaster(Rectangle rect) {
+        if (rect == null) {
+            throw new NullPointerException("Rect cannot be null");
+        }
+        return createCompatibleWritableRaster(rect.x, rect.y,
+                                              rect.width, rect.height);
+    }
+
+    /**
+     * Create a compatible WritableRaster with the specified
+     * location (minX, minY) and size (width, height), a
+     * new SampleModel, and a new initialized DataBuffer.
+     * @param x the X coordinate of the upper-left corner of
+     *        the <code>WritableRaster</code>
+     * @param y the Y coordinate of the upper-left corner of
+     *        the <code>WritableRaster</code>
+     * @param w the specified width of the <code>WritableRaster</code>
+     * @param h the specified height of the <code>WritableRaster</code>
+     * @return a compatible <code>WritableRaster</code> with the specified
+     *         size and location and a new sample model and data buffer.
+     * @throws RasterFormatException if <code>w</code> or <code>h</code>
+     *         is less than or equal to zero, or computing either
+     *         <code>x + w</code> or
+     *         <code>y + h</code> results in integer
+     *         overflow
+     */
+    public WritableRaster createCompatibleWritableRaster(int x, int y,
+                                                         int w, int h) {
+        WritableRaster ret = createCompatibleWritableRaster(w, h);
+        return ret.createWritableChild(0,0,w,h,x,y,null);
+    }
+
+    /**
+     * Create a Raster with the same size, SampleModel and DataBuffer
+     * as this one, but with a different location.  The new Raster
+     * will possess a reference to the current Raster, accessible
+     * through its getParent() method.
+     *
+     * @param childMinX the X coordinate of the upper-left
+     *        corner of the new <code>Raster</code>
+     * @param childMinY the Y coordinate of the upper-left
+     *        corner of the new <code>Raster</code>
+     * @return a new <code>Raster</code> with the same size, SampleModel,
+     *         and DataBuffer as this <code>Raster</code>, but with the
+     *         specified location.
+     * @throws RasterFormatException if  computing either
+     *         <code>childMinX + this.getWidth()</code> or
+     *         <code>childMinY + this.getHeight()</code> results in integer
+     *         overflow
+     */
+    public Raster createTranslatedChild(int childMinX, int childMinY) {
+        return createChild(minX,minY,width,height,
+                           childMinX,childMinY,null);
+    }
+
+    /**
+     * Returns a new Raster which shares all or part of this Raster's
+     * DataBuffer.  The new Raster will possess a reference to the
+     * current Raster, accessible through its getParent() method.
+     *
+     * <p> The parentX, parentY, width and height parameters
+     * form a Rectangle in this Raster's coordinate space,
+     * indicating the area of pixels to be shared.  An error will
+     * be thrown if this Rectangle is not contained with the bounds
+     * of the current Raster.
+     *
+     * <p> The new Raster may additionally be translated to a
+     * different coordinate system for the plane than that used by the current
+     * Raster.  The childMinX and childMinY parameters give the new
+     * (x, y) coordinate of the upper-left pixel of the returned
+     * Raster; the coordinate (childMinX, childMinY) in the new Raster
+     * will map to the same pixel as the coordinate (parentX, parentY)
+     * in the current Raster.
+     *
+     * <p> The new Raster may be defined to contain only a subset of
+     * the bands of the current Raster, possibly reordered, by means
+     * of the bandList parameter.  If bandList is null, it is taken to
+     * include all of the bands of the current Raster in their current
+     * order.
+     *
+     * <p> To create a new Raster that contains a subregion of the current
+     * Raster, but shares its coordinate system and bands,
+     * this method should be called with childMinX equal to parentX,
+     * childMinY equal to parentY, and bandList equal to null.
+     *
+     * @param parentX The X coordinate of the upper-left corner
+     *        in this Raster's coordinates
+     * @param parentY The Y coordinate of the upper-left corner
+     *        in this Raster's coordinates
+     * @param width      Width of the region starting at (parentX, parentY)
+     * @param height     Height of the region starting at (parentX, parentY).
+     * @param childMinX The X coordinate of the upper-left corner
+     *                   of the returned Raster
+     * @param childMinY The Y coordinate of the upper-left corner
+     *                   of the returned Raster
+     * @param bandList   Array of band indices, or null to use all bands
+     * @return a new <code>Raster</code>.
+     * @exception RasterFormatException if the specified subregion is outside
+     *                               of the raster bounds.
+     * @throws RasterFormatException if <code>width</code> or
+     *         <code>height</code>
+     *         is less than or equal to zero, or computing any of
+     *         <code>parentX + width</code>, <code>parentY + height</code>,
+     *         <code>childMinX + width</code>, or
+     *         <code>childMinY + height</code> results in integer
+     *         overflow
+     */
+    public Raster createChild(int parentX, int parentY,
+                              int width, int height,
+                              int childMinX, int childMinY,
+                              int bandList[]) {
+        if (parentX < this.minX) {
+            throw new RasterFormatException("parentX lies outside raster");
+        }
+        if (parentY < this.minY) {
+            throw new RasterFormatException("parentY lies outside raster");
+        }
+        if ((parentX + width < parentX) ||
+            (parentX + width > this.width + this.minX)) {
+            throw new RasterFormatException("(parentX + width) is outside raster");
+        }
+        if ((parentY + height < parentY) ||
+            (parentY + height > this.height + this.minY)) {
+            throw new RasterFormatException("(parentY + height) is outside raster");
+        }
+
+        SampleModel subSampleModel;
+        // Note: the SampleModel for the child Raster should have the same
+        // width and height as that for the parent, since it represents
+        // the physical layout of the pixel data.  The child Raster's width
+        // and height represent a "virtual" view of the pixel data, so
+        // they may be different than those of the SampleModel.
+        if (bandList == null) {
+            subSampleModel = sampleModel;
+        } else {
+            subSampleModel = sampleModel.createSubsetSampleModel(bandList);
+        }
+
+        int deltaX = childMinX - parentX;
+        int deltaY = childMinY - parentY;
+
+        return new Raster(subSampleModel, getDataBuffer(),
+                          new Rectangle(childMinX, childMinY, width, height),
+                          new Point(sampleModelTranslateX + deltaX,
+                                    sampleModelTranslateY + deltaY), this);
+    }
+
+    /**
+     * Returns the bounding Rectangle of this Raster. This function returns
+     * the same information as getMinX/MinY/Width/Height.
+     * @return the bounding box of this <code>Raster</code>.
+     */
+    public Rectangle getBounds() {
+        return new Rectangle(minX, minY, width, height);
+    }
+
+    /** Returns the minimum valid X coordinate of the Raster.
+     *  @return the minimum x coordinate of this <code>Raster</code>.
+     */
+    final public int getMinX() {
+        return minX;
+    }
+
+    /** Returns the minimum valid Y coordinate of the Raster.
+     *  @return the minimum y coordinate of this <code>Raster</code>.
+     */
+    final public int getMinY() {
+        return minY;
+    }
+
+    /** Returns the width in pixels of the Raster.
+     *  @return the width of this <code>Raster</code>.
+     */
+    final public int getWidth() {
+        return width;
+    }
+
+    /** Returns the height in pixels of the Raster.
+     *  @return the height of this <code>Raster</code>.
+     */
+    final public int getHeight() {
+        return height;
+    }
+
+    /** Returns the number of bands (samples per pixel) in this Raster.
+     *  @return the number of bands of this <code>Raster</code>.
+     */
+    final public int getNumBands() {
+        return numBands;
+    }
+
+    /**
+     *  Returns the number of data elements needed to transfer one pixel
+     *  via the getDataElements and setDataElements methods.  When pixels
+     *  are transferred via these methods, they may be transferred in a
+     *  packed or unpacked format, depending on the implementation of the
+     *  underlying SampleModel.  Using these methods, pixels are transferred
+     *  as an array of getNumDataElements() elements of a primitive type given
+     *  by getTransferType().  The TransferType may or may not be the same
+     *  as the storage data type of the DataBuffer.
+     *  @return the number of data elements.
+     */
+    final public int getNumDataElements() {
+        return sampleModel.getNumDataElements();
+    }
+
+    /**
+     *  Returns the TransferType used to transfer pixels via the
+     *  getDataElements and setDataElements methods.  When pixels
+     *  are transferred via these methods, they may be transferred in a
+     *  packed or unpacked format, depending on the implementation of the
+     *  underlying SampleModel.  Using these methods, pixels are transferred
+     *  as an array of getNumDataElements() elements of a primitive type given
+     *  by getTransferType().  The TransferType may or may not be the same
+     *  as the storage data type of the DataBuffer.  The TransferType will
+     *  be one of the types defined in DataBuffer.
+     *  @return this transfer type.
+     */
+    final public int getTransferType() {
+        return sampleModel.getTransferType();
+    }
+
+    /** Returns the DataBuffer associated with this Raster.
+     *  @return the <code>DataBuffer</code> of this <code>Raster</code>.
+     */
+    public DataBuffer getDataBuffer() {
+        return dataBuffer;
+    }
+
+    /** Returns the SampleModel that describes the layout of the image data.
+     *  @return the <code>SampleModel</code> of this <code>Raster</code>.
+     */
+    public SampleModel getSampleModel() {
+        return sampleModel;
+    }
+
+    /**
+     * Returns data for a single pixel in a primitive array of type
+     * TransferType.  For image data supported by the Java 2D(tm) API,
+     * this will be one of DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
+     * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT,
+     * or DataBuffer.TYPE_DOUBLE.  Data may be returned in a packed format,
+     * thus increasing efficiency for data transfers.
+     * An ArrayIndexOutOfBoundsException may be thrown
+     * if the coordinates are not in bounds.  However, explicit bounds
+     * checking is not guaranteed.
+     * A ClassCastException will be thrown if the input object is non null
+     * and references anything other than an array of TransferType.
+     * @see java.awt.image.SampleModel#getDataElements(int, int, Object, DataBuffer)
+     * @param x        The X coordinate of the pixel location
+     * @param y        The Y coordinate of the pixel location
+     * @param outData  An object reference to an array of type defined by
+     *                 getTransferType() and length getNumDataElements().
+     *                 If null, an array of appropriate type and size will be
+     *                 allocated
+     * @return         An object reference to an array of type defined by
+     *                 getTransferType() with the requested pixel data.
+     *
+     * @throws ArrayIndexOutOfBoundsException if the coordinates are not
+     * in bounds, or if outData is too small to hold the output.
+     */
+    public Object getDataElements(int x, int y, Object outData) {
+        return sampleModel.getDataElements(x - sampleModelTranslateX,
+                                           y - sampleModelTranslateY,
+                                           outData, dataBuffer);
+    }
+
+    /**
+     * Returns the pixel data for the specified rectangle of pixels in a
+     * primitive array of type TransferType.
+     * For image data supported by the Java 2D API, this
+     * will be one of DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
+     * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT,
+     * or DataBuffer.TYPE_DOUBLE.  Data may be returned in a packed format,
+     * thus increasing efficiency for data transfers.
+     * An ArrayIndexOutOfBoundsException may be thrown
+     * if the coordinates are not in bounds.  However, explicit bounds
+     * checking is not guaranteed.
+     * A ClassCastException will be thrown if the input object is non null
+     * and references anything other than an array of TransferType.
+     * @see java.awt.image.SampleModel#getDataElements(int, int, int, int, Object, DataBuffer)
+     * @param x    The X coordinate of the upper-left pixel location
+     * @param y    The Y coordinate of the upper-left pixel location
+     * @param w    Width of the pixel rectangle
+     * @param h   Height of the pixel rectangle
+     * @param outData  An object reference to an array of type defined by
+     *                 getTransferType() and length w*h*getNumDataElements().
+     *                 If null, an array of appropriate type and size will be
+     *                 allocated.
+     * @return         An object reference to an array of type defined by
+     *                 getTransferType() with the requested pixel data.
+     *
+     * @throws ArrayIndexOutOfBoundsException if the coordinates are not
+     * in bounds, or if outData is too small to hold the output.
+     */
+    public Object getDataElements(int x, int y, int w, int h, Object outData) {
+        return sampleModel.getDataElements(x - sampleModelTranslateX,
+                                           y - sampleModelTranslateY,
+                                           w, h, outData, dataBuffer);
+    }
+
+    /**
+     * Returns the samples in an array of int for the specified pixel.
+     * An ArrayIndexOutOfBoundsException may be thrown
+     * if the coordinates are not in bounds.  However, explicit bounds
+     * checking is not guaranteed.
+     * @param x The X coordinate of the pixel location
+     * @param y The Y coordinate of the pixel location
+     * @param iArray An optionally preallocated int array
+     * @return the samples for the specified pixel.
+     *
+     * @throws ArrayIndexOutOfBoundsException if the coordinates are not
+     * in bounds, or if iArray is too small to hold the output.
+     */
+    public int[] getPixel(int x, int y, int iArray[]) {
+        return sampleModel.getPixel(x - sampleModelTranslateX,
+                                    y - sampleModelTranslateY,
+                                    iArray, dataBuffer);
+    }
+
+    /**
+     * Returns the samples in an array of float for the
+     * specified pixel.
+     * An ArrayIndexOutOfBoundsException may be thrown
+     * if the coordinates are not in bounds.  However, explicit bounds
+     * checking is not guaranteed.
+     * @param x The X coordinate of the pixel location
+     * @param y The Y coordinate of the pixel location
+     * @param fArray An optionally preallocated float array
+     * @return the samples for the specified pixel.
+     *
+     * @throws ArrayIndexOutOfBoundsException if the coordinates are not
+     * in bounds, or if fArray is too small to hold the output.
+     */
+    public float[] getPixel(int x, int y, float fArray[]) {
+        return sampleModel.getPixel(x - sampleModelTranslateX,
+                                    y - sampleModelTranslateY,
+                                    fArray, dataBuffer);
+    }
+
+    /**
+     * Returns the samples in an array of double for the specified pixel.
+     * An ArrayIndexOutOfBoundsException may be thrown
+     * if the coordinates are not in bounds.  However, explicit bounds
+     * checking is not guaranteed.
+     * @param x The X coordinate of the pixel location
+     * @param y The Y coordinate of the pixel location
+     * @param dArray An optionally preallocated double array
+     * @return the samples for the specified pixel.
+     *
+     * @throws ArrayIndexOutOfBoundsException if the coordinates are not
+     * in bounds, or if dArray is too small to hold the output.
+     */
+    public double[] getPixel(int x, int y, double dArray[]) {
+        return sampleModel.getPixel(x - sampleModelTranslateX,
+                                    y - sampleModelTranslateY,
+                                    dArray, dataBuffer);
+    }
+
+    /**
+     * Returns an int array containing all samples for a rectangle of pixels,
+     * one sample per array element.
+     * An ArrayIndexOutOfBoundsException may be thrown
+     * if the coordinates are not in bounds.  However, explicit bounds
+     * checking is not guaranteed.
+     * @param x      The X coordinate of the upper-left pixel location
+     * @param y      The Y coordinate of the upper-left pixel location
+     * @param w      Width of the pixel rectangle
+     * @param h      Height of the pixel rectangle
+     * @param iArray An optionally pre-allocated int array
+     * @return the samples for the specified rectangle of pixels.
+     *
+     * @throws ArrayIndexOutOfBoundsException if the coordinates are not
+     * in bounds, or if iArray is too small to hold the output.
+     */
+    public int[] getPixels(int x, int y, int w, int h, int iArray[]) {
+        return sampleModel.getPixels(x - sampleModelTranslateX,
+                                     y - sampleModelTranslateY, w, h,
+                                     iArray, dataBuffer);
+    }
+
+    /**
+     * Returns a float array containing all samples for a rectangle of pixels,
+     * one sample per array element.
+     * An ArrayIndexOutOfBoundsException may be thrown
+     * if the coordinates are not in bounds.  However, explicit bounds
+     * checking is not guaranteed.
+     * @param x        The X coordinate of the pixel location
+     * @param y        The Y coordinate of the pixel location
+     * @param w        Width of the pixel rectangle
+     * @param h        Height of the pixel rectangle
+     * @param fArray   An optionally pre-allocated float array
+     * @return the samples for the specified rectangle of pixels.
+     *
+     * @throws ArrayIndexOutOfBoundsException if the coordinates are not
+     * in bounds, or if fArray is too small to hold the output.
+     */
+    public float[] getPixels(int x, int y, int w, int h,
+                             float fArray[]) {
+        return sampleModel.getPixels(x - sampleModelTranslateX,
+                                     y - sampleModelTranslateY, w, h,
+                                     fArray, dataBuffer);
+    }
+
+    /**
+     * Returns a double array containing all samples for a rectangle of pixels,
+     * one sample per array element.
+     * An ArrayIndexOutOfBoundsException may be thrown
+     * if the coordinates are not in bounds.  However, explicit bounds
+     * checking is not guaranteed.
+     * @param x        The X coordinate of the upper-left pixel location
+     * @param y        The Y coordinate of the upper-left pixel location
+     * @param w        Width of the pixel rectangle
+     * @param h        Height of the pixel rectangle
+     * @param dArray   An optionally pre-allocated double array
+     * @return the samples for the specified rectangle of pixels.
+     *
+     * @throws ArrayIndexOutOfBoundsException if the coordinates are not
+     * in bounds, or if dArray is too small to hold the output.
+     */
+    public double[] getPixels(int x, int y, int w, int h,
+                              double dArray[]) {
+        return sampleModel.getPixels(x - sampleModelTranslateX,
+                                     y - sampleModelTranslateY,
+                                     w, h, dArray, dataBuffer);
+    }
+
+
+    /**
+     * Returns the sample in a specified band for the pixel located
+     * at (x,y) as an int.
+     * An ArrayIndexOutOfBoundsException may be thrown
+     * if the coordinates are not in bounds.  However, explicit bounds
+     * checking is not guaranteed.
+     * @param x        The X coordinate of the pixel location
+     * @param y        The Y coordinate of the pixel location
+     * @param b        The band to return
+     * @return the sample in the specified band for the pixel at the
+     *         specified coordinate.
+     *
+     * @throws ArrayIndexOutOfBoundsException if the coordinates or
+     * the band index are not in bounds.
+     */
+    public int getSample(int x, int y, int b) {
+        return sampleModel.getSample(x - sampleModelTranslateX,
+                                     y - sampleModelTranslateY, b,
+                                     dataBuffer);
+    }
+
+    /**
+     * Returns the sample in a specified band
+     * for the pixel located at (x,y) as a float.
+     * An ArrayIndexOutOfBoundsException may be thrown
+     * if the coordinates are not in bounds.  However, explicit bounds
+     * checking is not guaranteed.
+     * @param x        The X coordinate of the pixel location
+     * @param y        The Y coordinate of the pixel location
+     * @param b        The band to return
+     * @return the sample in the specified band for the pixel at the
+     *         specified coordinate.
+     *
+     * @throws ArrayIndexOutOfBoundsException if the coordinates or
+     * the band index are not in bounds.
+     */
+    public float getSampleFloat(int x, int y, int b) {
+        return sampleModel.getSampleFloat(x - sampleModelTranslateX,
+                                          y - sampleModelTranslateY, b,
+                                          dataBuffer);
+    }
+
+    /**
+     * Returns the sample in a specified band
+     * for a pixel located at (x,y) as a double.
+     * An ArrayIndexOutOfBoundsException may be thrown
+     * if the coordinates are not in bounds.  However, explicit bounds
+     * checking is not guaranteed.
+     * @param x        The X coordinate of the pixel location
+     * @param y        The Y coordinate of the pixel location
+     * @param b        The band to return
+     * @return the sample in the specified band for the pixel at the
+     *         specified coordinate.
+     *
+     * @throws ArrayIndexOutOfBoundsException if the coordinates or
+     * the band index are not in bounds.
+     */
+    public double getSampleDouble(int x, int y, int b) {
+        return sampleModel.getSampleDouble(x - sampleModelTranslateX,
+                                           y - sampleModelTranslateY,
+                                           b, dataBuffer);
+    }
+
+    /**
+     * Returns the samples for a specified band for the specified rectangle
+     * of pixels in an int array, one sample per array element.
+     * An ArrayIndexOutOfBoundsException may be thrown
+     * if the coordinates are not in bounds.  However, explicit bounds
+     * checking is not guaranteed.
+     * @param x        The X coordinate of the upper-left pixel location
+     * @param y        The Y coordinate of the upper-left pixel location
+     * @param w        Width of the pixel rectangle
+     * @param h        Height of the pixel rectangle
+     * @param b        The band to return
+     * @param iArray   An optionally pre-allocated int array
+     * @return the samples for the specified band for the specified
+     *         rectangle of pixels.
+     *
+     * @throws ArrayIndexOutOfBoundsException if the coordinates or
+     * the band index are not in bounds, or if iArray is too small to
+     * hold the output.
+     */
+    public int[] getSamples(int x, int y, int w, int h, int b,
+                            int iArray[]) {
+        return sampleModel.getSamples(x - sampleModelTranslateX,
+                                      y - sampleModelTranslateY,
+                                      w, h, b, iArray,
+                                      dataBuffer);
+    }
+
+    /**
+     * Returns the samples for a specified band for the specified rectangle
+     * of pixels in a float array, one sample per array element.
+     * An ArrayIndexOutOfBoundsException may be thrown
+     * if the coordinates are not in bounds.  However, explicit bounds
+     * checking is not guaranteed.
+     * @param x        The X coordinate of the upper-left pixel location
+     * @param y        The Y coordinate of the upper-left pixel location
+     * @param w        Width of the pixel rectangle
+     * @param h        Height of the pixel rectangle
+     * @param b        The band to return
+     * @param fArray   An optionally pre-allocated float array
+     * @return the samples for the specified band for the specified
+     *         rectangle of pixels.
+     *
+     * @throws ArrayIndexOutOfBoundsException if the coordinates or
+     * the band index are not in bounds, or if fArray is too small to
+     * hold the output.
+     */
+    public float[] getSamples(int x, int y, int w, int h, int b,
+                              float fArray[]) {
+        return sampleModel.getSamples(x - sampleModelTranslateX,
+                                      y - sampleModelTranslateY,
+                                      w, h, b, fArray, dataBuffer);
+    }
+
+    /**
+     * Returns the samples for a specified band for a specified rectangle
+     * of pixels in a double array, one sample per array element.
+     * An ArrayIndexOutOfBoundsException may be thrown
+     * if the coordinates are not in bounds.  However, explicit bounds
+     * checking is not guaranteed.
+     * @param x        The X coordinate of the upper-left pixel location
+     * @param y        The Y coordinate of the upper-left pixel location
+     * @param w        Width of the pixel rectangle
+     * @param h        Height of the pixel rectangle
+     * @param b        The band to return
+     * @param dArray   An optionally pre-allocated double array
+     * @return the samples for the specified band for the specified
+     *         rectangle of pixels.
+     *
+     * @throws ArrayIndexOutOfBoundsException if the coordinates or
+     * the band index are not in bounds, or if dArray is too small to
+     * hold the output.
+     */
+    public double[] getSamples(int x, int y, int w, int h, int b,
+                               double dArray[]) {
+         return sampleModel.getSamples(x - sampleModelTranslateX,
+                                       y - sampleModelTranslateY,
+                                       w, h, b, dArray, dataBuffer);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/awt/image/RenderedImage.java	Thu Apr 10 16:28:45 2008 -0700
@@ -0,0 +1,217 @@
+/*
+ * Portions Copyright 1997-2000 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* ****************************************************************
+ ******************************************************************
+ ******************************************************************
+ *** COPYRIGHT (c) Eastman Kodak Company, 1997
+ *** As  an unpublished  work pursuant to Title 17 of the United
+ *** States Code.  All rights reserved.
+ ******************************************************************
+ ******************************************************************
+ ******************************************************************/
+
+package java.awt.image;
+import java.awt.Rectangle;
+import java.util.Dictionary;
+import java.util.Vector;
+
+/**
+ * RenderedImage is a common interface for objects which contain
+ * or can produce image data in the form of Rasters.  The image
+ * data may be stored/produced as a single tile or a regular array
+ * of tiles.
+ */
+
+public interface RenderedImage {
+
+    /**
+     * Returns a vector of RenderedImages that are the immediate sources of
+     * image data for this RenderedImage.  This method returns null if
+     * the RenderedImage object has no information about its immediate
+     * sources.  It returns an empty Vector if the RenderedImage object has
+     * no immediate sources.
+     * @return a Vector of <code>RenderedImage</code> objects.
+     */
+    Vector<RenderedImage> getSources();
+
+    /**
+     * Gets a property from the property set of this image.  The set of
+     * properties and whether it is immutable is determined by the
+     * implementing class.  This method returns
+     * java.awt.Image.UndefinedProperty if the specified property is
+     * not defined for this RenderedImage.
+     * @param name the name of the property
+     * @return the property indicated by the specified name.
+     * @see java.awt.Image#UndefinedProperty
+     */
+    Object getProperty(String name);
+
+    /**
+      * Returns an array of names recognized by
+      * {@link #getProperty(String) getProperty(String)}
+      * or <code>null</code>, if no property names are recognized.
+      * @return a <code>String</code> array containing all of the
+      * property names that <code>getProperty(String)</code> recognizes;
+      * or <code>null</code> if no property names are recognized.
+      */
+    String[] getPropertyNames();
+
+    /**
+     * Returns the ColorModel associated with this image.  All Rasters
+     * returned from this image will have this as their ColorModel.  This
+     * can return null.
+     * @return the <code>ColorModel</code> of this image.
+     */
+    ColorModel getColorModel();
+
+    /**
+     * Returns the SampleModel associated with this image.  All Rasters
+     * returned from this image will have this as their SampleModel.
+     * @return the <code>SampleModel</code> of this image.
+     */
+    SampleModel getSampleModel();
+
+    /**
+     * Returns the width of the RenderedImage.
+     * @return the width of this <code>RenderedImage</code>.
+     */
+    int getWidth();
+
+    /**
+     * Returns the height of the RenderedImage.
+     * @return the height of this <code>RenderedImage</code>.
+     */
+    int getHeight();
+
+    /**
+     * Returns the minimum X coordinate (inclusive) of the RenderedImage.
+     * @return the X coordinate of this <code>RenderedImage</code>.
+     */
+    int getMinX();
+
+    /**
+     * Returns the minimum Y coordinate (inclusive) of the RenderedImage.
+     * @return the Y coordinate of this <code>RenderedImage</code>.
+     */
+    int getMinY();
+
+    /**
+     * Returns the number of tiles in the X direction.
+     * @return the number of tiles in the X direction.
+     */
+    int getNumXTiles();
+
+    /**
+     * Returns the number of tiles in the Y direction.
+     * @return the number of tiles in the Y direction.
+     */
+    int getNumYTiles();
+
+    /**
+     *  Returns the minimum tile index in the X direction.
+     *  @return the minimum tile index in the X direction.
+     */
+    int getMinTileX();
+
+    /**
+     *  Returns the minimum tile index in the Y direction.
+     *  @return the minimum tile index in the X direction.
+     */
+    int getMinTileY();
+
+    /**
+     *  Returns the tile width in pixels.  All tiles must have the same
+     *  width.
+     *  @return the tile width in pixels.
+     */
+    int getTileWidth();
+
+    /**
+     *  Returns the tile height in pixels.  All tiles must have the same
+     *  height.
+     *  @return the tile height in pixels.
+     */
+    int getTileHeight();
+
+    /**
+     * Returns the X offset of the tile grid relative to the origin,
+     * i.e., the X coordinate of the upper-left pixel of tile (0, 0).
+     * (Note that tile (0, 0) may not actually exist.)
+     * @return the X offset of the tile grid relative to the origin.
+     */
+    int getTileGridXOffset();
+
+    /**
+     * Returns the Y offset of the tile grid relative to the origin,
+     * i.e., the Y coordinate of the upper-left pixel of tile (0, 0).
+     * (Note that tile (0, 0) may not actually exist.)
+     * @return the Y offset of the tile grid relative to the origin.
+     */
+    int getTileGridYOffset();
+
+    /**
+     * Returns tile (tileX, tileY).  Note that tileX and tileY are indices
+     * into the tile array, not pixel locations.  The Raster that is returned
+     * is live and will be updated if the image is changed.
+     * @param tileX the X index of the requested tile in the tile array
+     * @param tileY the Y index of the requested tile in the tile array
+     * @return the tile given the specified indices.
+     */
+   Raster getTile(int tileX, int tileY);
+
+    /**
+     * Returns the image as one large tile (for tile based
+     * images this will require fetching the whole image
+     * and copying the image data over).  The Raster returned is
+     * a copy of the image data and will not be updated if the image
+     * is changed.
+     * @return the image as one large tile.
+     */
+    Raster getData();
+
+    /**
+     * Computes and returns an arbitrary region of the RenderedImage.
+     * The Raster returned is a copy of the image data and will not
+     * be updated if the image is changed.
+     * @param rect the region of the RenderedImage to be returned.
+     * @return the region of the <code>RenderedImage</code>
+     * indicated by the specified <code>Rectangle</code>.
+     */
+    Raster getData(Rectangle rect);
+
+    /**
+     * Computes an arbitrary rectangular region of the RenderedImage
+     * and copies it into a caller-supplied WritableRaster.  The region
+     * to be computed is determined from the bounds of the supplied
+     * WritableRaster.  The supplied WritableRaster must have a
+     * SampleModel that is compatible with this image.  If raster is null,
+     * an appropriate WritableRaster is created.
+     * @param raster a WritableRaster to hold the returned portion of the
+     *               image, or null.
+     * @return a reference to the supplied or created WritableRaster.
+     */
+    WritableRaster copyData(WritableRaster raster);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/awt/image/SampleModel.java	Thu Apr 10 16:28:45 2008 -0700
@@ -0,0 +1,1393 @@
+/*
+ * Portions Copyright 1997-2006 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* ****************************************************************
+ ******************************************************************
+ ******************************************************************
+ *** COPYRIGHT (c) Eastman Kodak Company, 1997
+ *** As  an unpublished  work pursuant to Title 17 of the United
+ *** States Code.  All rights reserved.
+ ******************************************************************
+ ******************************************************************
+ ******************************************************************/
+
+package java.awt.image;
+
+/**
+ *  This abstract class defines an interface for extracting samples of pixels
+ *  in an image.  All image data is expressed as a collection of pixels.
+ *  Each pixel consists of a number of samples. A sample is a datum
+ *  for one band of an image and a band consists of all samples of a
+ *  particular type in an image.  For example, a pixel might contain
+ *  three samples representing its red, green and blue components.
+ *  There are three bands in the image containing this pixel.  One band
+ *  consists of all the red samples from all pixels in the
+ *  image.  The second band consists of all the green samples and
+ *  the remaining band consists of all of the blue samples.  The pixel
+ *  can be stored in various formats.  For example, all samples from
+ *  a particular band can be stored contiguously or all samples from a
+ *  single pixel can be stored contiguously.
+ *  <p>
+ *  Subclasses of SampleModel specify the types of samples they can
+ *  represent (e.g. unsigned 8-bit byte, signed 16-bit short, etc.)
+ *  and may specify how the samples are organized in memory.
+ *  In the Java 2D(tm) API, built-in image processing operators may
+ *  not operate on all possible sample types, but generally will work
+ *  for unsigned integral samples of 16 bits or less.  Some operators
+ *  support a wider variety of sample types.
+ *  <p>
+ *  A collection of pixels is represented as a Raster, which consists of
+ *  a DataBuffer and a SampleModel.  The SampleModel allows access to
+ *  samples in the DataBuffer and may provide low-level information that
+ *  a programmer can use to directly manipulate samples and pixels in the
+ *  DataBuffer.
+ *  <p>
+ *  This class is generally a fall back method for dealing with
+ *  images.  More efficient code will cast the SampleModel to the
+ *  appropriate subclass and extract the information needed to directly
+ *  manipulate pixels in the DataBuffer.
+ *
+ *  @see java.awt.image.DataBuffer
+ *  @see java.awt.image.Raster
+ *  @see java.awt.image.ComponentSampleModel
+ *  @see java.awt.image.PixelInterleavedSampleModel
+ *  @see java.awt.image.BandedSampleModel
+ *  @see java.awt.image.MultiPixelPackedSampleModel
+ *  @see java.awt.image.SinglePixelPackedSampleModel
+ */
+
+public abstract class SampleModel
+{
+
+    /** Width in pixels of the region of image data that this SampleModel
+     *  describes.
+     */
+    protected int width;
+
+    /** Height in pixels of the region of image data that this SampleModel
+     *  describes.
+     */
+    protected int height;
+
+    /** Number of bands of the image data that this SampleModel describes. */
+    protected int numBands;
+
+    /** Data type of the DataBuffer storing the pixel data.
+     *  @see java.awt.image.DataBuffer
+     */
+    protected int dataType;
+
+    static private native void initIDs();
+    static {
+        ColorModel.loadLibraries();
+        initIDs();
+    }
+
+    /**
+     * Constructs a SampleModel with the specified parameters.
+     * @param dataType  The data type of the DataBuffer storing the pixel data.
+     * @param w         The width (in pixels) of the region of image data.
+     * @param h         The height (in pixels) of the region of image data.
+     * @param numBands  The number of bands of the image data.
+     * @throws IllegalArgumentException if <code>w</code> or <code>h</code>
+     *         is not greater than 0
+     * @throws IllegalArgumentException if the product of <code>w</code>
+     *         and <code>h</code> is greater than
+     *         <code>Integer.MAX_VALUE</code>
+     * @throws IllegalArgumentException if <code>dataType</code> is not
+     *         one of the supported data types
+     */
+    public SampleModel(int dataType, int w, int h, int numBands)
+    {
+        float size = (float)w*h;
+        if (w <= 0 || h <= 0) {
+            throw new IllegalArgumentException("Width ("+w+") and height ("+
+                                               h+") must be > 0");
+        }
+        if (size >= Integer.MAX_VALUE) {
+            throw new IllegalArgumentException("Dimensions (width="+w+
+                                               " height="+h+") are too large");
+        }
+
+        if (dataType < DataBuffer.TYPE_BYTE ||
+            (dataType > DataBuffer.TYPE_DOUBLE &&
+             dataType != DataBuffer.TYPE_UNDEFINED))
+        {
+            throw new IllegalArgumentException("Unsupported dataType: "+
+                                               dataType);
+        }
+
+        if (numBands <= 0) {
+            throw new IllegalArgumentException("Number of bands must be > 0");
+        }
+
+        this.dataType = dataType;
+        this.width = w;
+        this.height = h;
+        this.numBands = numBands;
+    }
+
+    /** Returns the width in pixels.
+     *  @return the width in pixels of the region of image data
+     *          that this <code>SampleModel</code> describes.
+     */
+    final public int getWidth() {
+         return width;
+    }
+
+    /** Returns the height in pixels.
+     *  @return the height in pixels of the region of image data
+     *          that this <code>SampleModel</code> describes.
+     */
+    final public int getHeight() {
+         return height;
+    }
+
+    /** Returns the total number of bands of image data.
+     *  @return the number of bands of image data that this
+     *          <code>SampleModel</code> describes.
+     */
+    final public int getNumBands() {
+         return numBands;
+    }
+
+    /** Returns the number of data elements needed to transfer a pixel
+     *  via the getDataElements and setDataElements methods.  When pixels
+     *  are transferred via these methods, they may be transferred in a
+     *  packed or unpacked format, depending on the implementation of the
+     *  SampleModel.  Using these methods, pixels are transferred as an
+     *  array of getNumDataElements() elements of a primitive type given
+     *  by getTransferType().  The TransferType may or may not be the same
+     *  as the storage DataType.
+     *  @return the number of data elements.
+     *  @see #getDataElements(int, int, Object, DataBuffer)
+     *  @see #getDataElements(int, int, int, int, Object, DataBuffer)
+     *  @see #setDataElements(int, int, Object, DataBuffer)
+     *  @see #setDataElements(int, int, int, int, Object, DataBuffer)
+     *  @see #getTransferType
+     */
+    public abstract int getNumDataElements();
+
+    /** Returns the data type of the DataBuffer storing the pixel data.
+     *  @return the data type.
+     */
+    final public int getDataType() {
+        return dataType;
+    }
+
+    /** Returns the TransferType used to transfer pixels via the
+     *  getDataElements and setDataElements methods.  When pixels
+     *  are transferred via these methods, they may be transferred in a
+     *  packed or unpacked format, depending on the implementation of the
+     *  SampleModel.  Using these methods, pixels are transferred as an
+     *  array of getNumDataElements() elements of a primitive type given
+     *  by getTransferType().  The TransferType may or may not be the same
+     *  as the storage DataType.  The TransferType will be one of the types
+     *  defined in DataBuffer.
+     *  @return the transfer type.
+     *  @see #getDataElements(int, int, Object, DataBuffer)
+     *  @see #getDataElements(int, int, int, int, Object, DataBuffer)
+     *  @see #setDataElements(int, int, Object, DataBuffer)
+     *  @see #setDataElements(int, int, int, int, Object, DataBuffer)
+     *  @see #getNumDataElements
+     *  @see java.awt.image.DataBuffer
+     */
+    public int getTransferType() {
+        return dataType;
+    }
+
+    /**
+     * Returns the samples for a specified pixel in an int array,
+     * one sample per array element.
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the pixel location
+     * @param y         The Y coordinate of the pixel location
+     * @param iArray    If non-null, returns the samples in this array
+     * @param data      The DataBuffer containing the image data
+     * @return the samples for the specified pixel.
+     * @see #setPixel(int, int, int[], DataBuffer)
+     *
+     * @throws NullPointerException if data is null.
+     * @throws ArrayIndexOutOfBoundsException if the coordinates are
+     * not in bounds, or if iArray is too small to hold the output.
+     */
+    public int[] getPixel(int x, int y, int iArray[], DataBuffer data) {
+
+        int pixels[];
+
+        if (iArray != null)
+            pixels = iArray;
+        else
+            pixels = new int[numBands];
+
+        for (int i=0; i<numBands; i++) {
+            pixels[i] = getSample(x, y, i, data);
+        }
+
+        return pixels;
+    }
+
+    /**
+     * Returns data for a single pixel in a primitive array of type
+     * TransferType.  For image data supported by the Java 2D API, this
+     * will be one of DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
+     * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT,
+     * or DataBuffer.TYPE_DOUBLE.  Data may be returned in a packed format,
+     * thus increasing efficiency for data transfers. Generally, obj
+     * should be passed in as null, so that the Object will be created
+     * automatically and will be of the right primitive data type.
+     * <p>
+     * The following code illustrates transferring data for one pixel from
+     * DataBuffer <code>db1</code>, whose storage layout is described by
+     * SampleModel <code>sm1</code>, to DataBuffer <code>db2</code>, whose
+     * storage layout is described by SampleModel <code>sm2</code>.
+     * The transfer will generally be more efficient than using
+     * getPixel/setPixel.
+     * <pre>
+     *       SampleModel sm1, sm2;
+     *       DataBuffer db1, db2;
+     *       sm2.setDataElements(x, y, sm1.getDataElements(x, y, null, db1), db2);
+     * </pre>
+     * Using getDataElements/setDataElements to transfer between two
+     * DataBuffer/SampleModel pairs is legitimate if the SampleModels have
+     * the same number of bands, corresponding bands have the same number of
+     * bits per sample, and the TransferTypes are the same.
+     * <p>
+     * If obj is non-null, it should be a primitive array of type TransferType.
+     * Otherwise, a ClassCastException is thrown.  An
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds, or if obj is non-null and is not large enough to hold
+     * the pixel data.
+     * @param x         The X coordinate of the pixel location.
+     * @param y         The Y coordinate of the pixel location.
+     * @param obj       If non-null, a primitive array in which to return
+     *                  the pixel data.
+     * @param data      The DataBuffer containing the image data.
+     * @return the data elements for the specified pixel.
+     * @see #getNumDataElements
+     * @see #getTransferType
+     * @see java.awt.image.DataBuffer
+     * @see #setDataElements(int, int, Object, DataBuffer)
+     *
+     * @throws NullPointerException if data is null.
+     * @throws ArrayIndexOutOfBoundsException if the coordinates are
+     * not in bounds, or if obj is too small to hold the output.
+     */
+    public abstract Object getDataElements(int x, int y,
+                                           Object obj, DataBuffer data);
+
+    /**
+     * Returns the pixel data for the specified rectangle of pixels in a
+     * primitive array of type TransferType.
+     * For image data supported by the Java 2D API, this
+     * will be one of DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT,
+     * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT,
+     * or DataBuffer.TYPE_DOUBLE.  Data may be returned in a packed format,
+     * thus increasing efficiency for data transfers. Generally, obj
+     * should be passed in as null, so that the Object will be created
+     * automatically and will be of the right primitive data type.
+     * <p>
+     * The following code illustrates transferring data for a rectangular
+     * region of pixels from
+     * DataBuffer <code>db1</code>, whose storage layout is described by
+     * SampleModel <code>sm1</code>, to DataBuffer <code>db2</code>, whose
+     * storage layout is described by SampleModel <code>sm2</code>.
+     * The transfer will generally be more efficient than using
+     * getPixels/setPixels.
+     * <pre>
+     *       SampleModel sm1, sm2;
+     *       DataBuffer db1, db2;
+     *       sm2.setDataElements(x, y, w, h, sm1.getDataElements(x, y, w,
+     *                           h, null, db1), db2);
+     * </pre>
+     * Using getDataElements/setDataElements to transfer between two
+     * DataBuffer/SampleModel pairs is legitimate if the SampleModels have
+     * the same number of bands, corresponding bands have the same number of
+     * bits per sample, and the TransferTypes are the same.
+     * <p>
+     * If obj is non-null, it should be a primitive array of type TransferType.
+     * Otherwise, a ClassCastException is thrown.  An
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds, or if obj is non-null and is not large enough to hold
+     * the pixel data.
+     * @param x         The minimum X coordinate of the pixel rectangle.
+     * @param y         The minimum Y coordinate of the pixel rectangle.
+     * @param w         The width of the pixel rectangle.
+     * @param h         The height of the pixel rectangle.
+     * @param obj       If non-null, a primitive array in which to return
+     *                  the pixel data.
+     * @param data      The DataBuffer containing the image data.
+     * @return the data elements for the specified region of pixels.
+     * @see #getNumDataElements
+     * @see #getTransferType
+     * @see #setDataElements(int, int, int, int, Object, DataBuffer)
+     * @see java.awt.image.DataBuffer
+     *
+     * @throws NullPointerException if data is null.
+     * @throws ArrayIndexOutOfBoundsException if the coordinates are
+     * not in bounds, or if obj is too small to hold the output.
+     */
+    public Object getDataElements(int x, int y, int w, int h,
+                                  Object obj, DataBuffer data) {
+
+        int type = getTransferType();
+        int numDataElems = getNumDataElements();
+        int cnt = 0;
+        Object o = null;
+
+        switch(type) {
+
+        case DataBuffer.TYPE_BYTE:
+
+            byte[] btemp;
+            byte[] bdata;
+
+            if (obj == null)
+                bdata = new byte[numDataElems*w*h];
+            else
+                bdata = (byte[])obj;
+
+            for (int i=y; i<y+h; i++) {
+                for (int j=x; j<x+w; j++) {
+                    o = getDataElements(j, i, o, data);
+                    btemp = (byte[])o;
+                    for (int k=0; k<numDataElems; k++) {
+                        bdata[cnt++] = btemp[k];
+                    }
+                }
+            }
+            obj = (Object)bdata;
+            break;
+
+        case DataBuffer.TYPE_USHORT:
+        case DataBuffer.TYPE_SHORT:
+
+            short[] sdata;
+            short[] stemp;
+
+            if (obj == null)
+                sdata = new short[numDataElems*w*h];
+            else
+                sdata = (short[])obj;
+
+            for (int i=y; i<y+h; i++) {
+                for (int j=x; j<x+w; j++) {
+                    o = getDataElements(j, i, o, data);
+                    stemp = (short[])o;
+                    for (int k=0; k<numDataElems; k++) {
+                        sdata[cnt++] = stemp[k];
+                    }
+                }
+            }
+
+            obj = (Object)sdata;
+            break;
+
+        case DataBuffer.TYPE_INT:
+
+            int[] idata;
+            int[] itemp;
+
+            if (obj == null)
+                idata = new int[numDataElems*w*h];
+            else
+                idata = (int[])obj;
+
+            for (int i=y; i<y+h; i++) {
+                for (int j=x; j<x+w; j++) {
+                    o = getDataElements(j, i, o, data);
+                    itemp = (int[])o;
+                    for (int k=0; k<numDataElems; k++) {
+                        idata[cnt++] = itemp[k];
+                    }
+                }
+            }
+
+            obj = (Object)idata;
+            break;
+
+        case DataBuffer.TYPE_FLOAT:
+
+            float[] fdata;
+            float[] ftemp;
+
+            if (obj == null)
+                fdata = new float[numDataElems*w*h];
+            else
+                fdata = (float[])obj;
+
+            for (int i=y; i<y+h; i++) {
+                for (int j=x; j<x+w; j++) {
+                    o = getDataElements(j, i, o, data);
+                    ftemp = (float[])o;
+                    for (int k=0; k<numDataElems; k++) {
+                        fdata[cnt++] = ftemp[k];
+                    }
+                }
+            }
+
+            obj = (Object)fdata;
+            break;
+
+        case DataBuffer.TYPE_DOUBLE:
+
+            double[] ddata;
+            double[] dtemp;
+
+            if (obj == null)
+                ddata = new double[numDataElems*w*h];
+            else
+                ddata = (double[])obj;
+
+            for (int i=y; i<y+h; i++) {
+                for (int j=x; j<x+w; j++) {
+                    o = getDataElements(j, i, o, data);
+                    dtemp = (double[])o;
+                    for (int k=0; k<numDataElems; k++) {
+                        ddata[cnt++] = dtemp[k];
+                    }
+                }
+            }
+
+            obj = (Object)ddata;
+            break;
+        }
+
+        return obj;
+    }
+
+    /**
+     * Sets the data for a single pixel in the specified DataBuffer from a
+     * primitive array of type TransferType.  For image data supported by
+     * the Java 2D API, this will be one of DataBuffer.TYPE_BYTE,
+     * DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT,
+     * DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE.  Data in the array
+     * may be in a packed format, thus increasing efficiency for data
+     * transfers.
+     * <p>
+     * The following code illustrates transferring data for one pixel from
+     * DataBuffer <code>db1</code>, whose storage layout is described by
+     * SampleModel <code>sm1</code>, to DataBuffer <code>db2</code>, whose
+     * storage layout is described by SampleModel <code>sm2</code>.
+     * The transfer will generally be more efficient than using
+     * getPixel/setPixel.
+     * <pre>
+     *       SampleModel sm1, sm2;
+     *       DataBuffer db1, db2;
+     *       sm2.setDataElements(x, y, sm1.getDataElements(x, y, null, db1),
+     *                           db2);
+     * </pre>
+     * Using getDataElements/setDataElements to transfer between two
+     * DataBuffer/SampleModel pairs is legitimate if the SampleModels have
+     * the same number of bands, corresponding bands have the same number of
+     * bits per sample, and the TransferTypes are the same.
+     * <p>
+     * obj must be a primitive array of type TransferType.  Otherwise,
+     * a ClassCastException is thrown.  An
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds, or if obj is not large enough to hold the pixel data.
+     * @param x         The X coordinate of the pixel location.
+     * @param y         The Y coordinate of the pixel location.
+     * @param obj       A primitive array containing pixel data.
+     * @param data      The DataBuffer containing the image data.
+     * @see #getNumDataElements
+     * @see #getTransferType
+     * @see #getDataElements(int, int, Object, DataBuffer)
+     * @see java.awt.image.DataBuffer
+     *
+     * @throws NullPointerException if data is null.
+     * @throws ArrayIndexOutOfBoundsException if the coordinates are
+     * not in bounds, or if obj is too small to hold the input.
+     */
+    public abstract void setDataElements(int x, int y,
+                                         Object obj, DataBuffer data);
+
+    /**
+     * Sets the data for a rectangle of pixels in the specified DataBuffer
+     * from a primitive array of type TransferType.  For image data supported
+     * by the Java 2D API, this will be one of DataBuffer.TYPE_BYTE,
+     * DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT,
+     * DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE.  Data in the array
+     * may be in a packed format, thus increasing efficiency for data
+     * transfers.
+     * <p>
+     * The following code illustrates transferring data for a rectangular
+     * region of pixels from
+     * DataBuffer <code>db1</code>, whose storage layout is described by
+     * SampleModel <code>sm1</code>, to DataBuffer <code>db2</code>, whose
+     * storage layout is described by SampleModel <code>sm2</code>.
+     * The transfer will generally be more efficient than using
+     * getPixels/setPixels.
+     * <pre>
+     *       SampleModel sm1, sm2;
+     *       DataBuffer db1, db2;
+     *       sm2.setDataElements(x, y, w, h, sm1.getDataElements(x, y, w, h,
+     *                           null, db1), db2);
+     * </pre>
+     * Using getDataElements/setDataElements to transfer between two
+     * DataBuffer/SampleModel pairs is legitimate if the SampleModels have
+     * the same number of bands, corresponding bands have the same number of
+     * bits per sample, and the TransferTypes are the same.
+     * <p>
+     * obj must be a primitive array of type TransferType.  Otherwise,
+     * a ClassCastException is thrown.  An
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds, or if obj is not large enough to hold the pixel data.
+     * @param x         The minimum X coordinate of the pixel rectangle.
+     * @param y         The minimum Y coordinate of the pixel rectangle.
+     * @param w         The width of the pixel rectangle.
+     * @param h         The height of the pixel rectangle.
+     * @param obj       A primitive array containing pixel data.
+     * @param data      The DataBuffer containing the image data.
+     * @see #getNumDataElements
+     * @see #getTransferType
+     * @see #getDataElements(int, int, int, int, Object, DataBuffer)
+     * @see java.awt.image.DataBuffer
+     *
+     * @throws NullPointerException if data is null.
+     * @throws ArrayIndexOutOfBoundsException if the coordinates are
+     * not in bounds, or if obj is too small to hold the input.
+     */
+    public void setDataElements(int x, int y, int w, int h,
+                                Object obj, DataBuffer data) {
+
+        int cnt = 0;
+        Object o = null;
+        int type = getTransferType();
+        int numDataElems = getNumDataElements();
+
+        switch(type) {
+
+        case DataBuffer.TYPE_BYTE:
+
+            byte[] barray = (byte[])obj;
+            byte[] btemp = new byte[numDataElems];
+
+            for (int i=y; i<y+h; i++) {
+                for (int j=x; j<x+w; j++) {
+                    for (int k=0; k<numDataElems; k++) {
+                        btemp[k] = barray[cnt++];
+                    }
+
+                    setDataElements(j, i, btemp, data);
+                }
+            }
+            break;
+
+        case DataBuffer.TYPE_USHORT:
+        case DataBuffer.TYPE_SHORT:
+
+            short[] sarray = (short[])obj;
+            short[] stemp = new short[numDataElems];
+
+            for (int i=y; i<y+h; i++) {
+                for (int j=x; j<x+w; j++) {
+                    for (int k=0; k<numDataElems; k++) {
+                        stemp[k] = sarray[cnt++];
+                    }
+
+                    setDataElements(j, i, stemp, data);
+                }
+            }
+            break;
+
+        case DataBuffer.TYPE_INT:
+
+            int[] iArray = (int[])obj;
+            int[] itemp = new int[numDataElems];
+
+            for (int i=y; i<y+h; i++) {
+                for (int j=x; j<x+w; j++) {
+                    for (int k=0; k<numDataElems; k++) {
+                        itemp[k] = iArray[cnt++];
+                    }
+
+                    setDataElements(j, i, itemp, data);
+                }
+            }
+            break;
+
+        case DataBuffer.TYPE_FLOAT:
+
+            float[] fArray = (float[])obj;
+            float[] ftemp = new float[numDataElems];
+
+            for (int i=y; i<y+h; i++) {
+                for (int j=x; j<x+w; j++) {
+                    for (int k=0; k<numDataElems; k++) {
+                        ftemp[k] = fArray[cnt++];
+                    }
+
+                    setDataElements(j, i, ftemp, data);
+                }
+            }
+            break;
+
+        case DataBuffer.TYPE_DOUBLE:
+
+            double[] dArray = (double[])obj;
+            double[] dtemp = new double[numDataElems];
+
+            for (int i=y; i<y+h; i++) {
+                for (int j=x; j<x+w; j++) {
+                    for (int k=0; k<numDataElems; k++) {
+                        dtemp[k] = dArray[cnt++];
+                    }
+
+                    setDataElements(j, i, dtemp, data);
+                }
+            }
+            break;
+        }
+
+    }
+
+    /**
+     * Returns the samples for the specified pixel in an array of float.
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the pixel location.
+     * @param y         The Y coordinate of the pixel location.
+     * @param fArray    If non-null, returns the samples in this array.
+     * @param data      The DataBuffer containing the image data.
+     * @return the samples for the specified pixel.
+     * @see #setPixel(int, int, float[], DataBuffer)
+     *
+     * @throws NullPointerException if data is null.
+     * @throws ArrayIndexOutOfBoundsException if the coordinates are
+     * not in bounds, or if fArray is too small to hold the output.
+     */
+    public float[] getPixel(int x, int y, float fArray[],
+                            DataBuffer data) {
+
+        float pixels[];
+
+        if (fArray != null)
+            pixels = fArray;
+        else
+            pixels = new float[numBands];
+
+        for (int i=0; i<numBands; i++)
+            pixels[i] = getSampleFloat(x, y, i, data);
+
+        return pixels;
+    }
+
+    /**
+     * Returns the samples for the specified pixel in an array of double.
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the pixel location.
+     * @param y         The Y coordinate of the pixel location.
+     * @param dArray    If non-null, returns the samples in this array.
+     * @param data      The DataBuffer containing the image data.
+     * @return the samples for the specified pixel.
+     * @see #setPixel(int, int, double[], DataBuffer)
+     *
+     * @throws NullPointerException if data is null.
+     * @throws ArrayIndexOutOfBoundsException if the coordinates are
+     * not in bounds, or if dArray is too small to hold the output.
+     */
+    public double[] getPixel(int x, int y, double dArray[],
+                             DataBuffer data) {
+
+        double pixels[];
+
+        if(dArray != null)
+            pixels = dArray;
+        else
+            pixels = new double[numBands];
+
+        for (int i=0; i<numBands; i++)
+            pixels[i] = getSampleDouble(x, y, i, data);
+
+        return pixels;
+    }
+
+    /**
+     * Returns all samples for a rectangle of pixels in an
+     * int array, one sample per array element.
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the upper left pixel location.
+     * @param y         The Y coordinate of the upper left pixel location.
+     * @param w         The width of the pixel rectangle.
+     * @param h         The height of the pixel rectangle.
+     * @param iArray    If non-null, returns the samples in this array.
+     * @param data      The DataBuffer containing the image data.
+     * @return the samples for the specified region of pixels.
+     * @see #setPixels(int, int, int, int, int[], DataBuffer)
+     *
+     * @throws NullPointerException if data is null.
+     * @throws ArrayIndexOutOfBoundsException if the coordinates are
+     * not in bounds, or if iArray is too small to hold the output.
+     */
+    public int[] getPixels(int x, int y, int w, int h,
+                           int iArray[], DataBuffer data) {
+
+        int pixels[];
+        int Offset=0;
+
+        if (iArray != null)
+            pixels = iArray;
+        else
+            pixels = new int[numBands * w * h];
+
+        for (int i=y; i<(h+y); i++) {
+            for (int j=x; j<(w+x); j++) {
+                for(int k=0; k<numBands; k++) {
+                    pixels[Offset++] = getSample(j, i, k, data);
+                }
+            }
+        }
+
+        return pixels;
+    }
+
+    /**
+     * Returns all samples for a rectangle of pixels in a float
+     * array, one sample per array element.
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the upper left pixel location.
+     * @param y         The Y coordinate of the upper left pixel location.
+     * @param w         The width of the pixel rectangle.
+     * @param h         The height of the pixel rectangle.
+     * @param fArray    If non-null, returns the samples in this array.
+     * @param data      The DataBuffer containing the image data.
+     * @return the samples for the specified region of pixels.
+     * @see #setPixels(int, int, int, int, float[], DataBuffer)
+     *
+     * @throws NullPointerException if data is null.
+     * @throws ArrayIndexOutOfBoundsException if the coordinates are
+     * not in bounds, or if fArray is too small to hold the output.
+     */
+    public float[] getPixels(int x, int y, int w, int h,
+                             float fArray[], DataBuffer data) {
+
+        float pixels[];
+        int Offset = 0;
+
+        if (fArray != null)
+            pixels = fArray;
+        else
+            pixels = new float[numBands * w * h];
+
+        for (int i=y; i<(h+y); i++) {
+            for(int j=x; j<(w+x); j++) {
+                for(int k=0; k<numBands; k++) {
+                    pixels[Offset++] = getSampleFloat(j, i, k, data);
+                }
+            }
+        }
+
+        return pixels;
+    }
+
+    /**
+     * Returns all samples for a rectangle of pixels in a double
+     * array, one sample per array element.
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the upper left pixel location.
+     * @param y         The Y coordinate of the upper left pixel location.
+     * @param w         The width of the pixel rectangle.
+     * @param h         The height of the pixel rectangle.
+     * @param dArray    If non-null, returns the samples in this array.
+     * @param data      The DataBuffer containing the image data.
+     * @return the samples for the specified region of pixels.
+     * @see #setPixels(int, int, int, int, double[], DataBuffer)
+     *
+     * @throws NullPointerException if data is null.
+     * @throws ArrayIndexOutOfBoundsException if the coordinates are
+     * not in bounds, or if dArray is too small to hold the output.
+     */
+    public double[] getPixels(int x, int y, int w, int h,
+                              double dArray[], DataBuffer data) {
+        double pixels[];
+        int    Offset = 0;
+
+        if (dArray != null)
+            pixels = dArray;
+        else
+            pixels = new double[numBands * w * h];
+
+        // Fix 4217412
+        for (int i=y; i<(h+y); i++) {
+            for (int j=x; j<(w+x); j++) {
+                for (int k=0; k<numBands; k++) {
+                    pixels[Offset++] = getSampleDouble(j, i, k, data);
+                }
+            }
+        }
+
+        return pixels;
+    }
+
+
+    /**
+     * Returns the sample in a specified band for the pixel located
+     * at (x,y) as an int.
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the pixel location.
+     * @param y         The Y coordinate of the pixel location.
+     * @param b         The band to return.
+     * @param data      The DataBuffer containing the image data.
+     * @return the sample in a specified band for the specified pixel.
+     * @see #setSample(int, int, int, int, DataBuffer)
+     *
+     * @throws NullPointerException if data is null.
+     * @throws ArrayIndexOutOfBoundsException if the coordinates or
+     * the band index are not in bounds.
+     */
+    public abstract int getSample(int x, int y, int b, DataBuffer data);
+
+
+    /**
+     * Returns the sample in a specified band
+     * for the pixel located at (x,y) as a float.
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the pixel location.
+     * @param y         The Y coordinate of the pixel location.
+     * @param b         The band to return.
+     * @param data      The DataBuffer containing the image data.
+     * @return the sample in a specified band for the specified pixel.
+     *
+     * @throws NullPointerException if data is null.
+     * @throws ArrayIndexOutOfBoundsException if the coordinates or
+     * the band index are not in bounds.
+     */
+    public float getSampleFloat(int x, int y, int b, DataBuffer data) {
+
+        float sample;
+        sample = (float) getSample(x, y, b, data);
+        return sample;
+    }
+
+    /**
+     * Returns the sample in a specified band
+     * for a pixel located at (x,y) as a double.
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the pixel location.
+     * @param y         The Y coordinate of the pixel location.
+     * @param b         The band to return.
+     * @param data      The DataBuffer containing the image data.
+     * @return the sample in a specified band for the specified pixel.
+     *
+     * @throws NullPointerException if data is null.
+     * @throws ArrayIndexOutOfBoundsException if the coordinates or
+     * the band index are not in bounds.
+     */
+    public double getSampleDouble(int x, int y, int b, DataBuffer data) {
+
+        double sample;
+
+        sample = (double) getSample(x, y, b, data);
+        return sample;
+    }
+
+    /**
+     * Returns the samples for a specified band for the specified rectangle
+     * of pixels in an int array, one sample per array element.
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the upper left pixel location.
+     * @param y         The Y coordinate of the upper left pixel location.
+     * @param w         The width of the pixel rectangle.
+     * @param h         The height of the pixel rectangle.
+     * @param b         The band to return.
+     * @param iArray    If non-null, returns the samples in this array.
+     * @param data      The DataBuffer containing the image data.
+     * @return the samples for the specified band for the specified region
+     *         of pixels.
+     * @see #setSamples(int, int, int, int, int, int[], DataBuffer)
+     *
+     * @throws NullPointerException if data is null.
+     * @throws ArrayIndexOutOfBoundsException if the coordinates or
+     * the band index are not in bounds, or if iArray is too small to
+     * hold the output.
+     */
+    public int[] getSamples(int x, int y, int w, int h, int b,
+                            int iArray[], DataBuffer data) {
+        int pixels[];
+        int Offset=0;
+
+        if (iArray != null)
+            pixels = iArray;
+        else
+            pixels = new int[w * h];
+
+        for(int i=y; i<(h+y); i++) {
+            for (int j=x; j<(w+x); j++) {
+                pixels[Offset++] = getSample(j, i, b, data);
+            }
+        }
+
+        return pixels;
+    }
+
+    /**
+     * Returns the samples for a specified band for the specified rectangle
+     * of pixels in a float array, one sample per array element.
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the upper left pixel location.
+     * @param y         The Y coordinate of the upper left pixel location.
+     * @param w         The width of the pixel rectangle.
+     * @param h         The height of the pixel rectangle.
+     * @param b         The band to return.
+     * @param fArray    If non-null, returns the samples in this array.
+     * @param data      The DataBuffer containing the image data.
+     * @return the samples for the specified band for the specified region
+     *         of pixels.
+     * @see #setSamples(int, int, int, int, int, float[], DataBuffer)
+     *
+     * @throws NullPointerException if data is null.
+     * @throws ArrayIndexOutOfBoundsException if the coordinates or
+     * the band index are not in bounds, or if fArray is too small to
+     * hold the output.
+     */
+    public float[] getSamples(int x, int y, int w, int h,
+                              int b, float fArray[],
+                              DataBuffer data) {
+        float pixels[];
+        int   Offset=0;
+
+        if (fArray != null)
+            pixels = fArray;
+        else
+            pixels = new float[w * h];
+
+        for (int i=y; i<(h+y); i++) {
+            for (int j=x; j<(w+x); j++) {
+                pixels[Offset++] = getSampleFloat(j, i, b, data);
+            }
+        }
+
+        return pixels;
+    }
+
+    /**
+     * Returns the samples for a specified band for a specified rectangle
+     * of pixels in a double array, one sample per array element.
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the upper left pixel location.
+     * @param y         The Y coordinate of the upper left pixel location.
+     * @param w         The width of the pixel rectangle.
+     * @param h         The height of the pixel rectangle.
+     * @param b         The band to return.
+     * @param dArray    If non-null, returns the samples in this array.
+     * @param data      The DataBuffer containing the image data.
+     * @return the samples for the specified band for the specified region
+     *         of pixels.
+     * @see #setSamples(int, int, int, int, int, double[], DataBuffer)
+     *
+     * @throws NullPointerException if data is null.
+     * @throws ArrayIndexOutOfBoundsException if the coordinates or
+     * the band index are not in bounds, or if dArray is too small to
+     * hold the output.
+     */
+    public double[] getSamples(int x, int y, int w, int h,
+                               int b, double dArray[],
+                               DataBuffer data) {
+        double pixels[];
+        int    Offset=0;
+
+        if (dArray != null)
+            pixels = dArray;
+        else
+            pixels = new double[w * h];
+
+        for (int i=y; i<(y+h); i++) {
+            for (int j=x; j<(x+w); j++) {
+                pixels[Offset++] = getSampleDouble(j, i, b, data);
+            }
+        }
+
+        return pixels;
+    }
+
+    /**
+     * Sets a pixel in  the DataBuffer using an int array of samples for input.
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the pixel location.
+     * @param y         The Y coordinate of the pixel location.
+     * @param iArray    The input samples in an int array.
+     * @param data      The DataBuffer containing the image data.
+     * @see #getPixel(int, int, int[], DataBuffer)
+     *
+     * @throws NullPointerException if iArray or data is null.
+     * @throws ArrayIndexOutOfBoundsException if the coordinates are
+     * not in bounds, or if iArray is too small to hold the input.
+     */
+    public void setPixel(int x, int y, int iArray[], DataBuffer data) {
+
+        for (int i=0; i<numBands; i++)
+            setSample(x, y, i, iArray[i], data);
+    }
+
+    /**
+     * Sets a pixel in the DataBuffer using a float array of samples for input.
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the pixel location.
+     * @param y         The Y coordinate of the pixel location.
+     * @param fArray    The input samples in a float array.
+     * @param data      The DataBuffer containing the image data.
+     * @see #getPixel(int, int, float[], DataBuffer)
+     *
+     * @throws NullPointerException if fArray or data is null.
+     * @throws ArrayIndexOutOfBoundsException if the coordinates are
+     * not in bounds, or if fArray is too small to hold the input.
+     */
+    public void setPixel(int x, int y, float fArray[], DataBuffer data) {
+
+        for (int i=0; i<numBands; i++)
+            setSample(x, y, i, fArray[i], data);
+    }
+
+    /**
+     * Sets a pixel in the DataBuffer using a double array of samples
+     * for input.
+     * @param x         The X coordinate of the pixel location.
+     * @param y         The Y coordinate of the pixel location.
+     * @param dArray    The input samples in a double array.
+     * @param data      The DataBuffer containing the image data.
+     * @see #getPixel(int, int, double[], DataBuffer)
+     *
+     * @throws NullPointerException if dArray or data is null.
+     * @throws ArrayIndexOutOfBoundsException if the coordinates are
+     * not in bounds, or if fArray is too small to hold the input.
+     */
+    public void setPixel(int x, int y, double dArray[], DataBuffer data) {
+
+        for (int i=0; i<numBands; i++)
+            setSample(x, y, i, dArray[i], data);
+    }
+
+    /**
+     * Sets all samples for a rectangle of pixels from an int array containing
+     * one sample per array element.
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the upper left pixel location.
+     * @param y         The Y coordinate of the upper left pixel location.
+     * @param w         The width of the pixel rectangle.
+     * @param h         The height of the pixel rectangle.
+     * @param iArray    The input samples in an int array.
+     * @param data      The DataBuffer containing the image data.
+     * @see #getPixels(int, int, int, int, int[], DataBuffer)
+     *
+     * @throws NullPointerException if iArray or data is null.
+     * @throws ArrayIndexOutOfBoundsException if the coordinates are
+     * not in bounds, or if iArray is too small to hold the input.
+     */
+    public void setPixels(int x, int y, int w, int h,
+                          int iArray[], DataBuffer data) {
+        int Offset=0;
+
+        for (int i=y; i<(y+h); i++) {
+            for (int j=x; j<(x+w); j++) {
+                for (int k=0; k<numBands; k++) {
+                    setSample(j, i, k, iArray[Offset++], data);
+                }
+            }
+        }
+    }
+
+    /**
+     * Sets all samples for a rectangle of pixels from a float array containing
+     * one sample per array element.
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the upper left pixel location.
+     * @param y         The Y coordinate of the upper left pixel location.
+     * @param w         The width of the pixel rectangle.
+     * @param h         The height of the pixel rectangle.
+     * @param fArray    The input samples in a float array.
+     * @param data      The DataBuffer containing the image data.
+     * @see #getPixels(int, int, int, int, float[], DataBuffer)
+     *
+     * @throws NullPointerException if fArray or data is null.
+     * @throws ArrayIndexOutOfBoundsException if the coordinates are
+     * not in bounds, or if fArray is too small to hold the input.
+     */
+    public void setPixels(int x, int y, int w, int h,
+                          float fArray[], DataBuffer data) {
+        int Offset=0;
+
+        for (int i=y; i<(y+h); i++) {
+            for (int j=x; j<(x+w); j++) {
+                for(int k=0; k<numBands; k++) {
+                    setSample(j, i, k, fArray[Offset++], data);
+                }
+            }
+        }
+    }
+
+    /**
+     * Sets all samples for a rectangle of pixels from a double array
+     * containing one sample per array element.
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the upper left pixel location.
+     * @param y         The Y coordinate of the upper left pixel location.
+     * @param w         The width of the pixel rectangle.
+     * @param h         The height of the pixel rectangle.
+     * @param dArray    The input samples in a double array.
+     * @param data      The DataBuffer containing the image data.
+     * @see #getPixels(int, int, int, int, double[], DataBuffer)
+     *
+     * @throws NullPointerException if dArray or data is null.
+     * @throws ArrayIndexOutOfBoundsException if the coordinates are
+     * not in bounds, or if dArray is too small to hold the input.
+     */
+    public void setPixels(int x, int y, int w, int h,
+                          double dArray[], DataBuffer data) {
+        int Offset=0;
+
+        for (int i=y; i<(y+h); i++) {
+            for (int j=x; j<(x+w); j++) {
+                for (int k=0; k<numBands; k++) {
+                    setSample(j, i, k, dArray[Offset++], data);
+                }
+            }
+        }
+    }
+
+    /**
+     * Sets a sample in the specified band for the pixel located at (x,y)
+     * in the DataBuffer using an int for input.
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the pixel location.
+     * @param y         The Y coordinate of the pixel location.
+     * @param b         The band to set.
+     * @param s         The input sample as an int.
+     * @param data      The DataBuffer containing the image data.
+     * @see #getSample(int, int, int,  DataBuffer)
+     *
+     * @throws NullPointerException if data is null.
+     * @throws ArrayIndexOutOfBoundsException if the coordinates or
+     * the band index are not in bounds.
+     */
+    public abstract void setSample(int x, int y, int b,
+                                   int s,
+                                   DataBuffer data);
+
+    /**
+     * Sets a sample in the specified band for the pixel located at (x,y)
+     * in the DataBuffer using a float for input.
+     * The default implementation of this method casts the input
+     * float sample to an int and then calls the
+     * <code>setSample(int, int, int, DataBuffer)</code> method using
+     * that int value.
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the pixel location.
+     * @param y         The Y coordinate of the pixel location.
+     * @param b         The band to set.
+     * @param s         The input sample as a float.
+     * @param data      The DataBuffer containing the image data.
+     * @see #getSample(int, int, int, DataBuffer)
+     *
+     * @throws NullPointerException if data is null.
+     * @throws ArrayIndexOutOfBoundsException if the coordinates or
+     * the band index are not in bounds.
+     */
+    public void setSample(int x, int y, int b,
+                          float s ,
+                          DataBuffer data) {
+        int sample = (int)s;
+
+        setSample(x, y, b, sample, data);
+    }
+
+    /**
+     * Sets a sample in the specified band for the pixel located at (x,y)
+     * in the DataBuffer using a double for input.
+     * The default implementation of this method casts the input
+     * double sample to an int and then calls the
+     * <code>setSample(int, int, int, DataBuffer)</code> method using
+     * that int value.
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the pixel location.
+     * @param y         The Y coordinate of the pixel location.
+     * @param b         The band to set.
+     * @param s         The input sample as a double.
+     * @param data      The DataBuffer containing the image data.
+     * @see #getSample(int, int, int, DataBuffer)
+     *
+     * @throws NullPointerException if data is null.
+     * @throws ArrayIndexOutOfBoundsException if the coordinates or
+     * the band index are not in bounds.
+     */
+    public void setSample(int x, int y, int b,
+                          double s,
+                          DataBuffer data) {
+        int sample = (int)s;
+
+        setSample(x, y, b, sample, data);
+    }
+
+    /**
+     * Sets the samples in the specified band for the specified rectangle
+     * of pixels from an int array containing one sample per array element.
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the upper left pixel location.
+     * @param y         The Y coordinate of the upper left pixel location.
+     * @param w         The width of the pixel rectangle.
+     * @param h         The height of the pixel rectangle.
+     * @param b         The band to set.
+     * @param iArray    The input samples in an int array.
+     * @param data      The DataBuffer containing the image data.
+     * @see #getSamples(int, int, int, int, int, int[], DataBuffer)
+     *
+     * @throws NullPointerException if iArray or data is null.
+     * @throws ArrayIndexOutOfBoundsException if the coordinates or
+     * the band index are not in bounds, or if iArray is too small to
+     * hold the input.
+     */
+    public void setSamples(int x, int y, int w, int h, int b,
+                           int iArray[], DataBuffer data) {
+
+        int Offset=0;
+
+        for (int i=y; i<(y+h); i++) {
+            for (int j=x; j<(x+w); j++) {
+                setSample(j, i, b, iArray[Offset++], data);
+            }
+        }
+    }
+
+    /**
+     * Sets the samples in the specified band for the specified rectangle
+     * of pixels from a float array containing one sample per array element.
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the upper left pixel location.
+     * @param y         The Y coordinate of the upper left pixel location.
+     * @param w         The width of the pixel rectangle.
+     * @param h         The height of the pixel rectangle.
+     * @param b         The band to set.
+     * @param fArray    The input samples in a float array.
+     * @param data      The DataBuffer containing the image data.
+     * @see #getSamples(int, int, int, int, int, float[], DataBuffer)
+     *
+     * @throws NullPointerException if fArray or data is null.
+     * @throws ArrayIndexOutOfBoundsException if the coordinates or
+     * the band index are not in bounds, or if fArray is too small to
+     * hold the input.
+     */
+    public void setSamples(int x, int y, int w, int h, int b,
+                           float fArray[], DataBuffer data) {
+        int Offset=0;
+
+        for (int i=y; i<(y+h); i++) {
+            for (int j=x; j<(x+w); j++) {
+                setSample(j, i, b, fArray[Offset++], data);
+            }
+        }
+    }
+
+    /**
+     * Sets the samples in the specified band for the specified rectangle
+     * of pixels from a double array containing one sample per array element.
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the upper left pixel location.
+     * @param y         The Y coordinate of the upper left pixel location.
+     * @param w         The width of the pixel rectangle.
+     * @param h         The height of the pixel rectangle.
+     * @param b         The band to set.
+     * @param dArray    The input samples in a double array.
+     * @param data      The DataBuffer containing the image data.
+     * @see #getSamples(int, int, int, int, int, double[], DataBuffer)
+     *
+     * @throws NullPointerException if dArray or data is null.
+     * @throws ArrayIndexOutOfBoundsException if the coordinates or
+     * the band index are not in bounds, or if dArray is too small to
+     * hold the input.
+     */
+    public void setSamples(int x, int y, int w, int h, int b,
+                           double dArray[], DataBuffer data) {
+        int Offset=0;
+
+        for (int i=y; i<(y+h); i++) {
+            for (int j=x; j<(x+w); j++) {
+                setSample(j, i, b, dArray[Offset++], data);
+            }
+        }
+    }
+
+    /**
+     *  Creates a SampleModel which describes data in this SampleModel's
+     *  format, but with a different width and height.
+     *  @param w the width of the image data
+     *  @param h the height of the image data
+     *  @return a <code>SampleModel</code> describing the same image
+     *          data as this <code>SampleModel</code>, but with a
+     *          different size.
+     */
+    public abstract SampleModel createCompatibleSampleModel(int w, int h);
+
+    /**
+     * Creates a new SampleModel
+     * with a subset of the bands of this
+     * SampleModel.
+     * @param bands the subset of bands of this <code>SampleModel</code>
+     * @return a <code>SampleModel</code> with a subset of bands of this
+     *         <code>SampleModel</code>.
+     */
+    public abstract SampleModel createSubsetSampleModel(int bands[]);
+
+    /**
+     * Creates a DataBuffer that corresponds to this SampleModel.
+     * The DataBuffer's width and height will match this SampleModel's.
+     * @return a <code>DataBuffer</code> corresponding to this
+     *         <code>SampleModel</code>.
+     */
+    public abstract DataBuffer createDataBuffer();
+
+    /** Returns the size in bits of samples for all bands.
+     *  @return the size of samples for all bands.
+     */
+    public abstract int[] getSampleSize();
+
+    /** Returns the size in bits of samples for the specified band.
+     *  @param band the specified band
+     *  @return the size of the samples of the specified band.
+     */
+    public abstract int getSampleSize(int band);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/awt/image/SinglePixelPackedSampleModel.java	Thu Apr 10 16:28:45 2008 -0700
@@ -0,0 +1,805 @@
+/*
+ * Portions Copyright 1997-2001 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* ****************************************************************
+ ******************************************************************
+ ******************************************************************
+ *** COPYRIGHT (c) Eastman Kodak Company, 1997
+ *** As  an unpublished  work pursuant to Title 17 of the United
+ *** States Code.  All rights reserved.
+ ******************************************************************
+ ******************************************************************
+ ******************************************************************/
+
+package java.awt.image;
+
+import java.util.Arrays;
+
+/**
+ *  This class represents pixel data packed such that the N samples which make
+ *  up a single pixel are stored in a single data array element, and each data
+ *  data array element holds samples for only one pixel.
+ *  This class supports
+ *  {@link DataBuffer#TYPE_BYTE TYPE_BYTE},
+ *  {@link DataBuffer#TYPE_USHORT TYPE_USHORT},
+ *  {@link DataBuffer#TYPE_INT TYPE_INT} data types.
+ *  All data array elements reside
+ *  in the first bank of a DataBuffer.  Accessor methods are provided so
+ *  that the image data can be manipulated directly. Scanline stride is the
+ *  number of data array elements between a given sample and the corresponding
+ *  sample in the same column of the next scanline. Bit masks are the masks
+ *  required to extract the samples representing the bands of the pixel.
+ *  Bit offsets are the offsets in bits into the data array
+ *  element of the samples representing the bands of the pixel.
+ * <p>
+ * The following code illustrates extracting the bits of the sample
+ * representing band <code>b</code> for pixel <code>x,y</code>
+ * from DataBuffer <code>data</code>:
+ * <pre>
+ *      int sample = data.getElem(y * scanlineStride + x);
+ *      sample = (sample & bitMasks[b]) >>> bitOffsets[b];
+ * </pre>
+ */
+
+public class SinglePixelPackedSampleModel extends SampleModel
+{
+    /** Bit masks for all bands of the image data. */
+    private int bitMasks[];
+
+    /** Bit Offsets for all bands of the image data. */
+    private int bitOffsets[];
+
+    /** Bit sizes for all the bands of the image data. */
+    private int bitSizes[];
+
+    /** Maximum bit size. */
+    private int maxBitSize;
+
+    /** Line stride of the region of image data described by this
+     *  SinglePixelPackedSampleModel.
+     */
+    private int scanlineStride;
+
+    private static native void initIDs();
+    static {
+        ColorModel.loadLibraries();
+        initIDs();
+    }
+
+    /**
+     * Constructs a SinglePixelPackedSampleModel with bitMasks.length bands.
+     * Each sample is stored in a data array element in the position of
+     * its corresponding bit mask.  Each bit mask must be contiguous and
+     * masks must not overlap.
+     * @param dataType  The data type for storing samples.
+     * @param w         The width (in pixels) of the region of the
+     *                  image data described.
+     * @param h         The height (in pixels) of the region of the
+     *                  image data described.
+     * @param bitMasks  The bit masks for all bands.
+     * @throws IllegalArgumentException if <code>dataType</code> is not
+     *         either <code>DataBuffer.TYPE_BYTE</code>,
+     *         <code>DataBuffer.TYPE_USHORT</code>, or
+     *         <code>DataBuffer.TYPE_INT</code>
+     */
+    public SinglePixelPackedSampleModel(int dataType, int w, int h,
+                                   int bitMasks[]) {
+        this(dataType, w, h, w, bitMasks);
+        if (dataType != DataBuffer.TYPE_BYTE &&
+            dataType != DataBuffer.TYPE_USHORT &&
+            dataType != DataBuffer.TYPE_INT) {
+            throw new IllegalArgumentException("Unsupported data type "+
+                                               dataType);
+        }
+    }
+
+    /**
+     * Constructs a SinglePixelPackedSampleModel with bitMasks.length bands
+     * and a scanline stride equal to scanlineStride data array elements.
+     * Each sample is stored in a data array element in the position of
+     * its corresponding bit mask.  Each bit mask must be contiguous and
+     * masks must not overlap.
+     * @param dataType  The data type for storing samples.
+     * @param w         The width (in pixels) of the region of
+     *                  image data described.
+     * @param h         The height (in pixels) of the region of
+     *                  image data described.
+     * @param scanlineStride The line stride of the image data.
+     * @param bitMasks The bit masks for all bands.
+     * @throws IllegalArgumentException if <code>w</code> or
+     *         <code>h</code> is not greater than 0
+     * @throws IllegalArgumentException if any mask in
+     *         <code>bitMask</code> is not contiguous
+     * @throws IllegalArgumentException if <code>dataType</code> is not
+     *         either <code>DataBuffer.TYPE_BYTE</code>,
+     *         <code>DataBuffer.TYPE_USHORT</code>, or
+     *         <code>DataBuffer.TYPE_INT</code>
+     */
+    public SinglePixelPackedSampleModel(int dataType, int w, int h,
+                                   int scanlineStride, int bitMasks[]) {
+        super(dataType, w, h, bitMasks.length);
+        if (dataType != DataBuffer.TYPE_BYTE &&
+            dataType != DataBuffer.TYPE_USHORT &&
+            dataType != DataBuffer.TYPE_INT) {
+            throw new IllegalArgumentException("Unsupported data type "+
+                                               dataType);
+        }
+        this.dataType = dataType;
+        this.bitMasks = (int[]) bitMasks.clone();
+        this.scanlineStride = scanlineStride;
+
+        this.bitOffsets = new int[numBands];
+        this.bitSizes = new int[numBands];
+
+        this.maxBitSize = 0;
+        for (int i=0; i<numBands; i++) {
+            int bitOffset = 0, bitSize = 0, mask;
+            mask = bitMasks[i];
+
+            if (mask != 0) {
+                while ((mask & 1) == 0) {
+                    mask = mask >>> 1;
+                    bitOffset++;
+                }
+                while ((mask & 1) == 1) {
+                    mask = mask >>> 1;
+                    bitSize++;
+                }
+                if (mask != 0) {
+                    throw new IllegalArgumentException("Mask "+bitMasks[i]+
+                                                       " must be contiguous");
+                }
+            }
+            bitOffsets[i] = bitOffset;
+            bitSizes[i] = bitSize;
+            if (bitSize > maxBitSize) {
+                maxBitSize = bitSize;
+            }
+        }
+    }
+
+    /**
+     * Returns the number of data elements needed to transfer one pixel
+     * via the getDataElements and setDataElements methods.
+     * For a SinglePixelPackedSampleModel, this is one.
+     */
+    public int getNumDataElements() {
+        return 1;
+    }
+
+    /**
+     * Returns the size of the buffer (in data array elements)
+     * needed for a data buffer that matches this
+     * SinglePixelPackedSampleModel.
+     */
+    private long getBufferSize() {
+      long size = scanlineStride * (height-1) + width;
+      return size;
+    }
+
+    /**
+     * Creates a new SinglePixelPackedSampleModel with the specified
+     * width and height.  The new SinglePixelPackedSampleModel will have the
+     * same storage data type and bit masks as this
+     * SinglePixelPackedSampleModel.
+     * @param w the width of the resulting <code>SampleModel</code>
+     * @param h the height of the resulting <code>SampleModel</code>
+     * @return a <code>SinglePixelPackedSampleModel</code> with the
+     *         specified width and height.
+     * @throws IllegalArgumentException if <code>w</code> or
+     *         <code>h</code> is not greater than 0
+     */
+    public SampleModel createCompatibleSampleModel(int w, int h) {
+      SampleModel sampleModel = new SinglePixelPackedSampleModel(dataType, w, h,
+                                                              bitMasks);
+      return sampleModel;
+    }
+
+    /**
+     * Creates a DataBuffer that corresponds to this
+     * SinglePixelPackedSampleModel.  The DataBuffer's data type and size
+     * will be consistent with this SinglePixelPackedSampleModel.  The
+     * DataBuffer will have a single bank.
+     */
+    public DataBuffer createDataBuffer() {
+        DataBuffer dataBuffer = null;
+
+        int size = (int)getBufferSize();
+        switch (dataType) {
+        case DataBuffer.TYPE_BYTE:
+            dataBuffer = new DataBufferByte(size);
+            break;
+        case DataBuffer.TYPE_USHORT:
+            dataBuffer = new DataBufferUShort(size);
+            break;
+        case DataBuffer.TYPE_INT:
+            dataBuffer = new DataBufferInt(size);
+            break;
+        }
+        return dataBuffer;
+    }
+
+    /** Returns the number of bits per sample for all bands. */
+    public int[] getSampleSize() {
+        int mask;
+        int sampleSize[] = new int [numBands];
+        for (int i=0; i<numBands; i++) {
+            sampleSize[i] = 0;
+            mask = bitMasks[i] >>> bitOffsets[i];
+            while ((mask & 1) != 0) {
+                sampleSize[i] ++;
+                mask = mask >>> 1;
+            }
+        }
+
+        return sampleSize;
+    }
+
+    /** Returns the number of bits per sample for the specified band. */
+    public int getSampleSize(int band) {
+        int sampleSize = 0;
+        int mask = bitMasks[band] >>> bitOffsets[band];
+        while ((mask & 1) != 0) {
+            sampleSize ++;
+            mask = mask >>> 1;
+        }
+
+        return sampleSize;
+    }
+
+    /** Returns the offset (in data array elements) of pixel (x,y).
+     *  The data element containing pixel <code>x,y</code>
+     *  can be retrieved from a DataBuffer <code>data</code> with a
+     *  SinglePixelPackedSampleModel <code>sppsm</code> as:
+     * <pre>
+     *        data.getElem(sppsm.getOffset(x, y));
+     * </pre>
+     * @param x the X coordinate of the specified pixel
+     * @param y the Y coordinate of the specified pixel
+     * @return the offset of the specified pixel.
+     */
+    public int getOffset(int x, int y) {
+        int offset = y * scanlineStride + x;
+        return offset;
+    }
+
+    /** Returns the bit offsets into the data array element representing
+     *  a pixel for all bands.
+     *  @return the bit offsets representing a pixel for all bands.
+     */
+    public int [] getBitOffsets() {
+      return (int[])bitOffsets.clone();
+    }
+
+    /** Returns the bit masks for all bands.
+     *  @return the bit masks for all bands.
+     */
+    public int [] getBitMasks() {
+      return (int[])bitMasks.clone();
+    }
+
+    /** Returns the scanline stride of this SinglePixelPackedSampleModel.
+     *  @return the scanline stride of this
+     *          <code>SinglePixelPackedSampleModel</code>.
+     */
+    public int getScanlineStride() {
+      return scanlineStride;
+    }
+
+    /**
+     * This creates a new SinglePixelPackedSampleModel with a subset of the
+     * bands of this SinglePixelPackedSampleModel.  The new
+     * SinglePixelPackedSampleModel can be used with any DataBuffer that the
+     * existing SinglePixelPackedSampleModel can be used with.  The new
+     * SinglePixelPackedSampleModel/DataBuffer combination will represent
+     * an image with a subset of the bands of the original
+     * SinglePixelPackedSampleModel/DataBuffer combination.
+     * @exception RasterFormatException if the length of the bands argument is
+     *                                  greater than the number of bands in
+     *                                  the sample model.
+     */
+    public SampleModel createSubsetSampleModel(int bands[]) {
+        if (bands.length > numBands)
+            throw new RasterFormatException("There are only " +
+                                            numBands +
+                                            " bands");
+        int newBitMasks[] = new int[bands.length];
+        for (int i=0; i<bands.length; i++)
+            newBitMasks[i] = bitMasks[bands[i]];
+
+        return new SinglePixelPackedSampleModel(this.dataType, width, height,
+                                           this.scanlineStride, newBitMasks);
+    }
+
+    /**
+     * Returns data for a single pixel in a primitive array of type
+     * TransferType.  For a SinglePixelPackedSampleModel, the array will
+     * have one element, and the type will be the same as the storage
+     * data type.  Generally, obj
+     * should be passed in as null, so that the Object will be created
+     * automatically and will be of the right primitive data type.
+     * <p>
+     * The following code illustrates transferring data for one pixel from
+     * DataBuffer <code>db1</code>, whose storage layout is described by
+     * SinglePixelPackedSampleModel <code>sppsm1</code>, to
+     * DataBuffer <code>db2</code>, whose storage layout is described by
+     * SinglePixelPackedSampleModel <code>sppsm2</code>.
+     * The transfer will generally be more efficient than using
+     * getPixel/setPixel.
+     * <pre>
+     *       SinglePixelPackedSampleModel sppsm1, sppsm2;
+     *       DataBufferInt db1, db2;
+     *       sppsm2.setDataElements(x, y, sppsm1.getDataElements(x, y, null,
+     *                              db1), db2);
+     * </pre>
+     * Using getDataElements/setDataElements to transfer between two
+     * DataBuffer/SampleModel pairs is legitimate if the SampleModels have
+     * the same number of bands, corresponding bands have the same number of
+     * bits per sample, and the TransferTypes are the same.
+     * <p>
+     * If obj is non-null, it should be a primitive array of type TransferType.
+     * Otherwise, a ClassCastException is thrown.  An
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds, or if obj is non-null and is not large enough to hold
+     * the pixel data.
+     * @param x         The X coordinate of the pixel location.
+     * @param y         The Y coordinate of the pixel location.
+     * @param obj       If non-null, a primitive array in which to return
+     *                  the pixel data.
+     * @param data      The DataBuffer containing the image data.
+     * @return the data for the specified pixel.
+     * @see #setDataElements(int, int, Object, DataBuffer)
+     */
+    public Object getDataElements(int x, int y, Object obj, DataBuffer data) {
+        // Bounds check for 'b' will be performed automatically
+        if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+
+        int type = getTransferType();
+
+        switch(type) {
+
+        case DataBuffer.TYPE_BYTE:
+
+            byte[] bdata;
+
+            if (obj == null)
+                bdata = new byte[1];
+            else
+                bdata = (byte[])obj;
+
+            bdata[0] = (byte)data.getElem(y * scanlineStride + x);
+
+            obj = (Object)bdata;
+            break;
+
+        case DataBuffer.TYPE_USHORT:
+
+            short[] sdata;
+
+            if (obj == null)
+                sdata = new short[1];
+            else
+                sdata = (short[])obj;
+
+            sdata[0] = (short)data.getElem(y * scanlineStride + x);
+
+            obj = (Object)sdata;
+            break;
+
+        case DataBuffer.TYPE_INT:
+
+            int[] idata;
+
+            if (obj == null)
+                idata = new int[1];
+            else
+                idata = (int[])obj;
+
+            idata[0] = data.getElem(y * scanlineStride + x);
+
+            obj = (Object)idata;
+            break;
+        }
+
+        return obj;
+    }
+
+    /**
+     * Returns all samples in for the specified pixel in an int array.
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the pixel location.
+     * @param y         The Y coordinate of the pixel location.
+     * @param iArray    If non-null, returns the samples in this array
+     * @param data      The DataBuffer containing the image data.
+     * @return all samples for the specified pixel.
+     * @see #setPixel(int, int, int[], DataBuffer)
+     */
+    public int [] getPixel(int x, int y, int iArray[], DataBuffer data) {
+        if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+        int pixels[];
+        if (iArray == null) {
+            pixels = new int [numBands];
+        } else {
+            pixels = iArray;
+        }
+
+        int value = data.getElem(y * scanlineStride + x);
+        for (int i=0; i<numBands; i++) {
+            pixels[i] = (value & bitMasks[i]) >>> bitOffsets[i];
+        }
+        return pixels;
+    }
+
+    /**
+     * Returns all samples for the specified rectangle of pixels in
+     * an int array, one sample per array element.
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the upper left pixel location.
+     * @param y         The Y coordinate of the upper left pixel location.
+     * @param w         The width of the pixel rectangle.
+     * @param h         The height of the pixel rectangle.
+     * @param iArray    If non-null, returns the samples in this array.
+     * @param data      The DataBuffer containing the image data.
+     * @return all samples for the specified region of pixels.
+     * @see #setPixels(int, int, int, int, int[], DataBuffer)
+     */
+    public int[] getPixels(int x, int y, int w, int h,
+                           int iArray[], DataBuffer data) {
+        if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+        int pixels[];
+        if (iArray != null) {
+           pixels = iArray;
+        } else {
+           pixels = new int [w*h*numBands];
+        }
+        int lineOffset = y*scanlineStride + x;
+        int dstOffset = 0;
+
+        for (int i = 0; i < h; i++) {
+           for (int j = 0; j < w; j++) {
+              int value = data.getElem(lineOffset+j);
+              for (int k=0; k < numBands; k++) {
+                  pixels[dstOffset++] =
+                     ((value & bitMasks[k]) >>> bitOffsets[k]);
+              }
+           }
+           lineOffset += scanlineStride;
+        }
+        return pixels;
+    }
+
+    /**
+     * Returns as int the sample in a specified band for the pixel
+     * located at (x,y).
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the pixel location.
+     * @param y         The Y coordinate of the pixel location.
+     * @param b         The band to return.
+     * @param data      The DataBuffer containing the image data.
+     * @return the sample in a specified band for the specified
+     *         pixel.
+     * @see #setSample(int, int, int, int, DataBuffer)
+     */
+    public int getSample(int x, int y, int b, DataBuffer data) {
+        // Bounds check for 'b' will be performed automatically
+        if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+        int sample = data.getElem(y * scanlineStride + x);
+        return ((sample & bitMasks[b]) >>> bitOffsets[b]);
+    }
+
+    /**
+     * Returns the samples for a specified band for the specified rectangle
+     * of pixels in an int array, one sample per array element.
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the upper left pixel location.
+     * @param y         The Y coordinate of the upper left pixel location.
+     * @param w         The width of the pixel rectangle.
+     * @param h         The height of the pixel rectangle.
+     * @param b         The band to return.
+     * @param iArray    If non-null, returns the samples in this array.
+     * @param data      The DataBuffer containing the image data.
+     * @return the samples for the specified band for the specified
+     *         region of pixels.
+     * @see #setSamples(int, int, int, int, int, int[], DataBuffer)
+     */
+    public int[] getSamples(int x, int y, int w, int h, int b,
+                           int iArray[], DataBuffer data) {
+        // Bounds check for 'b' will be performed automatically
+        if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+        int samples[];
+        if (iArray != null) {
+           samples = iArray;
+        } else {
+           samples = new int [w*h];
+        }
+        int lineOffset = y*scanlineStride + x;
+        int dstOffset = 0;
+
+        for (int i = 0; i < h; i++) {
+           for (int j = 0; j < w; j++) {
+              int value = data.getElem(lineOffset+j);
+              samples[dstOffset++] =
+                 ((value & bitMasks[b]) >>> bitOffsets[b]);
+           }
+           lineOffset += scanlineStride;
+        }
+        return samples;
+    }
+
+    /**
+     * Sets the data for a single pixel in the specified DataBuffer from a
+     * primitive array of type TransferType.  For a
+     * SinglePixelPackedSampleModel, only the first element of the array
+     * will hold valid data, and the type of the array must be the same as
+     * the storage data type of the SinglePixelPackedSampleModel.
+     * <p>
+     * The following code illustrates transferring data for one pixel from
+     * DataBuffer <code>db1</code>, whose storage layout is described by
+     * SinglePixelPackedSampleModel <code>sppsm1</code>,
+     * to DataBuffer <code>db2</code>, whose storage layout is described by
+     * SinglePixelPackedSampleModel <code>sppsm2</code>.
+     * The transfer will generally be more efficient than using
+     * getPixel/setPixel.
+     * <pre>
+     *       SinglePixelPackedSampleModel sppsm1, sppsm2;
+     *       DataBufferInt db1, db2;
+     *       sppsm2.setDataElements(x, y, sppsm1.getDataElements(x, y, null,
+     *                              db1), db2);
+     * </pre>
+     * Using getDataElements/setDataElements to transfer between two
+     * DataBuffer/SampleModel pairs is legitimate if the SampleModels have
+     * the same number of bands, corresponding bands have the same number of
+     * bits per sample, and the TransferTypes are the same.
+     * <p>
+     * obj must be a primitive array of type TransferType.  Otherwise,
+     * a ClassCastException is thrown.  An
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds, or if obj is not large enough to hold the pixel data.
+     * @param x         The X coordinate of the pixel location.
+     * @param y         The Y coordinate of the pixel location.
+     * @param obj       A primitive array containing pixel data.
+     * @param data      The DataBuffer containing the image data.
+     * @see #getDataElements(int, int, Object, DataBuffer)
+     */
+    public void setDataElements(int x, int y, Object obj, DataBuffer data) {
+        if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+
+        int type = getTransferType();
+
+        switch(type) {
+
+        case DataBuffer.TYPE_BYTE:
+
+            byte[] barray = (byte[])obj;
+            data.setElem(y*scanlineStride+x, ((int)barray[0])&0xff);
+            break;
+
+        case DataBuffer.TYPE_USHORT:
+
+            short[] sarray = (short[])obj;
+            data.setElem(y*scanlineStride+x, ((int)sarray[0])&0xffff);
+            break;
+
+        case DataBuffer.TYPE_INT:
+
+            int[] iarray = (int[])obj;
+            data.setElem(y*scanlineStride+x, iarray[0]);
+            break;
+        }
+    }
+
+    /**
+     * Sets a pixel in the DataBuffer using an int array of samples for input.
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the pixel location.
+     * @param y         The Y coordinate of the pixel location.
+     * @param iArray    The input samples in an int array.
+     * @param data      The DataBuffer containing the image data.
+     * @see #getPixel(int, int, int[], DataBuffer)
+     */
+    public void setPixel(int x, int y,
+                         int iArray[],
+                         DataBuffer data) {
+        if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+        int lineOffset = y * scanlineStride + x;
+        int value = data.getElem(lineOffset);
+        for (int i=0; i < numBands; i++) {
+            value &= ~bitMasks[i];
+            value |= ((iArray[i] << bitOffsets[i]) & bitMasks[i]);
+        }
+        data.setElem(lineOffset, value);
+    }
+
+    /**
+     * Sets all samples for a rectangle of pixels from an int array containing
+     * one sample per array element.
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the upper left pixel location.
+     * @param y         The Y coordinate of the upper left pixel location.
+     * @param w         The width of the pixel rectangle.
+     * @param h         The height of the pixel rectangle.
+     * @param iArray    The input samples in an int array.
+     * @param data      The DataBuffer containing the image data.
+     * @see #getPixels(int, int, int, int, int[], DataBuffer)
+     */
+    public void setPixels(int x, int y, int w, int h,
+                          int iArray[], DataBuffer data) {
+        if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+
+        int lineOffset = y*scanlineStride + x;
+        int srcOffset = 0;
+
+        for (int i = 0; i < h; i++) {
+           for (int j = 0; j < w; j++) {
+               int value = data.getElem(lineOffset+j);
+               for (int k=0; k < numBands; k++) {
+                   value &= ~bitMasks[k];
+                   int srcValue = iArray[srcOffset++];
+                   value |= ((srcValue << bitOffsets[k])
+                             & bitMasks[k]);
+               }
+               data.setElem(lineOffset+j, value);
+           }
+           lineOffset += scanlineStride;
+        }
+    }
+
+    /**
+     * Sets a sample in the specified band for the pixel located at (x,y)
+     * in the DataBuffer using an int for input.
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the pixel location.
+     * @param y         The Y coordinate of the pixel location.
+     * @param b         The band to set.
+     * @param s         The input sample as an int.
+     * @param data      The DataBuffer containing the image data.
+     * @see #getSample(int, int, int, DataBuffer)
+     */
+    public void setSample(int x, int y, int b, int s,
+                          DataBuffer data) {
+        // Bounds check for 'b' will be performed automatically
+        if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+        int value = data.getElem(y*scanlineStride + x);
+        value &= ~bitMasks[b];
+        value |= (s << bitOffsets[b]) & bitMasks[b];
+        data.setElem(y*scanlineStride + x,value);
+    }
+
+    /**
+     * Sets the samples in the specified band for the specified rectangle
+     * of pixels from an int array containing one sample per array element.
+     * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * @param x         The X coordinate of the upper left pixel location.
+     * @param y         The Y coordinate of the upper left pixel location.
+     * @param w         The width of the pixel rectangle.
+     * @param h         The height of the pixel rectangle.
+     * @param b         The band to set.
+     * @param iArray    The input samples in an int array.
+     * @param data      The DataBuffer containing the image data.
+     * @see #getSamples(int, int, int, int, int, int[], DataBuffer)
+     */
+    public void setSamples(int x, int y, int w, int h, int b,
+                          int iArray[], DataBuffer data) {
+        // Bounds check for 'b' will be performed automatically
+        if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+        int lineOffset = y*scanlineStride + x;
+        int srcOffset = 0;
+
+        for (int i = 0; i < h; i++) {
+           for (int j = 0; j < w; j++) {
+              int value = data.getElem(lineOffset+j);
+              value &= ~bitMasks[b];
+              int sample = iArray[srcOffset++];
+              value |= ((int)sample << bitOffsets[b]) & bitMasks[b];
+              data.setElem(lineOffset+j,value);
+           }
+           lineOffset += scanlineStride;
+        }
+    }
+
+    public boolean equals(Object o) {
+        if ((o == null) || !(o instanceof SinglePixelPackedSampleModel)) {
+            return false;
+        }
+
+        SinglePixelPackedSampleModel that = (SinglePixelPackedSampleModel)o;
+        return this.width == that.width &&
+            this.height == that.height &&
+            this.numBands == that.numBands &&
+            this.dataType == that.dataType &&
+            Arrays.equals(this.bitMasks, that.bitMasks) &&
+            Arrays.equals(this.bitOffsets, that.bitOffsets) &&
+            Arrays.equals(this.bitSizes, that.bitSizes) &&
+            this.maxBitSize == that.maxBitSize &&
+            this.scanlineStride == that.scanlineStride;
+    }
+
+    // If we implement equals() we must also implement hashCode
+    public int hashCode() {
+        int hash = 0;
+        hash = width;
+        hash <<= 8;
+        hash ^= height;
+        hash <<= 8;
+        hash ^= numBands;
+        hash <<= 8;
+        hash ^= dataType;
+        hash <<= 8;
+        for (int i = 0; i < bitMasks.length; i++) {
+            hash ^= bitMasks[i];
+            hash <<= 8;
+        }
+        for (int i = 0; i < bitOffsets.length; i++) {
+            hash ^= bitOffsets[i];
+            hash <<= 8;
+        }
+        for (int i = 0; i < bitSizes.length; i++) {
+            hash ^= bitSizes[i];
+            hash <<= 8;
+        }
+        hash ^= maxBitSize;
+        hash <<= 8;
+        hash ^= scanlineStride;
+        return hash;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/awt/image/WritableRaster.java	Thu Apr 10 16:28:45 2008 -0700
@@ -0,0 +1,741 @@
+/*
+ * Portions Copyright 1997-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* ****************************************************************
+ ******************************************************************
+ ******************************************************************
+ *** COPYRIGHT (c) Eastman Kodak Company, 1997
+ *** As  an unpublished  work pursuant to Title 17 of the United
+ *** States Code.  All rights reserved.
+ ******************************************************************
+ ******************************************************************
+ ******************************************************************/
+
+package java.awt.image;
+import java.awt.Rectangle;
+import java.awt.Point;
+
+/**
+ * This class extends Raster to provide pixel writing capabilities.
+ * Refer to the class comment for Raster for descriptions of how
+ * a Raster stores pixels.
+ *
+ * <p> The constructors of this class are protected.  To instantiate
+ * a WritableRaster, use one of the createWritableRaster factory methods
+ * in the Raster class.
+ */
+public class WritableRaster extends Raster {
+
+    /**
+     *  Constructs a WritableRaster with the given SampleModel.  The
+     *  WritableRaster's upper left corner is origin and it is the
+     *  same size as the  SampleModel.  A DataBuffer large enough to
+     *  describe the WritableRaster is automatically created.
+     *  @param sampleModel     The SampleModel that specifies the layout.
+     *  @param origin          The Point that specifies the origin.
+     *  @throws RasterFormatException if computing either
+     *          <code>origin.x + sampleModel.getWidth()</code> or
+     *          <code>origin.y + sampleModel.getHeight()</code> results
+     *          in integer overflow
+     */
+    protected WritableRaster(SampleModel sampleModel,
+                             Point origin) {
+        this(sampleModel,
+             sampleModel.createDataBuffer(),
+             new Rectangle(origin.x,
+                           origin.y,
+                           sampleModel.getWidth(),
+                           sampleModel.getHeight()),
+             origin,
+             null);
+    }
+
+    /**
+     *  Constructs a WritableRaster with the given SampleModel and DataBuffer.
+     *  The WritableRaster's upper left corner is origin and it is the same
+     *  size as the SampleModel.  The DataBuffer is not initialized and must
+     *  be compatible with SampleModel.
+     *  @param sampleModel     The SampleModel that specifies the layout.
+     *  @param dataBuffer      The DataBuffer that contains the image data.
+     *  @param origin          The Point that specifies the origin.
+     *  @throws RasterFormatException if computing either
+     *          <code>origin.x + sampleModel.getWidth()</code> or
+     *          <code>origin.y + sampleModel.getHeight()</code> results
+     *          in integer overflow
+     */
+    protected WritableRaster(SampleModel sampleModel,
+                             DataBuffer dataBuffer,
+                             Point origin) {
+        this(sampleModel,
+             dataBuffer,
+             new Rectangle(origin.x,
+                           origin.y,
+                           sampleModel.getWidth(),
+                           sampleModel.getHeight()),
+             origin,
+             null);
+    }
+
+    /**
+     * Constructs a WritableRaster with the given SampleModel, DataBuffer,
+     * and parent.  aRegion specifies the bounding rectangle of the new
+     * Raster.  When translated into the base Raster's coordinate
+     * system, aRegion must be contained by the base Raster.
+     * (The base Raster is the Raster's ancestor which has no parent.)
+     * sampleModelTranslate specifies the sampleModelTranslateX and
+     * sampleModelTranslateY values of the new Raster.
+     *
+     * Note that this constructor should generally be called by other
+     * constructors or create methods, it should not be used directly.
+     * @param sampleModel     The SampleModel that specifies the layout.
+     * @param dataBuffer      The DataBuffer that contains the image data.
+     * @param aRegion         The Rectangle that specifies the image area.
+     * @param sampleModelTranslate  The Point that specifies the translation
+     *                        from SampleModel to Raster coordinates.
+     * @param parent          The parent (if any) of this raster.
+     * @throws RasterFormatException if <code>aRegion</code> has width
+     *         or height less than or equal to zero, or computing either
+     *         <code>aRegion.x + aRegion.width</code> or
+     *         <code>aRegion.y + aRegion.height</code> results in integer
+     *         overflow
+     */
+    protected WritableRaster(SampleModel sampleModel,
+                             DataBuffer dataBuffer,
+                             Rectangle aRegion,
+                             Point sampleModelTranslate,
+                             WritableRaster parent){
+        super(sampleModel,dataBuffer,aRegion,sampleModelTranslate,parent);
+    }
+
+    /** Returns the parent WritableRaster (if any) of this WritableRaster,
+     *  or else null.
+     *  @return the parent of this <code>WritableRaster</code>, or
+     *          <code>null</code>.
+     */
+    public WritableRaster getWritableParent() {
+        return (WritableRaster)parent;
+    }
+
+    /**
+     * Create a WritableRaster with the same size, SampleModel and DataBuffer
+     * as this one, but with a different location.  The new WritableRaster
+     * will possess a reference to the current WritableRaster, accessible
+     * through its getParent() and getWritableParent() methods.
+     *
+     * @param childMinX X coord of the upper left corner of the new Raster.
+     * @param childMinY Y coord of the upper left corner of the new Raster.
+     * @return a <code>WritableRaster</code> the same as this one except
+     *         for the specified location.
+     * @throws RasterFormatException if  computing either
+     *         <code>childMinX + this.getWidth()</code> or
+     *         <code>childMinY + this.getHeight()</code> results in integer
+     *         overflow
+     */
+    public WritableRaster createWritableTranslatedChild(int childMinX,
+                                                        int childMinY) {
+        return createWritableChild(minX,minY,width,height,
+                                   childMinX,childMinY,null);
+    }
+
+    /**
+     * Returns a new WritableRaster which shares all or part of this
+     * WritableRaster's DataBuffer.  The new WritableRaster will
+     * possess a reference to the current WritableRaster, accessible
+     * through its getParent() and getWritableParent() methods.
+     *
+     * <p> The parentX, parentY, width and height parameters form a
+     * Rectangle in this WritableRaster's coordinate space, indicating
+     * the area of pixels to be shared.  An error will be thrown if
+     * this Rectangle is not contained with the bounds of the current
+     * WritableRaster.
+     *
+     * <p> The new WritableRaster may additionally be translated to a
+     * different coordinate system for the plane than that used by the current
+     * WritableRaster.  The childMinX and childMinY parameters give
+     * the new (x, y) coordinate of the upper-left pixel of the
+     * returned WritableRaster; the coordinate (childMinX, childMinY)
+     * in the new WritableRaster will map to the same pixel as the
+     * coordinate (parentX, parentY) in the current WritableRaster.
+     *
+     * <p> The new WritableRaster may be defined to contain only a
+     * subset of the bands of the current WritableRaster, possibly
+     * reordered, by means of the bandList parameter.  If bandList is
+     * null, it is taken to include all of the bands of the current
+     * WritableRaster in their current order.
+     *
+     * <p> To create a new WritableRaster that contains a subregion of
+     * the current WritableRaster, but shares its coordinate system
+     * and bands, this method should be called with childMinX equal to
+     * parentX, childMinY equal to parentY, and bandList equal to
+     * null.
+     *
+     * @param parentX    X coordinate of the upper left corner in this
+     *                   WritableRaster's coordinates.
+     * @param parentY    Y coordinate of the upper left corner in this
+     *                   WritableRaster's coordinates.
+     * @param w          Width of the region starting at (parentX, parentY).
+     * @param h          Height of the region starting at (parentX, parentY).
+     * @param childMinX  X coordinate of the upper left corner of
+     *                   the returned WritableRaster.
+     * @param childMinY  Y coordinate of the upper left corner of
+     *                   the returned WritableRaster.
+     * @param bandList   Array of band indices, or null to use all bands.
+     * @return a <code>WritableRaster</code> sharing all or part of the
+     *         <code>DataBuffer</code> of this <code>WritableRaster</code>.
+     * @exception RasterFormatException if the subregion is outside of the
+     *                               raster bounds.
+     * @throws RasterFormatException if <code>w</code> or
+     *         <code>h</code>
+     *         is less than or equal to zero, or computing any of
+     *         <code>parentX + w</code>, <code>parentY + h</code>,
+     *         <code>childMinX + w</code>, or
+     *         <code>childMinY + h</code> results in integer
+     *         overflow
+     */
+    public WritableRaster createWritableChild(int parentX, int parentY,
+                                              int w, int h,
+                                              int childMinX, int childMinY,
+                                              int bandList[]) {
+        if (parentX < this.minX) {
+            throw new RasterFormatException("parentX lies outside raster");
+        }
+        if (parentY < this.minY) {
+            throw new RasterFormatException("parentY lies outside raster");
+        }
+        if ((parentX+w < parentX) || (parentX+w > this.width + this.minX)) {
+            throw new RasterFormatException("(parentX + width) is outside raster");
+        }
+        if ((parentY+h < parentY) || (parentY+h > this.height + this.minY)) {
+            throw new RasterFormatException("(parentY + height) is outside raster");
+        }
+
+        SampleModel sm;
+        // Note: the SampleModel for the child Raster should have the same
+        // width and height as that for the parent, since it represents
+        // the physical layout of the pixel data.  The child Raster's width
+        // and height represent a "virtual" view of the pixel data, so
+        // they may be different than those of the SampleModel.
+        if (bandList != null) {
+            sm = sampleModel.createSubsetSampleModel(bandList);
+        }
+        else {
+            sm = sampleModel;
+        }
+
+        int deltaX = childMinX - parentX;
+        int deltaY = childMinY - parentY;
+
+        return new WritableRaster(sm,
+                                  getDataBuffer(),
+                                  new Rectangle(childMinX,childMinY,
+                                                w, h),
+                                  new Point(sampleModelTranslateX+deltaX,
+                                            sampleModelTranslateY+deltaY),
+                                  this);
+    }
+
+    /**
+     * Sets the data for a single pixel from a
+     * primitive array of type TransferType.  For image data supported by
+     * the Java 2D(tm) API, this will be one of DataBuffer.TYPE_BYTE,
+     * DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT,
+     * DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE.  Data in the array
+     * may be in a packed format, thus increasing efficiency for data
+     * transfers.
+     * An ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds, or if inData is not large enough to hold the pixel data.
+     * However, explicit bounds checking is not guaranteed.
+     * A ClassCastException will be thrown if the input object is not null
+     * and references anything other than an array of TransferType.
+     * @see java.awt.image.SampleModel#setDataElements(int, int, Object, DataBuffer)
+     * @param x        The X coordinate of the pixel location.
+     * @param y        The Y coordinate of the pixel location.
+     * @param inData   An object reference to an array of type defined by
+     *                 getTransferType() and length getNumDataElements()
+     *                 containing the pixel data to place at x,y.
+     *
+     * @throws ArrayIndexOutOfBoundsException if the coordinates are not
+     * in bounds, or if inData is too small to hold the input.
+     */
+    public void setDataElements(int x, int y, Object inData) {
+        sampleModel.setDataElements(x-sampleModelTranslateX,
+                                    y-sampleModelTranslateY,
+                                    inData, dataBuffer);
+    }
+
+    /**
+     * Sets the data for a rectangle of pixels from an input Raster.
+     * The input Raster must be compatible with this WritableRaster
+     * in that they must have the same number of bands, corresponding bands
+     * must have the same number of bits per sample, the TransferTypes
+     * and NumDataElements must be the same, and the packing used by
+     * the getDataElements/setDataElements must be identical.
+     * An ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * However, explicit bounds checking is not guaranteed.
+     * @param x        The X coordinate of the pixel location.
+     * @param y        The Y coordinate of the pixel location.
+     * @param inRaster Raster containing data to place at x,y.
+     *
+     * @throws NullPointerException if inRaster is null.
+     * @throws ArrayIndexOutOfBoundsException if the coordinates are not
+     * in bounds.
+     */
+    public void setDataElements(int x, int y, Raster inRaster) {
+        int dstOffX = x+inRaster.getMinX();
+        int dstOffY = y+inRaster.getMinY();
+        int width  = inRaster.getWidth();
+        int height = inRaster.getHeight();
+        if ((dstOffX < this.minX) || (dstOffY < this.minY) ||
+            (dstOffX + width > this.minX + this.width) ||
+            (dstOffY + height > this.minY + this.height)) {
+            throw new ArrayIndexOutOfBoundsException
+                ("Coordinate out of bounds!");
+        }
+
+        int srcOffX = inRaster.getMinX();
+        int srcOffY = inRaster.getMinY();
+        Object tdata = null;
+
+        for (int startY=0; startY < height; startY++) {
+            tdata = inRaster.getDataElements(srcOffX, srcOffY+startY,
+                                             width, 1, tdata);
+            setDataElements(dstOffX, dstOffY+startY,
+                            width, 1, tdata);
+        }
+    }
+
+    /**
+     * Sets the data for a rectangle of pixels from a
+     * primitive array of type TransferType.  For image data supported by
+     * the Java 2D API, this will be one of DataBuffer.TYPE_BYTE,
+     * DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT,
+     * DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE.  Data in the array
+     * may be in a packed format, thus increasing efficiency for data
+     * transfers.
+     * An ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds, or if inData is not large enough to hold the pixel data.
+     * However, explicit bounds checking is not guaranteed.
+     * A ClassCastException will be thrown if the input object is not null
+     * and references anything other than an array of TransferType.
+     * @see java.awt.image.SampleModel#setDataElements(int, int, int, int, Object, DataBuffer)
+     * @param x        The X coordinate of the upper left pixel location.
+     * @param y        The Y coordinate of the upper left pixel location.
+     * @param w        Width of the pixel rectangle.
+     * @param h        Height of the pixel rectangle.
+     * @param inData   An object reference to an array of type defined by
+     *                 getTransferType() and length w*h*getNumDataElements()
+     *                 containing the pixel data to place between x,y and
+     *                 x+w-1, y+h-1.
+     *
+     * @throws NullPointerException if inData is null.
+     * @throws ArrayIndexOutOfBoundsException if the coordinates are not
+     * in bounds, or if inData is too small to hold the input.
+     */
+    public void setDataElements(int x, int y, int w, int h, Object inData) {
+        sampleModel.setDataElements(x-sampleModelTranslateX,
+                                    y-sampleModelTranslateY,
+                                    w,h,inData,dataBuffer);
+    }
+
+    /**
+     * Copies pixels from Raster srcRaster to this WritableRaster.  Each pixel
+     * in srcRaster is copied to the same x,y address in this raster, unless
+     * the address falls outside the bounds of this raster.  srcRaster
+     * must have the same number of bands as this WritableRaster.  The
+     * copy is a simple copy of source samples to the corresponding destination
+     * samples.
+     * <p>
+     * If all samples of both source and destination Rasters are of
+     * integral type and less than or equal to 32 bits in size, then calling
+     * this method is equivalent to executing the following code for all
+     * <code>x,y</code> addresses valid in both Rasters.
+     * <pre>
+     *       Raster srcRaster;
+     *       WritableRaster dstRaster;
+     *       for (int b = 0; b < srcRaster.getNumBands(); b++) {
+     *           dstRaster.setSample(x, y, b, srcRaster.getSample(x, y, b));
+     *       }
+     * </pre>
+     * Thus, when copying an integral type source to an integral type
+     * destination, if the source sample size is greater than the destination
+     * sample size for a particular band, the high order bits of the source
+     * sample are truncated.  If the source sample size is less than the
+     * destination size for a particular band, the high order bits of the
+     * destination are zero-extended or sign-extended depending on whether
+     * srcRaster's SampleModel treats the sample as a signed or unsigned
+     * quantity.
+     * <p>
+     * When copying a float or double source to an integral type destination,
+     * each source sample is cast to the destination type.  When copying an
+     * integral type source to a float or double destination, the source
+     * is first converted to a 32-bit int (if necessary), using the above
+     * rules for integral types, and then the int is cast to float or
+     * double.
+     * <p>
+     * @param srcRaster  The  Raster from which to copy pixels.
+     *
+     * @throws NullPointerException if srcRaster is null.
+     */
+    public void setRect(Raster srcRaster) {
+        setRect(0,0,srcRaster);
+    }
+
+    /**
+     * Copies pixels from Raster srcRaster to this WritableRaster.
+     * For each (x, y) address in srcRaster, the corresponding pixel
+     * is copied to address (x+dx, y+dy) in this WritableRaster,
+     * unless (x+dx, y+dy) falls outside the bounds of this raster.
+     * srcRaster must have the same number of bands as this WritableRaster.
+     * The copy is a simple copy of source samples to the corresponding
+     * destination samples.  For details, see
+     * {@link WritableRaster#setRect(Raster)}.
+     *
+     * @param dx        The X translation factor from src space to dst space
+     *                  of the copy.
+     * @param dy        The Y translation factor from src space to dst space
+     *                  of the copy.
+     * @param srcRaster The Raster from which to copy pixels.
+     *
+     * @throws NullPointerException if srcRaster is null.
+     */
+    public void setRect(int dx, int dy, Raster srcRaster) {
+        int width  = srcRaster.getWidth();
+        int height = srcRaster.getHeight();
+        int srcOffX = srcRaster.getMinX();
+        int srcOffY = srcRaster.getMinY();
+        int dstOffX = dx+srcOffX;
+        int dstOffY = dy+srcOffY;
+
+        // Clip to this raster
+        if (dstOffX < this.minX) {
+            int skipX = this.minX - dstOffX;
+            width -= skipX;
+            srcOffX += skipX;
+            dstOffX = this.minX;
+        }
+        if (dstOffY < this.minY) {
+            int skipY = this.minY - dstOffY;
+            height -= skipY;
+            srcOffY += skipY;
+            dstOffY = this.minY;
+        }
+        if (dstOffX+width > this.minX+this.width) {
+            width = this.minX + this.width - dstOffX;
+        }
+        if (dstOffY+height > this.minY+this.height) {
+            height = this.minY + this.height - dstOffY;
+        }
+
+        if (width <= 0 || height <= 0) {
+            return;
+        }
+
+        switch (srcRaster.getSampleModel().getDataType()) {
+        case DataBuffer.TYPE_BYTE:
+        case DataBuffer.TYPE_SHORT:
+        case DataBuffer.TYPE_USHORT:
+        case DataBuffer.TYPE_INT:
+            int[] iData = null;
+            for (int startY=0; startY < height; startY++) {
+                // Grab one scanline at a time
+                iData =
+                    srcRaster.getPixels(srcOffX, srcOffY+startY, width, 1,
+                                        iData);
+                setPixels(dstOffX, dstOffY+startY, width, 1, iData);
+            }
+            break;
+
+        case DataBuffer.TYPE_FLOAT:
+            float[] fData = null;
+            for (int startY=0; startY < height; startY++) {
+                fData =
+                    srcRaster.getPixels(srcOffX, srcOffY+startY, width, 1,
+                                        fData);
+                setPixels(dstOffX, dstOffY+startY, width, 1, fData);
+            }
+            break;
+
+        case DataBuffer.TYPE_DOUBLE:
+            double[] dData = null;
+            for (int startY=0; startY < height; startY++) {
+                // Grab one scanline at a time
+                dData =
+                    srcRaster.getPixels(srcOffX, srcOffY+startY, width, 1,
+                                        dData);
+                setPixels(dstOffX, dstOffY+startY, width, 1, dData);
+            }
+            break;
+        }
+    }
+
+    /**
+     * Sets a pixel in the DataBuffer using an int array of samples for input.
+     * An ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * However, explicit bounds checking is not guaranteed.
+     * @param x      The X coordinate of the pixel location.
+     * @param y      The Y coordinate of the pixel location.
+     * @param iArray The input samples in a int array.
+     *
+     * @throws NullPointerException if iArray is null.
+     * @throws ArrayIndexOutOfBoundsException if the coordinates are not
+     * in bounds, or if iArray is too small to hold the input.
+     */
+    public void setPixel(int x, int y, int iArray[]) {
+        sampleModel.setPixel(x-sampleModelTranslateX,y-sampleModelTranslateY,
+                             iArray,dataBuffer);
+    }
+
+    /**
+     * Sets a pixel in the DataBuffer using a float array of samples for input.
+     * An ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * However, explicit bounds checking is not guaranteed.
+     * @param x      The X coordinate of the pixel location.
+     * @param y      The Y coordinate of the pixel location.
+     * @param fArray The input samples in a float array.
+     *
+     * @throws NullPointerException if fArray is null.
+     * @throws ArrayIndexOutOfBoundsException if the coordinates are not
+     * in bounds, or if fArray is too small to hold the input.
+     */
+    public void setPixel(int x, int y, float fArray[]) {
+        sampleModel.setPixel(x-sampleModelTranslateX,y-sampleModelTranslateY,
+                             fArray,dataBuffer);
+    }
+
+    /**
+     * Sets a pixel in the DataBuffer using a double array of samples for input.
+     * An ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * However, explicit bounds checking is not guaranteed.
+     * @param x      The X coordinate of the pixel location.
+     * @param y      The Y coordinate of the pixel location.
+     * @param dArray The input samples in a double array.
+     *
+     * @throws NullPointerException if dArray is null.
+     * @throws ArrayIndexOutOfBoundsException if the coordinates are not
+     * in bounds, or if dArray is too small to hold the input.
+     */
+    public void setPixel(int x, int y, double dArray[]) {
+        sampleModel.setPixel(x-sampleModelTranslateX,y-sampleModelTranslateY,
+                             dArray,dataBuffer);
+    }
+
+    /**
+     * Sets all samples for a rectangle of pixels from an int array containing
+     * one sample per array element.
+     * An ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * However, explicit bounds checking is not guaranteed.
+     * @param x        The X coordinate of the upper left pixel location.
+     * @param y        The Y coordinate of the upper left pixel location.
+     * @param w        Width of the pixel rectangle.
+     * @param h        Height of the pixel rectangle.
+     * @param iArray   The input int pixel array.
+     *
+     * @throws NullPointerException if iArray is null.
+     * @throws ArrayIndexOutOfBoundsException if the coordinates are not
+     * in bounds, or if iArray is too small to hold the input.
+     */
+    public void setPixels(int x, int y, int w, int h, int iArray[]) {
+        sampleModel.setPixels(x-sampleModelTranslateX,y-sampleModelTranslateY,
+                              w,h,iArray,dataBuffer);
+    }
+
+    /**
+     * Sets all samples for a rectangle of pixels from a float array containing
+     * one sample per array element.
+     * An ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * However, explicit bounds checking is not guaranteed.
+     * @param x        The X coordinate of the upper left pixel location.
+     * @param y        The Y coordinate of the upper left pixel location.
+     * @param w        Width of the pixel rectangle.
+     * @param h        Height of the pixel rectangle.
+     * @param fArray   The input float pixel array.
+     *
+     * @throws NullPointerException if fArray is null.
+     * @throws ArrayIndexOutOfBoundsException if the coordinates are not
+     * in bounds, or if fArray is too small to hold the input.
+     */
+    public void setPixels(int x, int y, int w, int h, float fArray[]) {
+        sampleModel.setPixels(x-sampleModelTranslateX,y-sampleModelTranslateY,
+                              w,h,fArray,dataBuffer);
+    }
+
+    /**
+     * Sets all samples for a rectangle of pixels from a double array containing
+     * one sample per array element.
+     * An ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * However, explicit bounds checking is not guaranteed.
+     * @param x        The X coordinate of the upper left pixel location.
+     * @param y        The Y coordinate of the upper left pixel location.
+     * @param w        Width of the pixel rectangle.
+     * @param h        Height of the pixel rectangle.
+     * @param dArray   The input double pixel array.
+     *
+     * @throws NullPointerException if dArray is null.
+     * @throws ArrayIndexOutOfBoundsException if the coordinates are not
+     * in bounds, or if dArray is too small to hold the input.
+     */
+    public void setPixels(int x, int y, int w, int h, double dArray[]) {
+        sampleModel.setPixels(x-sampleModelTranslateX,y-sampleModelTranslateY,
+                              w,h,dArray,dataBuffer);
+    }
+
+    /**
+     * Sets a sample in the specified band for the pixel located at (x,y)
+     * in the DataBuffer using an int for input.
+     * An ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * However, explicit bounds checking is not guaranteed.
+     * @param x        The X coordinate of the pixel location.
+     * @param y        The Y coordinate of the pixel location.
+     * @param b        The band to set.
+     * @param s        The input sample.
+     *
+     * @throws ArrayIndexOutOfBoundsException if the coordinates or
+     * the band index are not in bounds.
+     */
+    public void setSample(int x, int y, int b, int s) {
+        sampleModel.setSample(x-sampleModelTranslateX,
+                              y-sampleModelTranslateY, b, s,
+                              dataBuffer);
+    }
+
+    /**
+     * Sets a sample in the specified band for the pixel located at (x,y)
+     * in the DataBuffer using a float for input.
+     * An ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * However, explicit bounds checking is not guaranteed.
+     * @param x        The X coordinate of the pixel location.
+     * @param y        The Y coordinate of the pixel location.
+     * @param b        The band to set.
+     * @param s        The input sample as a float.
+     *
+     * @throws ArrayIndexOutOfBoundsException if the coordinates or
+     * the band index are not in bounds.
+     */
+    public void setSample(int x, int y, int b, float s){
+        sampleModel.setSample(x-sampleModelTranslateX,y-sampleModelTranslateY,
+                              b,s,dataBuffer);
+    }
+
+    /**
+     * Sets a sample in the specified band for the pixel located at (x,y)
+     * in the DataBuffer using a double for input.
+     * An ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * However, explicit bounds checking is not guaranteed.
+     * @param x        The X coordinate of the pixel location.
+     * @param y        The Y coordinate of the pixel location.
+     * @param b        The band to set.
+     * @param s        The input sample as a double.
+     *
+     * @throws ArrayIndexOutOfBoundsException if the coordinates or
+     * the band index are not in bounds.
+     */
+    public void setSample(int x, int y, int b, double s){
+        sampleModel.setSample(x-sampleModelTranslateX,y-sampleModelTranslateY,
+                                    b,s,dataBuffer);
+    }
+
+    /**
+     * Sets the samples in the specified band for the specified rectangle
+     * of pixels from an int array containing one sample per array element.
+     * An ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * However, explicit bounds checking is not guaranteed.
+     * @param x        The X coordinate of the upper left pixel location.
+     * @param y        The Y coordinate of the upper left pixel location.
+     * @param w        Width of the pixel rectangle.
+     * @param h        Height of the pixel rectangle.
+     * @param b        The band to set.
+     * @param iArray   The input int sample array.
+     *
+     * @throws NullPointerException if iArray is null.
+     * @throws ArrayIndexOutOfBoundsException if the coordinates or
+     * the band index are not in bounds, or if iArray is too small to
+     * hold the input.
+     */
+    public void setSamples(int x, int y, int w, int h, int b,
+                           int iArray[]) {
+        sampleModel.setSamples(x-sampleModelTranslateX,y-sampleModelTranslateY,
+                               w,h,b,iArray,dataBuffer);
+    }
+
+    /**
+     * Sets the samples in the specified band for the specified rectangle
+     * of pixels from a float array containing one sample per array element.
+     * An ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * However, explicit bounds checking is not guaranteed.
+     * @param x        The X coordinate of the upper left pixel location.
+     * @param y        The Y coordinate of the upper left pixel location.
+     * @param w        Width of the pixel rectangle.
+     * @param h        Height of the pixel rectangle.
+     * @param b        The band to set.
+     * @param fArray   The input float sample array.
+     *
+     * @throws NullPointerException if fArray is null.
+     * @throws ArrayIndexOutOfBoundsException if the coordinates or
+     * the band index are not in bounds, or if fArray is too small to
+     * hold the input.
+     */
+    public void setSamples(int x, int y, int w, int h, int b,
+                           float fArray[]) {
+        sampleModel.setSamples(x-sampleModelTranslateX,y-sampleModelTranslateY,
+                               w,h,b,fArray,dataBuffer);
+    }
+
+    /**
+     * Sets the samples in the specified band for the specified rectangle
+     * of pixels from a double array containing one sample per array element.
+     * An ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+     * not in bounds.
+     * However, explicit bounds checking is not guaranteed.
+     * @param x        The X coordinate of the upper left pixel location.
+     * @param y        The Y coordinate of the upper left pixel location.
+     * @param w        Width of the pixel rectangle.
+     * @param h        Height of the pixel rectangle.
+     * @param b        The band to set.
+     * @param dArray   The input double sample array.
+     *
+     * @throws NullPointerException if dArray is null.
+     * @throws ArrayIndexOutOfBoundsException if the coordinates or
+     * the band index are not in bounds, or if dArray is too small to
+     * hold the input.
+     */
+    public void setSamples(int x, int y, int w, int h, int b,
+                           double dArray[]) {
+        sampleModel.setSamples(x-sampleModelTranslateX,y-sampleModelTranslateY,
+                              w,h,b,dArray,dataBuffer);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/awt/image/WritableRenderedImage.java	Thu Apr 10 16:28:45 2008 -0700
@@ -0,0 +1,151 @@
+/*
+ * Portions Copyright 1997-2000 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* ****************************************************************
+ ******************************************************************
+ ******************************************************************
+ *** COPYRIGHT (c) Eastman Kodak Company, 1997
+ *** As  an unpublished  work pursuant to Title 17 of the United
+ *** States Code.  All rights reserved.
+ ******************************************************************
+ ******************************************************************
+ ******************************************************************/
+
+package java.awt.image;
+import java.awt.Point;
+
+/**
+ * WriteableRenderedImage is a common interface for objects which
+ * contain or can produce image data in the form of Rasters and
+ * which can be modified and/or written over.  The image
+ * data may be stored/produced as a single tile or a regular array
+ * of tiles.
+ * <p>
+ * WritableRenderedImage provides notification to other interested
+ * objects when a tile is checked out for writing (via the
+ * getWritableTile method) and when the last writer of a particular
+ * tile relinquishes its access (via a call to releaseWritableTile).
+ * Additionally, it allows any caller to determine whether any tiles
+ * are currently checked out (via hasTileWriters), and to obtain a
+ * list of such tiles (via getWritableTileIndices, in the form of a Vector
+ * of Point objects).
+ * <p>
+ * Objects wishing to be notified of changes in tile writability must
+ * implement the TileObserver interface, and are added by a
+ * call to addTileObserver.  Multiple calls to
+ * addTileObserver for the same object will result in multiple
+ * notifications.  An existing observer may reduce its notifications
+ * by calling removeTileObserver; if the observer had no
+ * notifications the operation is a no-op.
+ * <p>
+ * It is necessary for a WritableRenderedImage to ensure that
+ * notifications occur only when the first writer acquires a tile and
+ * the last writer releases it.
+ *
+ */
+
+public interface WritableRenderedImage extends RenderedImage
+{
+
+  /**
+   * Adds an observer.  If the observer is already present,
+   * it will receive multiple notifications.
+   * @param to the specified <code>TileObserver</code>
+   */
+  public void addTileObserver(TileObserver to);
+
+  /**
+   * Removes an observer.  If the observer was not registered,
+   * nothing happens.  If the observer was registered for multiple
+   * notifications, it will now be registered for one fewer.
+   * @param to the specified <code>TileObserver</code>
+   */
+  public void removeTileObserver(TileObserver to);
+
+  /**
+   * Checks out a tile for writing.
+   *
+   * The WritableRenderedImage is responsible for notifying all
+   * of its TileObservers when a tile goes from having
+   * no writers to having one writer.
+   *
+   * @param tileX the X index of the tile.
+   * @param tileY the Y index of the tile.
+   * @return a writable tile.
+   */
+  public WritableRaster getWritableTile(int tileX, int tileY);
+
+  /**
+   * Relinquishes the right to write to a tile.  If the caller
+   * continues to write to the tile, the results are undefined.
+   * Calls to this method should only appear in matching pairs
+   * with calls to getWritableTile; any other use will lead
+   * to undefined results.
+   *
+   * The WritableRenderedImage is responsible for notifying all of
+   * its TileObservers when a tile goes from having one writer
+   * to having no writers.
+   *
+   * @param tileX the X index of the tile.
+   * @param tileY the Y index of the tile.
+   */
+  public void releaseWritableTile(int tileX, int tileY);
+
+  /**
+   * Returns whether a tile is currently checked out for writing.
+   *
+   * @param tileX the X index of the tile.
+   * @param tileY the Y index of the tile.
+   * @return <code>true</code> if specified tile is checked out
+   *         for writing; <code>false</code> otherwise.
+   */
+  public boolean isTileWritable(int tileX, int tileY);
+
+  /**
+   * Returns an array of Point objects indicating which tiles
+   * are checked out for writing.  Returns null if none are
+   * checked out.
+   * @return an array containing the locations of tiles that are
+   *         checked out for writing.
+   */
+  public Point[] getWritableTileIndices();
+
+  /**
+   * Returns whether any tile is checked out for writing.
+   * Semantically equivalent to (getWritableTileIndices() != null).
+   * @return <code>true</code> if any tiles are checked out for
+   *         writing; <code>false</code> otherwise.
+   */
+  public boolean hasTileWriters();
+
+  /**
+   * Sets a rect of the image to the contents of the Raster r, which is
+   * assumed to be in the same coordinate space as the WritableRenderedImage.
+   * The operation is clipped to the bounds of the WritableRenderedImage.
+   * @param r the specified <code>Raster</code>
+   */
+  public void setData(Raster r);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/awt/image/renderable/ContextualRenderedImageFactory.java	Thu Apr 10 16:28:45 2008 -0700
@@ -0,0 +1,143 @@
+/*
+ * Portions Copyright 1998-2000 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* ********************************************************************
+ **********************************************************************
+ **********************************************************************
+ *** COPYRIGHT (c) Eastman Kodak Company, 1997                      ***
+ *** As  an unpublished  work pursuant to Title 17 of the United    ***
+ *** States Code.  All rights reserved.                             ***
+ **********************************************************************
+ **********************************************************************
+ **********************************************************************/
+
+package java.awt.image.renderable;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.RenderedImage;
+
+/**
+ * ContextualRenderedImageFactory provides an interface for the
+ * functionality that may differ between instances of
+ * RenderableImageOp.  Thus different operations on RenderableImages
+ * may be performed by a single class such as RenderedImageOp through
+ * the use of multiple instances of ContextualRenderedImageFactory.
+ * The name ContextualRenderedImageFactory is commonly shortened to
+ * "CRIF."
+ *
+ * <p> All operations that are to be used in a rendering-independent
+ * chain must implement ContextualRenderedImageFactory.
+ *
+ * <p> Classes that implement this interface must provide a
+ * constructor with no arguments.
+ */
+public interface ContextualRenderedImageFactory extends RenderedImageFactory {
+
+    /**
+     * Maps the operation's output RenderContext into a RenderContext
+     * for each of the operation's sources.  This is useful for
+     * operations that can be expressed in whole or in part simply as
+     * alterations in the RenderContext, such as an affine mapping, or
+     * operations that wish to obtain lower quality renderings of
+     * their sources in order to save processing effort or
+     * transmission bandwith.  Some operations, such as blur, can also
+     * use this mechanism to avoid obtaining sources of higher quality
+     * than necessary.
+     *
+     * @param i the index of the source image.
+     * @param renderContext the RenderContext being applied to the operation.
+     * @param paramBlock a ParameterBlock containing the operation's
+     *        sources and parameters.
+     * @param image the RenderableImage being rendered.
+     * @return a <code>RenderContext</code> for
+     *         the source at the specified index of the parameters
+     *         Vector contained in the specified ParameterBlock.
+     */
+    RenderContext mapRenderContext(int i,
+                                   RenderContext renderContext,
+                                   ParameterBlock paramBlock,
+                                   RenderableImage image);
+
+    /**
+     * Creates a rendering, given a RenderContext and a ParameterBlock
+     * containing the operation's sources and parameters.  The output
+     * is a RenderedImage that takes the RenderContext into account to
+     * determine its dimensions and placement on the image plane.
+     * This method houses the "intelligence" that allows a
+     * rendering-independent operation to adapt to a specific
+     * RenderContext.
+     *
+     * @param renderContext The RenderContext specifying the rendering
+     * @param paramBlock a ParameterBlock containing the operation's
+     *        sources and parameters
+     * @return a <code>RenderedImage</code> from the sources and parameters
+     *         in the specified ParameterBlock and according to the
+     *         rendering instructions in the specified RenderContext.
+     */
+    RenderedImage create(RenderContext renderContext,
+                         ParameterBlock paramBlock);
+
+    /**
+     * Returns the bounding box for the output of the operation,
+     * performed on a given set of sources, in rendering-independent
+     * space.  The bounds are returned as a Rectangle2D, that is, an
+     * axis-aligned rectangle with floating-point corner coordinates.
+     *
+     * @param paramBlock a ParameterBlock containing the operation's
+     *        sources and parameters.
+     * @return a Rectangle2D specifying the rendering-independent
+     *         bounding box of the output.
+     */
+    Rectangle2D getBounds2D(ParameterBlock paramBlock);
+
+    /**
+     * Gets the appropriate instance of the property specified by the name
+     * parameter.  This method must determine which instance of a property to
+     * return when there are multiple sources that each specify the property.
+     *
+     * @param paramBlock a ParameterBlock containing the operation's
+     *        sources and parameters.
+     * @param name a String naming the desired property.
+     * @return an object reference to the value of the property requested.
+     */
+    Object getProperty(ParameterBlock paramBlock, String name);
+
+    /**
+     * Returns a list of names recognized by getProperty.
+     * @return the list of property names.
+     */
+    String[] getPropertyNames();
+
+    /**
+     * Returns true if successive renderings (that is, calls to
+     * create(RenderContext, ParameterBlock)) with the same arguments
+     * may produce different results.  This method may be used to
+     * determine whether an existing rendering may be cached and
+     * reused.  It is always safe to return true.
+     * @return <code>true</code> if successive renderings with the
+     *         same arguments might produce different results;
+     *         <code>false</code> otherwise.
+     */
+    boolean isDynamic();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/awt/image/renderable/RenderContext.java	Thu Apr 10 16:28:45 2008 -0700
@@ -0,0 +1,272 @@
+/*
+ * Portions Copyright 1998-2000 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* ********************************************************************
+ **********************************************************************
+ **********************************************************************
+ *** COPYRIGHT (c) Eastman Kodak Company, 1997                      ***
+ *** As  an unpublished  work pursuant to Title 17 of the United    ***
+ *** States Code.  All rights reserved.                             ***
+ **********************************************************************
+ **********************************************************************
+ **********************************************************************/
+
+package java.awt.image.renderable;
+import java.util.*;
+import java.awt.geom.*;
+import java.awt.*;
+import java.awt.image.*;
+
+/**
+ * A RenderContext encapsulates the information needed to produce a
+ * specific rendering from a RenderableImage.  It contains the area to
+ * be rendered specified in rendering-independent terms, the
+ * resolution at which the rendering is to be performed, and hints
+ * used to control the rendering process.
+ *
+ * <p> Users create RenderContexts and pass them to the
+ * RenderableImage via the createRendering method.  Most of the methods of
+ * RenderContexts are not meant to be used directly by applications,
+ * but by the RenderableImage and operator classes to which it is
+ * passed.
+ *
+ * <p> The AffineTransform parameter passed into and out of this class
+ * are cloned.  The RenderingHints and Shape parameters are not
+ * necessarily cloneable and are therefore only reference copied.
+ * Altering RenderingHints or Shape instances that are in use by
+ * instances of RenderContext may have undesired side effects.
+ */
+public class RenderContext implements Cloneable {
+
+    /** Table of hints. May be null. */
+    RenderingHints hints;
+
+    /** Transform to convert user coordinates to device coordinates.  */
+    AffineTransform usr2dev;
+
+    /** The area of interest.  May be null. */
+    Shape aoi;
+
+    // Various constructors that allow different levels of
+    // specificity. If the Shape is missing the whole renderable area
+    // is assumed. If hints is missing no hints are assumed.
+
+    /**
+     * Constructs a RenderContext with a given transform.
+     * The area of interest is supplied as a Shape,
+     * and the rendering hints are supplied as a RenderingHints object.
+     *
+     * @param usr2dev an AffineTransform.
+     * @param aoi a Shape representing the area of interest.
+     * @param hints a RenderingHints object containing rendering hints.
+     */
+    public RenderContext(AffineTransform usr2dev,
+                         Shape aoi,
+                         RenderingHints hints) {
+        this.hints = hints;
+        this.aoi = aoi;
+        this.usr2dev = (AffineTransform)usr2dev.clone();
+    }
+
+    /**
+     * Constructs a RenderContext with a given transform.
+     * The area of interest is taken to be the entire renderable area.
+     * No rendering hints are used.
+     *
+     * @param usr2dev an AffineTransform.
+     */
+    public RenderContext(AffineTransform usr2dev) {
+        this(usr2dev, null, null);
+    }
+
+    /**
+     * Constructs a RenderContext with a given transform and rendering hints.
+     * The area of interest is taken to be the entire renderable area.
+     *
+     * @param usr2dev an AffineTransform.
+     * @param hints a RenderingHints object containing rendering hints.
+     */
+    public RenderContext(AffineTransform usr2dev, RenderingHints hints) {
+        this(usr2dev, null, hints);
+    }
+
+    /**
+     * Constructs a RenderContext with a given transform and area of interest.
+     * The area of interest is supplied as a Shape.
+     * No rendering hints are used.
+     *
+     * @param usr2dev an AffineTransform.
+     * @param aoi a Shape representing the area of interest.
+     */
+    public RenderContext(AffineTransform usr2dev, Shape aoi) {
+        this(usr2dev, aoi, null);
+    }
+
+    /**
+     * Gets the rendering hints of this <code>RenderContext</code>.
+     * @return a <code>RenderingHints</code> object that represents
+     * the rendering hints of this <code>RenderContext</code>.
+     * @see #setRenderingHints(RenderingHints)
+     */
+    public RenderingHints getRenderingHints() {
+        return hints;
+    }
+
+    /**
+     * Sets the rendering hints of this <code>RenderContext</code>.
+     * @param hints a <code>RenderingHints</code> object that represents
+     * the rendering hints to assign to this <code>RenderContext</code>.
+     * @see #getRenderingHints
+     */
+    public void setRenderingHints(RenderingHints hints) {
+        this.hints = hints;
+    }
+
+    /**
+     * Sets the current user-to-device AffineTransform contained
+     * in the RenderContext to a given transform.
+     *
+     * @param newTransform the new AffineTransform.
+     * @see #getTransform
+     */
+    public void setTransform(AffineTransform newTransform) {
+        usr2dev = (AffineTransform)newTransform.clone();
+    }
+
+    /**
+     * Modifies the current user-to-device transform by prepending another
+     * transform.  In matrix notation the operation is:
+     * <pre>
+     * [this] = [modTransform] x [this]
+     * </pre>
+     *
+     * @param modTransform the AffineTransform to prepend to the
+     *        current usr2dev transform.
+     * @since 1.3
+     */
+    public void preConcatenateTransform(AffineTransform modTransform) {
+        this.preConcetenateTransform(modTransform);
+    }
+
+    /**
+     * Modifies the current user-to-device transform by prepending another
+     * transform.  In matrix notation the operation is:
+     * <pre>
+     * [this] = [modTransform] x [this]
+     * </pre>
+     * This method does the same thing as the preConcatenateTransform
+     * method.  It is here for backward compatibility with previous releases
+     * which misspelled the method name.
+     *
+     * @param modTransform the AffineTransform to prepend to the
+     *        current usr2dev transform.
+     * @deprecated     replaced by
+     *                 <code>preConcatenateTransform(AffineTransform)</code>.
+     */
+    @Deprecated
+    public void preConcetenateTransform(AffineTransform modTransform) {
+        usr2dev.preConcatenate(modTransform);
+    }
+
+    /**
+     * Modifies the current user-to-device transform by appending another
+     * transform.  In matrix notation the operation is:
+     * <pre>
+     * [this] = [this] x [modTransform]
+     * </pre>
+     *
+     * @param modTransform the AffineTransform to append to the
+     *        current usr2dev transform.
+     * @since 1.3
+     */
+    public void concatenateTransform(AffineTransform modTransform) {
+        this.concetenateTransform(modTransform);
+    }
+
+    /**
+     * Modifies the current user-to-device transform by appending another
+     * transform.  In matrix notation the operation is:
+     * <pre>
+     * [this] = [this] x [modTransform]
+     * </pre>
+     * This method does the same thing as the concatenateTransform
+     * method.  It is here for backward compatibility with previous releases
+     * which misspelled the method name.
+     *
+     * @param modTransform the AffineTransform to append to the
+     *        current usr2dev transform.
+     * @deprecated     replaced by
+     *                 <code>concatenateTransform(AffineTransform)</code>.
+     */
+    @Deprecated
+    public void concetenateTransform(AffineTransform modTransform) {
+        usr2dev.concatenate(modTransform);
+    }
+
+    /**
+     * Gets the current user-to-device AffineTransform.
+     *
+     * @return a reference to the current AffineTransform.
+     * @see #setTransform(AffineTransform)
+     */
+    public AffineTransform getTransform() {
+        return (AffineTransform)usr2dev.clone();
+    }
+
+    /**
+     * Sets the current area of interest.  The old area is discarded.
+     *
+     * @param newAoi The new area of interest.
+     * @see #getAreaOfInterest
+     */
+    public void setAreaOfInterest(Shape newAoi) {
+        aoi = newAoi;
+    }
+
+    /**
+     * Gets the ares of interest currently contained in the
+     * RenderContext.
+     *
+     * @return a reference to the area of interest of the RenderContext,
+     *         or null if none is specified.
+     * @see #setAreaOfInterest(Shape)
+     */
+    public Shape getAreaOfInterest() {
+        return aoi;
+    }
+
+    /**
+     * Makes a copy of a RenderContext. The area of interest is copied
+     * by reference.  The usr2dev AffineTransform and hints are cloned,
+     * while the area of interest is copied by reference.
+     *
+     * @return the new cloned RenderContext.
+     */
+    public Object clone() {
+        RenderContext newRenderContext = new RenderContext(usr2dev,
+                                                           aoi, hints);
+        return newRenderContext;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/awt/image/renderable/RenderableImage.java	Thu Apr 10 16:28:45 2008 -0700
@@ -0,0 +1,198 @@
+/*
+ * Portions Copyright 1998-2000 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* ********************************************************************
+ **********************************************************************
+ **********************************************************************
+ *** COPYRIGHT (c) Eastman Kodak Company, 1997                      ***
+ *** As  an unpublished  work pursuant to Title 17 of the United    ***
+ *** States Code.  All rights reserved.                             ***
+ **********************************************************************
+ **********************************************************************
+ **********************************************************************/
+
+package java.awt.image.renderable;
+import java.util.Vector;
+import java.awt.RenderingHints;
+import java.awt.image.*;
+
+/**
+ * A RenderableImage is a common interface for rendering-independent
+ * images (a notion which subsumes resolution independence).  That is,
+ * images which are described and have operations applied to them
+ * independent of any specific rendering of the image.  For example, a
+ * RenderableImage can be rotated and cropped in
+ * resolution-independent terms.  Then, it can be rendered for various
+ * specific contexts, such as a draft preview, a high-quality screen
+ * display, or a printer, each in an optimal fashion.
+ *
+ * <p> A RenderedImage is returned from a RenderableImage via the
+ * createRendering() method, which takes a RenderContext.  The
+ * RenderContext specifies how the RenderedImage should be
+ * constructed.  Note that it is not possible to extract pixels
+ * directly from a RenderableImage.
+ *
+ * <p> The createDefaultRendering() and createScaledRendering() methods are
+ * convenience methods that construct an appropriate RenderContext
+ * internally.  All of the rendering methods may return a reference to a
+ * previously produced rendering.
+ */
+public interface RenderableImage {
+
+    /**
+     * String constant that can be used to identify a property on
+     * a RenderedImage obtained via the createRendering or
+     * createScaledRendering methods.  If such a property exists,
+     * the value of the propoery will be a RenderingHints object
+     * specifying which hints were observed in creating the rendering.
+     */
+     static final String HINTS_OBSERVED = "HINTS_OBSERVED";
+
+    /**
+     * Returns a vector of RenderableImages that are the sources of
+     * image data for this RenderableImage. Note that this method may
+     * return an empty vector, to indicate that the image has no sources,
+     * or null, to indicate that no information is available.
+     *
+     * @return a (possibly empty) Vector of RenderableImages, or null.
+     */
+    Vector<RenderableImage> getSources();
+
+    /**
+     * Gets a property from the property set of this image.
+     * If the property name is not recognized, java.awt.Image.UndefinedProperty
+     * will be returned.
+     *
+     * @param name the name of the property to get, as a String.
+     * @return a reference to the property Object, or the value
+     *         java.awt.Image.UndefinedProperty.
+     */
+    Object getProperty(String name);
+
+    /**
+     * Returns a list of names recognized by getProperty.
+     * @return a list of property names.
+     */
+    String[] getPropertyNames();
+
+    /**
+     * Returns true if successive renderings (that is, calls to
+     * createRendering() or createScaledRendering()) with the same arguments
+     * may produce different results.  This method may be used to
+     * determine whether an existing rendering may be cached and
+     * reused.  It is always safe to return true.
+     * @return <code>true</code> if successive renderings with the
+     *         same arguments might produce different results;
+     *         <code>false</code> otherwise.
+     */
+    boolean isDynamic();
+
+    /**
+     * Gets the width in user coordinate space.  By convention, the
+     * usual width of a RenderableImage is equal to the image's aspect
+     * ratio (width divided by height).
+     *
+     * @return the width of the image in user coordinates.
+     */
+    float getWidth();
+
+    /**
+     * Gets the height in user coordinate space.  By convention, the
+     * usual height of a RenderedImage is equal to 1.0F.
+     *
+     * @return the height of the image in user coordinates.
+     */
+    float getHeight();
+
+    /**
+     * Gets the minimum X coordinate of the rendering-independent image data.
+     * @return the minimum X coordinate of the rendering-independent image
+     * data.
+     */
+    float getMinX();
+
+    /**
+     * Gets the minimum Y coordinate of the rendering-independent image data.
+     * @return the minimum Y coordinate of the rendering-independent image
+     * data.
+     */
+    float getMinY();
+
+    /**
+     * Creates a RenderedImage instance of this image with width w, and
+     * height h in pixels.  The RenderContext is built automatically
+     * with an appropriate usr2dev transform and an area of interest
+     * of the full image.  All the rendering hints come from hints
+     * passed in.
+     *
+     * <p> If w == 0, it will be taken to equal
+     * Math.round(h*(getWidth()/getHeight())).
+     * Similarly, if h == 0, it will be taken to equal
+     * Math.round(w*(getHeight()/getWidth())).  One of
+     * w or h must be non-zero or else an IllegalArgumentException
+     * will be thrown.
+     *
+     * <p> The created RenderedImage may have a property identified
+     * by the String HINTS_OBSERVED to indicate which RenderingHints
+     * were used to create the image.  In addition any RenderedImages
+     * that are obtained via the getSources() method on the created
+     * RenderedImage may have such a property.
+     *
+     * @param w the width of rendered image in pixels, or 0.
+     * @param h the height of rendered image in pixels, or 0.
+     * @param hints a RenderingHints object containg hints.
+     * @return a RenderedImage containing the rendered data.
+     */
+    RenderedImage createScaledRendering(int w, int h, RenderingHints hints);
+
+    /**
+     * Returnd a RenderedImage instance of this image with a default
+     * width and height in pixels.  The RenderContext is built
+     * automatically with an appropriate usr2dev transform and an area
+     * of interest of the full image.  The rendering hints are
+     * empty.  createDefaultRendering may make use of a stored
+     * rendering for speed.
+     *
+     * @return a RenderedImage containing the rendered data.
+     */
+    RenderedImage createDefaultRendering();
+
+    /**
+     * Creates a RenderedImage that represented a rendering of this image
+     * using a given RenderContext.  This is the most general way to obtain a
+     * rendering of a RenderableImage.
+     *
+     * <p> The created RenderedImage may have a property identified
+     * by the String HINTS_OBSERVED to indicate which RenderingHints
+     * (from the RenderContext) were used to create the image.
+     * In addition any RenderedImages
+     * that are obtained via the getSources() method on the created
+     * RenderedImage may have such a property.
+     *
+     * @param renderContext the RenderContext to use to produce the rendering.
+     * @return a RenderedImage containing the rendered data.
+     */
+    RenderedImage createRendering(RenderContext renderContext);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/awt/image/renderable/RenderableImageOp.java	Thu Apr 10 16:28:45 2008 -0700
@@ -0,0 +1,350 @@
+/*
+ * Portions Copyright 1998-2000 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* ********************************************************************
+ **********************************************************************
+ **********************************************************************
+ *** COPYRIGHT (c) Eastman Kodak Company, 1997                      ***
+ *** As  an unpublished  work pursuant to Title 17 of the United    ***
+ *** States Code.  All rights reserved.                             ***
+ **********************************************************************
+ **********************************************************************
+ **********************************************************************/
+
+package java.awt.image.renderable;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.RenderedImage;
+import java.awt.RenderingHints;
+import java.util.Hashtable;
+import java.util.Vector;
+
+/**
+ * This class handles the renderable aspects of an operation with help
+ * from its associated instance of a ContextualRenderedImageFactory.
+ */
+public class RenderableImageOp implements RenderableImage {
+
+    /** A ParameterBlock containing source and parameters. */
+    ParameterBlock paramBlock;
+
+    /** The associated ContextualRenderedImageFactory. */
+    ContextualRenderedImageFactory myCRIF;
+
+    /** The bounding box of the results of this RenderableImageOp. */
+    Rectangle2D boundingBox;
+
+
+    /**
+     * Constructs a RenderedImageOp given a
+     * ContextualRenderedImageFactory object, and
+     * a ParameterBlock containing RenderableImage sources and other
+     * parameters.  Any RenderedImage sources referenced by the
+     * ParameterBlock will be ignored.
+     *
+     * @param CRIF a ContextualRenderedImageFactory object
+     * @param paramBlock a ParameterBlock containing this operation's source
+     *        images and other parameters necessary for the operation
+     *        to run.
+     */
+    public RenderableImageOp(ContextualRenderedImageFactory CRIF,
+                             ParameterBlock paramBlock) {
+        this.myCRIF = CRIF;
+        this.paramBlock = (ParameterBlock) paramBlock.clone();
+    }
+
+    /**
+     * Returns a vector of RenderableImages that are the sources of
+     * image data for this RenderableImage. Note that this method may
+     * return an empty vector, to indicate that the image has no sources,
+     * or null, to indicate that no information is available.
+     *
+     * @return a (possibly empty) Vector of RenderableImages, or null.
+     */
+    public Vector<RenderableImage> getSources() {
+        return getRenderableSources();
+    }
+
+    private Vector getRenderableSources() {
+        Vector sources = null;
+
+        if (paramBlock.getNumSources() > 0) {
+            sources = new Vector();
+            int i = 0;
+            while (i < paramBlock.getNumSources()) {
+                Object o = paramBlock.getSource(i);
+                if (o instanceof RenderableImage) {
+                    sources.add((RenderableImage)o);
+                    i++;
+                } else {
+                    break;
+                }
+            }
+        }
+        return sources;
+    }
+
+    /**
+     * Gets a property from the property set of this image.
+     * If the property name is not recognized, java.awt.Image.UndefinedProperty
+     * will be returned.
+     *
+     * @param name the name of the property to get, as a String.
+     * @return a reference to the property Object, or the value
+     *         java.awt.Image.UndefinedProperty.
+     */
+    public Object getProperty(String name) {
+        return myCRIF.getProperty(paramBlock, name);
+    }
+
+    /**
+     * Return a list of names recognized by getProperty.
+     * @return a list of property names.
+     */
+    public String[] getPropertyNames() {
+        return myCRIF.getPropertyNames();
+    }
+
+    /**
+     * Returns true if successive renderings (that is, calls to
+     * createRendering() or createScaledRendering()) with the same arguments
+     * may produce different results.  This method may be used to
+     * determine whether an existing rendering may be cached and
+     * reused.  The CRIF's isDynamic method will be called.
+     * @return <code>true</code> if successive renderings with the
+     *         same arguments might produce different results;
+     *         <code>false</code> otherwise.
+     */
+    public boolean isDynamic() {
+        return myCRIF.isDynamic();
+    }
+
+    /**
+     * Gets the width in user coordinate space.  By convention, the
+     * usual width of a RenderableImage is equal to the image's aspect
+     * ratio (width divided by height).
+     *
+     * @return the width of the image in user coordinates.
+     */
+    public float getWidth() {
+        if (boundingBox == null) {
+            boundingBox = myCRIF.getBounds2D(paramBlock);
+        }
+        return (float)boundingBox.getWidth();
+    }
+
+    /**
+     * Gets the height in user coordinate space.  By convention, the
+     * usual height of a RenderedImage is equal to 1.0F.
+     *
+     * @return the height of the image in user coordinates.
+     */
+    public float getHeight() {
+        if (boundingBox == null) {
+            boundingBox = myCRIF.getBounds2D(paramBlock);
+        }
+        return (float)boundingBox.getHeight();
+    }
+
+    /**
+     * Gets the minimum X coordinate of the rendering-independent image data.
+     */
+    public float getMinX() {
+        if (boundingBox == null) {
+            boundingBox = myCRIF.getBounds2D(paramBlock);
+        }
+        return (float)boundingBox.getMinX();
+    }
+
+    /**
+     * Gets the minimum Y coordinate of the rendering-independent image data.
+     */
+    public float getMinY() {
+        if (boundingBox == null) {
+            boundingBox = myCRIF.getBounds2D(paramBlock);
+        }
+        return (float)boundingBox.getMinY();
+    }
+
+    /**
+     * Change the current ParameterBlock of the operation, allowing
+     * editing of image rendering chains.  The effects of such a
+     * change will be visible when a new rendering is created from
+     * this RenderableImageOp or any dependent RenderableImageOp.
+     *
+     * @param paramBlock the new ParameterBlock.
+     * @return the old ParameterBlock.
+     * @see #getParameterBlock
+     */
+    public ParameterBlock setParameterBlock(ParameterBlock paramBlock) {
+        ParameterBlock oldParamBlock = this.paramBlock;
+        this.paramBlock = (ParameterBlock)paramBlock.clone();
+        return oldParamBlock;
+    }
+
+    /**
+     * Returns a reference to the current parameter block.
+     * @return the <code>ParameterBlock</code> of this
+     *         <code>RenderableImageOp</code>.
+     * @see #setParameterBlock(ParameterBlock)
+     */
+    public ParameterBlock getParameterBlock() {
+        return paramBlock;
+    }
+
+    /**
+     * Creates a RenderedImage instance of this image with width w, and
+     * height h in pixels.  The RenderContext is built automatically
+     * with an appropriate usr2dev transform and an area of interest
+     * of the full image.  All the rendering hints come from hints
+     * passed in.
+     *
+     * <p> If w == 0, it will be taken to equal
+     * Math.round(h*(getWidth()/getHeight())).
+     * Similarly, if h == 0, it will be taken to equal
+     * Math.round(w*(getHeight()/getWidth())).  One of
+     * w or h must be non-zero or else an IllegalArgumentException
+     * will be thrown.
+     *
+     * <p> The created RenderedImage may have a property identified
+     * by the String HINTS_OBSERVED to indicate which RenderingHints
+     * were used to create the image.  In addition any RenderedImages
+     * that are obtained via the getSources() method on the created
+     * RenderedImage may have such a property.
+     *
+     * @param w the width of rendered image in pixels, or 0.
+     * @param h the height of rendered image in pixels, or 0.
+     * @param hints a RenderingHints object containg hints.
+     * @return a RenderedImage containing the rendered data.
+     */
+    public RenderedImage createScaledRendering(int w, int h,
+                                               RenderingHints hints) {
+        // DSR -- code to try to get a unit scale
+        double sx = (double)w/getWidth();
+        double sy = (double)h/getHeight();
+        if (Math.abs(sx/sy - 1.0) < 0.01) {
+            sx = sy;
+        }
+        AffineTransform usr2dev = AffineTransform.getScaleInstance(sx, sy);
+        RenderContext newRC = new RenderContext(usr2dev, hints);
+        return createRendering(newRC);
+    }
+
+    /**
+     * Gets a RenderedImage instance of this image with a default
+     * width and height in pixels.  The RenderContext is built
+     * automatically with an appropriate usr2dev transform and an area
+     * of interest of the full image.  All the rendering hints come
+     * from hints passed in.  Implementors of this interface must be
+     * sure that there is a defined default width and height.
+     *
+     * @return a RenderedImage containing the rendered data.
+     */
+    public RenderedImage createDefaultRendering() {
+        AffineTransform usr2dev = new AffineTransform(); // Identity
+        RenderContext newRC = new RenderContext(usr2dev);
+        return createRendering(newRC);
+    }
+
+    /**
+     * Creates a RenderedImage which represents this
+     * RenderableImageOp (including its Renderable sources) rendered
+     * according to the given RenderContext.
+     *
+     * <p> This method supports chaining of either Renderable or
+     * RenderedImage operations.  If sources in
+     * the ParameterBlock used to construct the RenderableImageOp are
+     * RenderableImages, then a three step process is followed:
+     *
+     * <ol>
+     * <li> mapRenderContext() is called on the associated CRIF for
+     * each RenderableImage source;
+     * <li> createRendering() is called on each of the RenderableImage sources
+     * using the backwards-mapped RenderContexts obtained in step 1,
+     * resulting in a rendering of each source;
+     * <li> ContextualRenderedImageFactory.create() is called
+     * with a new ParameterBlock containing the parameters of
+     * the RenderableImageOp and the RenderedImages that were created by the
+     * createRendering() calls.
+     * </ol>
+     *
+     * <p> If the elements of the source Vector of
+     * the ParameterBlock used to construct the RenderableImageOp are
+     * instances of RenderedImage, then the CRIF.create() method is
+     * called immediately using the original ParameterBlock.
+     * This provides a basis case for the recursion.
+     *
+     * <p> The created RenderedImage may have a property identified
+     * by the String HINTS_OBSERVED to indicate which RenderingHints
+     * (from the RenderContext) were used to create the image.
+     * In addition any RenderedImages
+     * that are obtained via the getSources() method on the created
+     * RenderedImage may have such a property.
+     *
+     * @param renderContext The RenderContext to use to perform the rendering.
+     * @return a RenderedImage containing the desired output image.
+     */
+    public RenderedImage createRendering(RenderContext renderContext) {
+        RenderedImage image = null;
+        RenderContext rcOut = null;
+
+        // Clone the original ParameterBlock; if the ParameterBlock
+        // contains RenderableImage sources, they will be replaced by
+        // RenderedImages.
+        ParameterBlock renderedParamBlock = (ParameterBlock)paramBlock.clone();
+        Vector sources = getRenderableSources();
+
+        try {
+            // This assumes that if there is no renderable source, that there
+            // is a rendered source in paramBlock
+
+            if (sources != null) {
+                Vector renderedSources = new Vector();
+                for (int i = 0; i < sources.size(); i++) {
+                    rcOut = myCRIF.mapRenderContext(i, renderContext,
+                                                    paramBlock, this);
+                    RenderedImage rdrdImage =
+                       ((RenderableImage)sources.elementAt(i)).createRendering(rcOut);
+                    if (rdrdImage == null) {
+                        return null;
+                    }
+
+                    // Add this rendered image to the ParameterBlock's
+                    // list of RenderedImages.
+                    renderedSources.addElement(rdrdImage);
+                }
+
+                if (renderedSources.size() > 0) {
+                    renderedParamBlock.setSources(renderedSources);
+                }
+            }
+
+            return myCRIF.create(renderContext, renderedParamBlock);
+        } catch (ArrayIndexOutOfBoundsException e) {
+            // This should never happen
+            return null;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/awt/image/renderable/RenderableImageProducer.java	Thu Apr 10 16:28:45 2008 -0700
@@ -0,0 +1,219 @@
+/*
+ * Portions Copyright 1998 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* ********************************************************************
+ **********************************************************************
+ **********************************************************************
+ *** COPYRIGHT (c) Eastman Kodak Company, 1997                      ***
+ *** As  an unpublished  work pursuant to Title 17 of the United    ***
+ *** States Code.  All rights reserved.                             ***
+ **********************************************************************
+ **********************************************************************
+ **********************************************************************/
+
+package java.awt.image.renderable;
+import java.awt.color.ColorSpace;
+import java.awt.image.ColorModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.DirectColorModel;
+import java.awt.image.ImageConsumer;
+import java.awt.image.ImageProducer;
+import java.awt.image.Raster;
+import java.awt.image.RenderedImage;
+import java.awt.image.SampleModel;
+import java.util.Enumeration;
+import java.util.Vector;
+
+/**
+ * An adapter class that implements ImageProducer to allow the
+ * asynchronous production of a RenderableImage.  The size of the
+ * ImageConsumer is determined by the scale factor of the usr2dev
+ * transform in the RenderContext.  If the RenderContext is null, the
+ * default rendering of the RenderableImage is used.  This class
+ * implements an asynchronous production that produces the image in
+ * one thread at one resolution.  This class may be subclassed to
+ * implement versions that will render the image using several
+ * threads.  These threads could render either the same image at
+ * progressively better quality, or different sections of the image at
+ * a single resolution.
+ */
+public class RenderableImageProducer implements ImageProducer, Runnable {
+
+    /** The RenderableImage source for the producer. */
+    RenderableImage rdblImage;
+
+    /** The RenderContext to use for producing the image. */
+    RenderContext rc;
+
+    /** A Vector of image consumers. */
+    Vector ics = new Vector();
+
+    /**
+     * Constructs a new RenderableImageProducer from a RenderableImage
+     * and a RenderContext.
+     *
+     * @param rdblImage the RenderableImage to be rendered.
+     * @param rc the RenderContext to use for producing the pixels.
+     */
+    public RenderableImageProducer(RenderableImage rdblImage,
+                                   RenderContext rc) {
+        this.rdblImage = rdblImage;
+        this.rc = rc;
+    }
+
+    /**
+     * Sets a new RenderContext to use for the next startProduction() call.
+     *
+     * @param rc the new RenderContext.
+     */
+    public synchronized void setRenderContext(RenderContext rc) {
+        this.rc = rc;
+    }
+
+   /**
+     * Adds an ImageConsumer to the list of consumers interested in
+     * data for this image.
+     *
+     * @param ic an ImageConsumer to be added to the interest list.
+     */
+    public synchronized void addConsumer(ImageConsumer ic) {
+        if (!ics.contains(ic)) {
+            ics.addElement(ic);
+        }
+    }
+
+    /**
+     * Determine if an ImageConsumer is on the list of consumers
+     * currently interested in data for this image.
+     *
+     * @param ic the ImageConsumer to be checked.
+     * @return true if the ImageConsumer is on the list; false otherwise.
+     */
+    public synchronized boolean isConsumer(ImageConsumer ic) {
+        return ics.contains(ic);
+    }
+
+    /**
+     * Remove an ImageConsumer from the list of consumers interested in
+     * data for this image.
+     *
+     * @param ic the ImageConsumer to be removed.
+     */
+    public synchronized void removeConsumer(ImageConsumer ic) {
+        ics.removeElement(ic);
+    }
+
+    /**
+     * Adds an ImageConsumer to the list of consumers interested in
+     * data for this image, and immediately starts delivery of the
+     * image data through the ImageConsumer interface.
+     *
+     * @param ic the ImageConsumer to be added to the list of consumers.
+     */
+    public synchronized void startProduction(ImageConsumer ic) {
+        addConsumer(ic);
+        // Need to build a runnable object for the Thread.
+        Thread thread = new Thread(this, "RenderableImageProducer Thread");
+        thread.start();
+    }
+
+    /**
+     * Requests that a given ImageConsumer have the image data delivered
+     * one more time in top-down, left-right order.
+     *
+     * @param ic the ImageConsumer requesting the resend.
+     */
+    public void requestTopDownLeftRightResend(ImageConsumer ic) {
+        // So far, all pixels are already sent in TDLR order
+    }
+
+    /**
+     * The runnable method for this class. This will produce an image using
+     * the current RenderableImage and RenderContext and send it to all the
+     * ImageConsumer currently registered with this class.
+     */
+    public void run() {
+        // First get the rendered image
+        RenderedImage rdrdImage;
+        if (rc != null) {
+            rdrdImage = rdblImage.createRendering(rc);
+        } else {
+            rdrdImage = rdblImage.createDefaultRendering();
+        }
+
+        // And its ColorModel
+        ColorModel colorModel = rdrdImage.getColorModel();
+        Raster raster = rdrdImage.getData();
+        SampleModel sampleModel = raster.getSampleModel();
+        DataBuffer dataBuffer = raster.getDataBuffer();
+
+        if (colorModel == null) {
+            colorModel = ColorModel.getRGBdefault();
+        }
+        int minX = raster.getMinX();
+        int minY = raster.getMinY();
+        int width = raster.getWidth();
+        int height = raster.getHeight();
+
+        Enumeration icList;
+        ImageConsumer ic;
+        // Set up the ImageConsumers
+        icList = ics.elements();
+        while (icList.hasMoreElements()) {
+            ic = (ImageConsumer)icList.nextElement();
+            ic.setDimensions(width,height);
+            ic.setHints(ImageConsumer.TOPDOWNLEFTRIGHT |
+                        ImageConsumer.COMPLETESCANLINES |
+                        ImageConsumer.SINGLEPASS |
+                        ImageConsumer.SINGLEFRAME);
+        }
+
+        // Get RGB pixels from the raster scanline by scanline and
+        // send to consumers.
+        int pix[] = new int[width];
+        int i,j;
+        int numBands = sampleModel.getNumBands();
+        int tmpPixel[] = new int[numBands];
+        for (j = 0; j < height; j++) {
+            for(i = 0; i < width; i++) {
+                sampleModel.getPixel(i, j, tmpPixel, dataBuffer);
+                pix[i] = colorModel.getDataElement(tmpPixel, 0);
+            }
+            // Now send the scanline to the Consumers
+            icList = ics.elements();
+            while (icList.hasMoreElements()) {
+                ic = (ImageConsumer)icList.nextElement();
+                ic.setPixels(0, j, width, 1, colorModel, pix, 0, width);
+            }
+        }
+
+        // Now tell the consumers we're done.
+        icList = ics.elements();
+        while (icList.hasMoreElements()) {
+            ic = (ImageConsumer)icList.nextElement();
+            ic.imageComplete(ImageConsumer.STATICIMAGEDONE);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/awt/image/renderable/RenderedImageFactory.java	Thu Apr 10 16:28:45 2008 -0700
@@ -0,0 +1,78 @@
+/*
+ * Portions Copyright 1998 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* ********************************************************************
+ **********************************************************************
+ **********************************************************************
+ *** COPYRIGHT (c) Eastman Kodak Company, 1997                      ***
+ *** As  an unpublished  work pursuant to Title 17 of the United    ***
+ *** States Code.  All rights reserved.                             ***
+ **********************************************************************
+ **********************************************************************
+ **********************************************************************/
+
+package java.awt.image.renderable;
+import java.awt.image.RenderedImage;
+import java.awt.RenderingHints;
+
+/**
+ * The RenderedImageFactory interface (often abbreviated RIF) is
+ * intended to be implemented by classes that wish to act as factories
+ * to produce different renderings, for example by executing a series
+ * of BufferedImageOps on a set of sources, depending on a specific
+ * set of parameters, properties, and rendering hints.
+ */
+public interface RenderedImageFactory {
+
+  /**
+   * Creates a RenderedImage representing the results of an imaging
+   * operation (or chain of operations) for a given ParameterBlock and
+   * RenderingHints.  The RIF may also query any source images
+   * referenced by the ParameterBlock for their dimensions,
+   * SampleModels, properties, etc., as necessary.
+   *
+   * <p> The create() method can return null if the
+   * RenderedImageFactory is not capable of producing output for the
+   * given set of source images and parameters.  For example, if a
+   * RenderedImageFactory is only capable of performing a 3x3
+   * convolution on single-banded image data, and the source image has
+   * multiple bands or the convolution Kernel is 5x5, null should be
+   * returned.
+   *
+   * <p> Hints should be taken into account, but can be ignored.
+   * The created RenderedImage may have a property identified
+   * by the String HINTS_OBSERVED to indicate which RenderingHints
+   * were used to create the image.  In addition any RenderedImages
+   * that are obtained via the getSources() method on the created
+   * RenderedImage may have such a property.
+   *
+   * @param paramBlock a ParameterBlock containing sources and parameters
+   *        for the RenderedImage to be created.
+   * @param hints a RenderingHints object containing hints.
+   * @return A RenderedImage containing the desired output.
+   */
+  RenderedImage create(ParameterBlock paramBlock,
+                       RenderingHints hints);
+}