changeset 337:e21f4266466c jdk7-b29

Merge
author xdono
date Thu, 12 Jun 2008 11:46:57 -0700
parents a0d703b249f0 906a396bff74
children 0a5b87833562 3570562846ef edf7cd1ec436
files src/solaris/classes/sun/java2d/SurfaceManagerFactory.java src/windows/classes/sun/java2d/SurfaceManagerFactory.java test/javax/management/Introspector/LegacyIntrospectorTest.java
diffstat 109 files changed, 17877 insertions(+), 518 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Tue Jun 10 16:31:26 2008 -0700
+++ b/.hgtags	Thu Jun 12 11:46:57 2008 -0700
@@ -2,3 +2,4 @@
 75fca0b0ab83ab1392e615910cea020f66535390 jdk7-b25
 fb57027902e04ecafceae31a605e69b436c23d57 jdk7-b26
 3e599d98875ddf919c8ea11cff9b3a99ba631a9b jdk7-b27
+02e4c5348592a8d7fc2cba28bc5f8e35c0e17277 jdk7-b28
--- a/make/common/internal/BinaryPlugs.gmk	Tue Jun 10 16:31:26 2008 -0700
+++ b/make/common/internal/BinaryPlugs.gmk	Thu Jun 12 11:46:57 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	Tue Jun 10 16:31:26 2008 -0700
+++ b/make/java/awt/Makefile	Thu Jun 12 11:46:57 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
 
 #
--- a/make/sun/cmm/Makefile	Tue Jun 10 16:31:26 2008 -0700
+++ b/make/sun/cmm/Makefile	Thu Jun 12 11:46:57 2008 -0700
@@ -41,12 +41,8 @@
 ICCPROFILE_DEST_DIR = $(LIBDIR)/cmm
 
 iccprofiles: $(ICCPROFILE_DEST_DIR)/sRGB.pf $(ICCPROFILE_DEST_DIR)/GRAY.pf \
-	     $(ICCPROFILE_DEST_DIR)/CIEXYZ.pf
-
-ifndef OPENJDK
-iccprofiles:  $(ICCPROFILE_DEST_DIR)/PYCC.pf \
-	      $(ICCPROFILE_DEST_DIR)/LINEAR_RGB.pf
-endif
+	     $(ICCPROFILE_DEST_DIR)/CIEXYZ.pf $(ICCPROFILE_DEST_DIR)/PYCC.pf \
+	     $(ICCPROFILE_DEST_DIR)/LINEAR_RGB.pf
 
 $(ICCPROFILE_DEST_DIR)/sRGB.pf: $(ICCPROFILE_SRC_DIR)/sRGB.pf
 	$(RM) $(ICCPROFILE_DEST_DIR)/sRGB.pf
--- a/make/sun/font/FILES_c.gmk	Tue Jun 10 16:31:26 2008 -0700
+++ b/make/sun/font/FILES_c.gmk	Thu Jun 12 11:46:57 2008 -0700
@@ -113,7 +113,9 @@
 
 
 ifeq ($(PLATFORM),windows)
-FILES_c_platform = fontpath.c
+FILES_c_platform = fontpath.c \
+                   lcdglyph.c
+
 FILES_cpp_platform = D3DTextRenderer.cpp
 else
 FILES_c_platform = X11FontScaler.c \
--- a/make/sun/font/Makefile	Tue Jun 10 16:31:26 2008 -0700
+++ b/make/sun/font/Makefile	Thu Jun 12 11:46:57 2008 -0700
@@ -63,6 +63,7 @@
     java/awt/Font.java \
     java/text/Bidi.java \
     sun/font/FileFont.java \
+    sun/font/FileFontStrike.java \
     sun/font/FontManager.java \
     sun/font/GlyphList.java \
     sun/font/NativeFont.java \
--- a/src/share/classes/java/awt/Component.java	Tue Jun 10 16:31:26 2008 -0700
+++ b/src/share/classes/java/awt/Component.java	Thu Jun 12 11:46:57 2008 -0700
@@ -3057,10 +3057,24 @@
             // services.  Additionally, the request is restricted to
             // the bounds of the component.
             if (parent != null) {
-                int px = this.x + ((x < 0) ? 0 : x);
-                int py = this.y + ((y < 0) ? 0 : y);
+                if (x < 0) {
+                    width += x;
+                    x = 0;
+                }
+                if (y < 0) {
+                    height += y;
+                    y = 0;
+                }
+
                 int pwidth = (width > this.width) ? this.width : width;
                 int pheight = (height > this.height) ? this.height : height;
+
+                if (pwidth <= 0 || pheight <= 0) {
+                    return;
+                }
+
+                int px = this.x + x;
+                int py = this.y + y;
                 parent.repaint(tm, px, py, pwidth, pheight);
             }
         } else {
--- a/src/share/classes/java/awt/Font.java	Tue Jun 10 16:31:26 2008 -0700
+++ b/src/share/classes/java/awt/Font.java	Thu Jun 12 11:46:57 2008 -0700
@@ -711,7 +711,7 @@
                                 EBIDI_EMBEDDING, EJUSTIFICATION,
                                 EINPUT_METHOD_HIGHLIGHT, EINPUT_METHOD_UNDERLINE,
                                 ESWAP_COLORS, ENUMERIC_SHAPING, EKERNING,
-                                ELIGATURES, ETRACKING);
+                                ELIGATURES, ETRACKING, ESUPERSCRIPT);
 
     private static final int EXTRA_MASK =
             AttributeValues.getMask(ETRANSFORM, ESUPERSCRIPT, EWIDTH);
@@ -1970,7 +1970,6 @@
      * in the JDK - and the only likely caller - is in this same class.
      */
     private float getItalicAngle(FontRenderContext frc) {
-        AffineTransform at = (isTransformed()) ? getTransform() : identityTx;
         Object aa, fm;
         if (frc == null) {
             aa = RenderingHints.VALUE_TEXT_ANTIALIAS_OFF;
@@ -1979,7 +1978,7 @@
             aa = frc.getAntiAliasingHint();
             fm = frc.getFractionalMetricsHint();
         }
-        return getFont2D().getItalicAngle(this, at, aa, fm);
+        return getFont2D().getItalicAngle(this, identityTx, aa, fm);
     }
 
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/awt/color/CMMException.java	Thu Jun 12 11:46:57 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 Jun 12 11:46:57 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 Jun 12 11:46:57 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 Jun 12 11:46:57 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 Jun 12 11:46:57 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 Jun 12 11:46:57 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;
+    }
+
+}
--- a/src/share/classes/java/awt/dnd/DragSourceContext.java	Tue Jun 10 16:31:26 2008 -0700
+++ b/src/share/classes/java/awt/dnd/DragSourceContext.java	Thu Jun 12 11:46:57 2008 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright 1997-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1997-2008 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
@@ -485,7 +485,6 @@
 
         Cursor c = null;
 
-        targetAct = DnDConstants.ACTION_NONE;
         switch (status) {
             case ENTER:
             case OVER:
@@ -507,6 +506,10 @@
                     else
                         c = DragSource.DefaultCopyDrop;
                 }
+                break;
+            default:
+                targetAct = DnDConstants.ACTION_NONE;
+
         }
 
         setCursorImpl(c);
--- a/src/share/classes/java/awt/font/OpenType.java	Tue Jun 10 16:31:26 2008 -0700
+++ b/src/share/classes/java/awt/font/OpenType.java	Thu Jun 12 11:46:57 2008 -0700
@@ -31,9 +31,9 @@
  * <i>sfnt</i> tables from the font.  A particular
  * <code>Font</code> object can implement this interface.
  * <p>
- * For more information on TrueType fonts, see the
- * Apple TrueType Reference Manual
- * ( <a href="http://fonts.apple.com/TTRefMan/index.html">http://fonts.apple.com/TTRefMan/index.html</a> ).
+ * For more information on TrueType and OpenType fonts, see the
+ * OpenType specification.
+ * ( <a href=http://www.microsoft.com/typography/otspec/">http://www.microsoft.com/typography/otspec/l</a> ).
  */
 public interface OpenType {
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/awt/image/BandedSampleModel.java	Thu Jun 12 11:46:57 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 Jun 12 11:46:57 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 Jun 12 11:46:57 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 Jun 12 11:46:57 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 Jun 12 11:46:57 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 Jun 12 11:46:57 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 Jun 12 11:46:57 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 Jun 12 11:46:57 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 Jun 12 11:46:57 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 i