# HG changeset patch # User lana # Date 1207877486 25200 # Node ID 17a5f29f1ae87a18a7497ed2c68a786d46df3864 # Parent bbe9212c700515be4c8c5dff0354104386810e8c# Parent 7952521a4ad3e1950e995970f5e9a4cc8bdcd4ff Merge diff -r bbe9212c7005 -r 17a5f29f1ae8 jdk/make/common/internal/BinaryPlugs.gmk --- a/jdk/make/common/internal/BinaryPlugs.gmk Thu Apr 10 15:50:46 2008 -0700 +++ b/jdk/make/common/internal/BinaryPlugs.gmk Thu Apr 10 18:31:26 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 diff -r bbe9212c7005 -r 17a5f29f1ae8 jdk/make/java/awt/Makefile --- a/jdk/make/java/awt/Makefile Thu Apr 10 15:50:46 2008 -0700 +++ b/jdk/make/java/awt/Makefile Thu Apr 10 18:31:26 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 # diff -r bbe9212c7005 -r 17a5f29f1ae8 jdk/src/share/classes/java/awt/color/CMMException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/awt/color/CMMException.java Thu Apr 10 18:31:26 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); + } +} diff -r bbe9212c7005 -r 17a5f29f1ae8 jdk/src/share/classes/java/awt/color/ColorSpace.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/awt/color/ColorSpace.java Thu Apr 10 18:31:26 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. + *

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

+ * 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 + * http://www.w3.org/pub/WWW/Graphics/Color/sRGB.html + * . + *

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

+ * The CS_CIEXYZ space used by the toCIEXYZ/fromCIEXYZ methods can be + * described as follows: +

+
+      CIEXYZ
+      viewing illuminance: 200 lux
+      viewing white point: CIE D50
+      media white point: "that of a perfectly reflecting diffuser" -- D50
+      media black point: 0 lux or 0 Reflectance
+      flare: 1 percent
+      surround: 20percent of the media white point
+      media description: reflection print (i.e., RLAB, Hunt viewing media)
+      note: For developers creating an ICC profile for this conversion
+            space, the following is applicable.  Use a simple Von Kries
+            white point adaptation folded into the 3X3 matrix parameters
+            and fold the flare and surround effects into the three
+            one-dimensional lookup tables (assuming one uses the minimal
+            model for monitors).
+
+
+ * + *

+ * @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 + * + * http://www.w3.org/pub/WWW/Graphics/Color/sRGB.html + * . + */ + 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 ColorSpace 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 ColorSpace 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 true if this is a CS_sRGB color + * space, false 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. + *

+ * 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 toCIEXYZ + * method of this color space to first convert from the input + * color space to the CS_CIEXYZ color space, and then use the + * fromCIEXYZ 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. + *

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

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

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

+ * 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 + * ICC_ColorSpace for further information. + *

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

+ * 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 + * ICC_ColorSpace for further information. + *

+ * @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 + * ColorSpace + */ + public int getType() { + return type; + } + + /** + * Returns the number of components of this ColorSpace. + * @return The number of components in this ColorSpace. + */ + 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 idx 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); + } +} diff -r bbe9212c7005 -r 17a5f29f1ae8 jdk/src/share/classes/java/awt/color/ICC_ColorSpace.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/awt/color/ICC_ColorSpace.java Thu Apr 10 18:31:26 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 http://www.color.org). + *

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

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

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

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

+ * 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 toCIEXYZ + * method of this color space to first convert from the input + * color space to the CS_CIEXYZ color space, and then use the + * fromCIEXYZ 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. + *

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

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

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

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

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

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

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

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

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

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

+ * Conversion from the PCS to the device would be done by inverting these + * equations: + *

+     *
+     * Xd = Xp * (Xdw / Xd50)
+     * Yd = Yp * (Ydw / Yd50)
+     * Zd = Zp * (Zdw / Zd50)
+     *
+     * 
+ *

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

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

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

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

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

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

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

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

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

+ * Conversion from the PCS to the device would be done by inverting these + * equations: + *

+     *
+     * Xd = Xp * (Xdw / Xd50)
+     * Yd = Yp * (Ydw / Yd50)
+     * Zd = Zp * (Zdw / Zd50)
+     *
+     * 
+ *

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

+ *

+ * @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; + } + +} diff -r bbe9212c7005 -r 17a5f29f1ae8 jdk/src/share/classes/java/awt/color/ICC_Profile.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/awt/color/ICC_Profile.java Thu Apr 10 18:31:26 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 http://www.color.org). + *

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

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

+ * @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 ICC_Profile object corresponding to + * the data in the specified data 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 ColorSpace class. + * + * @return an ICC_Profile object corresponding to + * the specified ColorSpace type. + * @exception IllegalArgumentException If cspace 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 ICC_Profile 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 ICC_Profile object corresponding to the + * data in the specified InputStream. + * + * @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 + * ColorSpace 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 + * ColorSpace 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 + * null 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 1 corresponds to Java 2 + * Platform, 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 ObjectInputStream. + * @serialData + * The String is the name of one of + * CS_* constants defined in the + * {@link ColorSpace} class if the profile object is a profile + * for a predefined color space (for example + * "CS_sRGB"). The string is null + * otherwise. + *

+ * The byte[] array is the profile data for the + * profile. For predefined color spaces null 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 ObjectInputStream. + * @throws ClassNotFoundException + * thrown by ObjectInputStream. + * @serialData + * The String is the name of one of + * CS_* constants defined in the + * {@link ColorSpace} class if the profile object is a profile + * for a predefined color space (for example + * "CS_sRGB"). The string is null + * otherwise. + *

+ * The byte[] array is the profile data for the + * profile. It will usually be null for the + * predefined profiles. + *

+ * If the string is recognized as a constant name for + * predefined color space the object will be resolved into + * profile obtained with + * getInstance(int cspace) and the profile + * data are ignored. Otherwise the object will be resolved + * into profile obtained with + * getInstance(byte[] data). + * @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; + } +} diff -r bbe9212c7005 -r 17a5f29f1ae8 jdk/src/share/classes/java/awt/color/ICC_ProfileGray.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/awt/color/ICC_ProfileGray.java Thu Apr 10 18:31:26 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. + *

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

+
+                PCSY = grayTRC[deviceGray]
+
+
+ * The inverse transform is done by converting the PCS Y components to + * device Gray via the inverse of the grayTRC. + *

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

+
+                          gamma
+         PCSY = deviceGray
+
+
+ * @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; + } + +} diff -r bbe9212c7005 -r 17a5f29f1ae8 jdk/src/share/classes/java/awt/color/ICC_ProfileRGB.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/awt/color/ICC_ProfileRGB.java Thu Apr 10 18:31:26 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: + * + * The ICC_Profile getInstance method will + * return an ICC_ProfileRGB object when these conditions are met. + * Three-component, matrix-based input profiles and RGB display profiles are + * examples of this type of profile. + *

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

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

+ *
+ *                 linearR = redTRC[deviceR]
+ *
+ *                 linearG = greenTRC[deviceG]
+ *
+ *                 linearB = blueTRC[deviceB]
+ *
+ *   _      _       _                                             _   _         _
+ *  [  PCSX  ]     [  redColorantX  greenColorantX  blueColorantX  ] [  linearR  ]
+ *  [        ]     [                                               ] [           ]
+ *  [  PCSY  ]  =  [  redColorantY  greenColorantY  blueColorantY  ] [  linearG  ]
+ *  [        ]     [                                               ] [           ]
+ *  [_ PCSZ _]     [_ redColorantZ  greenColorantZ  blueColorantZ _] [_ linearB _]
+ *
+ * 
+ * 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. + *

+ */ + + + +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 ICC_ProfileRGB from a CMM ID. + * + * @param ID The CMM ID for the profile. + * + */ + ICC_ProfileRGB(long ID) { + super(ID); + } + + /** + * Constructs a new ICC_ProfileRGB from a + * ProfileDeferralInfo object. + * + * @param pdi + */ + ICC_ProfileRGB(ProfileDeferralInfo pdi) { + super(pdi); + } + + + /** + * Returns an array that contains the components of the profile's + * mediaWhitePointTag. + * + * @return A 3-element float array containing the x, y, + * and z components of the profile's mediaWhitePointTag. + */ + public float[] getMediaWhitePoint() { + return super.getMediaWhitePoint(); + } + + + /** + * Returns a 3x3 float matrix constructed from the + * X, Y, and Z components of the profile's redColorantTag, + * greenColorantTag, and blueColorantTag. + *

+ * 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 float array that contains the x, y, and z + * components of the profile's redColorantTag, + * greenColorantTag, and blueColorantTag. + */ + 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. + *

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

+     *
+     *                                           gamma
+     *          linearComponent = deviceComponent
+     *
+     *
+ * @param component The ICC_ProfileRGB 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 REDCOMPONENT, + * GREENCOMPONENT, or BLUECOMPONENT. + * 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 + * short values even though they are returned in a + * short 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 ICC_ProfileRGB constant that + * represents the component whose TRC you want to retrieve: + * REDCOMPONENT, GREENCOMPONENT, or + * BLUECOMPONENT. + * + * @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; + } + +} diff -r bbe9212c7005 -r 17a5f29f1ae8 jdk/src/share/classes/java/awt/image/BandedSampleModel.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/awt/image/BandedSampleModel.java Thu Apr 10 18:31:26 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 dataType 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 dataType 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 BandedSampleModel + * @param h the height of the resulting BandedSampleModel + * @return a new BandedSampleModel with the specified + * width and height. + * @throws IllegalArgumentException if w or + * h equals either + * Integer.MAX_VALUE or + * Integer.MIN_VALUE + * @throws IllegalArgumentException if dataType 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 dataType 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; idataType 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. + *

+ * The following code illustrates transferring data for one pixel from + * DataBuffer db1, whose storage layout is described by + * BandedSampleModel bsm1, to DataBuffer db2, + * whose storage layout is described by + * BandedSampleModel bsm2. + * The transfer will generally be more efficient than using + * getPixel/setPixel. + *

+     *       BandedSampleModel bsm1, bsm2;
+     *       DataBufferInt db1, db2;
+     *       bsm2.setDataElements(x, y, bsm1.getDataElements(x, y, null, db1),
+     *                            db2);
+     * 
+ * 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. + *

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

+ * The following code illustrates transferring data for one pixel from + * DataBuffer db1, whose storage layout is described by + * BandedSampleModel bsm1, to DataBuffer db2, + * whose storage layout is described by + * BandedSampleModel bsm2. + * The transfer will generally be more efficient than using + * getPixel/setPixel. + *

+     *       BandedSampleModel bsm1, bsm2;
+     *       DataBufferInt db1, db2;
+     *       bsm2.setDataElements(x, y, bsm1.getDataElements(x, y, null, db1),
+     *                            db2);
+     * 
+ * 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. + *

+ * 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= width) || (y >= height)) { + throw new ArrayIndexOutOfBoundsException + ("Coordinate out of bounds!"); + } + int pixelOffset = y*scanlineStride + x; + for (int i=0; i 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; + } +} diff -r bbe9212c7005 -r 17a5f29f1ae8 jdk/src/share/classes/java/awt/image/ColorConvertOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/awt/image/ColorConvertOp.java Thu Apr 10 18:31:26 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. + *

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

+ * If a RenderingHints object is specified in the constructor, the + * color rendering hint and the dithering hint may be used to control + * color conversion. + *

+ * Note that Source and Destination may be the same object. + *

+ * @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 RenderingHints object used to control + * the color conversion, or null + */ + 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 ColorSpace or an + * intermediate ColorSpace + * @param hints the RenderingHints object used to control + * the color conversion, or null + * @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 ColorSpace + * @param dstCspace the destination ColorSpace + * @param hints the RenderingHints object used to control + * the color conversion, or null + * @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. + *

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

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 ICC_Profile objects + * @param hints the RenderingHints object used to control + * the color conversion, or null + * @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 ICC_Profile objects of this + * ColorConvertOp, or null if this + * ColorConvertOp was not constructed with an + * array of ICC_Profile 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 BufferedImage to be converted + * @param dest the destination BufferedImage, + * or null + * @return dest color converted from src + * or a new, converted BufferedImage + * if dest is null + * @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 Raster to be converted + * @param dest the destination WritableRaster, + * or null + * @return dest color converted from src + * or a new, converted WritableRaster + * if dest is null + * @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 BufferedImage + * @return a Rectangle2D that is the bounding box + * of the destination, given the specified src + */ + 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 Raster + * @return a Rectangle2D that is the bounding box + * of the destination, given the specified src + */ + 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 BufferedImage with the correct size and + * number of bands from the specified src. + * @throws IllegalArgumentException if destCM is + * null and this ColorConvertOp was + * created without any ICC_Profile or + * ColorSpace 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 Raster + * @return a WritableRaster with the correct size and number + * of bands from the specified src + * @throws IllegalArgumentException if this ColorConvertOp + * was created without sufficient information to define the + * dst and src 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 dstPt 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 Point2D + * @param dstPt the destination Point2D + * @return dstPt after setting its location to be + * the same as srcPt + */ + 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 RenderingHints object of this + * ColorConvertOp + */ + 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); + } + } + +} diff -r bbe9212c7005 -r 17a5f29f1ae8 jdk/src/share/classes/java/awt/image/ComponentSampleModel.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/awt/image/ComponentSampleModel.java Thu Apr 10 18:31:26 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 DataBuffer.TYPE_BYTE, + * DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT, + * respectively), data for which each sample is a signed integral number + * which can be stored in 16 bits (using DataBuffer.TYPE_SHORT), + * or data for which each sample is a signed float or double quantity + * (using DataBuffer.TYPE_FLOAT or + * DataBuffer.TYPE_DOUBLE, 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 + * ComponentSampleModel. + */ + protected int numBands = 1; + + /** + * The number of banks in this + * ComponentSampleModel. + */ + 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 w or + * h is not greater than 0 + * @throws IllegalArgumentException if pixelStride + * is less than 0 + * @throws IllegalArgumentException if scanlineStride + * is less than 0 + * @throws IllegalArgumentException if numBands + * is less than 1 + * @throws IllegalArgumentException if the product of w + * and h is greater than + * Integer.MAX_VALUE + * @throws IllegalArgumentException if dataType 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; iw or + * h is not greater than 0 + * @throws IllegalArgumentException if pixelStride + * is less than 0 + * @throws IllegalArgumentException if scanlineStride + * is less than 0 + * @throws IllegalArgumentException if the length of + * bankIndices does not equal the length of + * bankOffsets + * @throws IllegalArgumentException if any of the bank indices + * of bandIndices is less than 0 + * @throws IllegalArgumentException if dataType 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= 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 orig[map[j]]) { + index = j; + } + } + ret[map[index]] = i*step; + map[index] = map[i]; + } + return ret; + } + + /** + * Creates a new ComponentSampleModel with the specified + * width and height. The new SampleModel will have the same + * number of bands, storage data type, interleaving scheme, and + * pixel stride as this SampleModel. + * @param w the width of the resulting SampleModel + * @param h the height of the resulting SampleModel + * @return a new ComponentSampleModel with the specified size + * @throws IllegalArgumentException if w or + * h 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 lStride) { + if (pStride > bStride) { + if (lStride > bStride) { // pix > line > band + bandOff = new int[bandOffsets.length]; + for (int i=0; i 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 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; iComponentSampleModel + * @return a ComponentSampleModel created with a subset + * of bands from this ComponentSampleModel. + */ + 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; iDataBuffer that corresponds to this + * ComponentSampleModel. + * The DataBuffer object's data type, number of banks, + * and size are be consistent with this ComponentSampleModel. + * @return a DataBuffer whose data type, number of banks + * and size are consistent with this + * ComponentSampleModel. + */ + 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 + * DataBuffer + * data with a ComponentSampleModel + * csm as + *

+     *        data.getElem(csm.getOffset(x, y));
+     * 
+ * @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 b can be retrieved from a + * DataBuffer data + * with a ComponentSampleModel csm as + *
+     *       data.getElem(csm.getOffset(x, y, b));
+     * 
+ * @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; iComponentSampleModel. + */ + public final int getScanlineStride() { + return scanlineStride; + } + + /** Returns the pixel stride of this ComponentSampleModel. + * @return the pixel stride of this ComponentSampleModel. + */ + 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 ComponentSampleModel, this is identical to the + * number of bands. + * @return the number of data elements needed to transfer a pixel with + * the getDataElements and + * setDataElements 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 + * TransferType. For a ComponentSampleModel, + * this is the same as the data type, and samples are returned + * one per array element. Generally, obj should + * be passed in as null, so that the Object + * is created automatically and is the right primitive data type. + *

+ * The following code illustrates transferring data for one pixel from + * DataBuffer db1, whose storage layout is + * described by ComponentSampleModel csm1, + * to DataBuffer db2, whose storage layout + * is described by ComponentSampleModel csm2. + * The transfer is usually more efficient than using + * getPixel and setPixel. + *

+     *       ComponentSampleModel csm1, csm2;
+     *       DataBufferInt db1, db2;
+     *       csm2.setDataElements(x, y,
+     *                            csm1.getDataElements(x, y, null, db1), db2);
+     * 
+ * + * Using getDataElements and setDataElements + * to transfer between two DataBuffer/SampleModel + * pairs is legitimate if the SampleModel objects have + * the same number of bands, corresponding bands have the same number of + * bits per sample, and the TransferTypes are the same. + *

+ * If obj is not null, it should be a + * primitive array of type TransferType. + * Otherwise, a ClassCastException is thrown. An + * ArrayIndexOutOfBoundsException might be thrown if the + * coordinates are not in bounds, or if obj is not + * 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 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; iArrayIndexOutOfBoundsException 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; iArrayIndexOutOfBoundsException 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 ArrayIndexOutOfBoundsException 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 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 ArrayIndexOutOfBoundsException 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 ArrayIndexOutOfBoundsException 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 ArrayIndexOutOfBoundsException 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-null, returns the samples + * in this array + * @param data the DataBuffer 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 + * DataBuffer from a primitive array of type + * TransferType. For a ComponentSampleModel, + * this is the same as the data type, and samples are transferred + * one per array element. + *

+ * The following code illustrates transferring data for one pixel from + * DataBuffer db1, whose storage layout is + * described by ComponentSampleModel csm1, + * to DataBuffer db2, whose storage layout + * is described by ComponentSampleModel csm2. + * The transfer is usually more efficient than using + * getPixel and setPixel. + *

+     *       ComponentSampleModel csm1, csm2;
+     *       DataBufferInt db1, db2;
+     *       csm2.setDataElements(x, y, csm1.getDataElements(x, y, null, db1),
+     *                            db2);
+     * 
+ * Using getDataElements and setDataElements + * to transfer between two DataBuffer/SampleModel pairs + * is legitimate if the SampleModel objects have + * the same number of bands, corresponding bands have the same number of + * bits per sample, and the TransferTypes are the same. + *

+ * A ClassCastException is thrown if obj is not + * a primitive array of type TransferType. + * An ArrayIndexOutOfBoundsException might be thrown if + * the coordinates are not in bounds, or if obj is not large + * enough to hold the pixel data. + * @param x the X coordinate of the pixel location + * @param y the Y coordinate of the pixel location + * @param obj a primitive array containing pixel data + * @param data the DataBuffer containing the image data + * @see #getDataElements(int, int, Object, DataBuffer) + */ + public void setDataElements(int x, int y, Object obj, DataBuffer data) { + if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { + throw new ArrayIndexOutOfBoundsException + ("Coordinate out of bounds!"); + } + + int type = getTransferType(); + int numDataElems = getNumDataElements(); + int pixelOffset = y*scanlineStride + x*pixelStride; + + switch(type) { + + case DataBuffer.TYPE_BYTE: + + byte[] barray = (byte[])obj; + + for (int i=0; iDataBuffer using an int array of + * samples for input. An ArrayIndexOutOfBoundsException + * 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; iArrayIndexOutOfBoundsException 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 DataBuffer using an int for input. + * An ArrayIndexOutOfBoundsException 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 DataBuffer using a float for input. + * An ArrayIndexOutOfBoundsException 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 DataBuffer using a double for input. + * An ArrayIndexOutOfBoundsException 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 ArrayIndexOutOfBoundsException 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; + } +} diff -r bbe9212c7005 -r 17a5f29f1ae8 jdk/src/share/classes/java/awt/image/DataBuffer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/awt/image/DataBuffer.java Thu Apr 10 18:31:26 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 type 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 DataBuffer + * @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 DataBuffer + * @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 DataBuffer + * @param size the size of the banks + * @param numBanks the number of banks in this + * DataBuffer + */ + 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 DataBuffer + * @param size the size of the banks + * @param numBanks the number of banks in this + * DataBuffer + * @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 DataBuffer + * @param size the size of the banks + * @param numBanks the number of banks in this + * DataBuffer + * @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 DataBuffer + * @param size the size of the banks + * @param numBanks the number of banks in this + * DataBuffer + * @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 DataBuffer + * @param size the size of the banks + * @param numBanks the number of banks in this + * DataBuffer + * @param offsets an array containing an offset for each bank. + * @throws ArrayIndexOutOfBoundsException if numBanks + * does not equal the length of offsets + */ + 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 DataBuffer + * @param size the size of the banks + * @param numBanks the number of banks in this + * DataBuffer + * @param offsets an array containing an offset for each bank. + * @throws ArrayIndexOutOfBoundsException if numBanks + * does not equal the length of offsets + * @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 DataBuffer. + */ + 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; + } + }); + } +} diff -r bbe9212c7005 -r 17a5f29f1ae8 jdk/src/share/classes/java/awt/image/DataBufferByte.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/awt/image/DataBufferByte.java Thu Apr 10 18:31:26 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 DataBuffer and stores data internally as bytes. + * Values stored in the byte array(s) of this DataBuffer are treated as + * unsigned values. + *

+ * + * 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. + * + */ +public final class DataBufferByte extends DataBuffer +{ + /** The default data bank. */ + byte data[]; + + /** All data banks */ + byte bankdata[][]; + + /** + * Constructs a byte-based DataBuffer with a single bank and the + * specified size. + * + * @param size The size of the DataBuffer. + */ + public DataBufferByte(int size) { + super(STABLE, TYPE_BYTE, size); + data = new byte[size]; + bankdata = new byte[1][]; + bankdata[0] = data; + } + + /** + * Constructs a byte based DataBuffer with the specified number of + * banks all of which are the specified size. + * + * @param size The size of the banks in the DataBuffer. + * @param numBanks The number of banks in the aDataBuffer. + */ + 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 DataBuffer with a single bank using the + * specified array. + * Only the first size elements should be used by accessors of + * this DataBuffer. dataArray must be large enough to + * hold size elements. + *

+ * Note that {@code DataBuffer} objects created by this constructor + * may be incompatible with performance + * optimizations used by some implementations (such as caching + * an associated image in video memory). + * + * @param dataArray The byte array for the DataBuffer. + * @param size The size of the DataBuffer 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 DataBuffer with a single bank using the + * specified array, size, and offset. dataArray must have at least + * offset + size elements. Only elements offset + * through offset + size - 1 + * should be used by accessors of this DataBuffer. + *

+ * Note that {@code DataBuffer} objects created by this constructor + * may be incompatible with performance + * optimizations used by some implementations (such as caching + * an associated image in video memory). + * + * @param dataArray The byte array for the DataBuffer. + * @param size The size of the DataBuffer bank. + * @param offset The offset into the dataArray. dataArray + * must have at least offset + size 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 DataBuffer with the specified arrays. + * The number of banks is equal to dataArray.length. + * Only the first size elements of each array should be used by + * accessors of this DataBuffer. + *

+ * Note that {@code DataBuffer} objects created by this constructor + * may be incompatible with performance + * optimizations used by some implementations (such as caching + * an associated image in video memory). + * + * @param dataArray The byte arrays for the DataBuffer. + * @param size The size of the banks in the DataBuffer. + */ + public DataBufferByte(byte dataArray[][], int size) { + super(UNTRACKABLE, TYPE_BYTE, size, dataArray.length); + bankdata = (byte[][]) dataArray.clone(); + data = bankdata[0]; + } + + /** + * Constructs a byte-based DataBuffer with the specified arrays, size, + * and offsets. + * The number of banks is equal to dataArray.length. Each array must + * be at least as large as size + the corresponding offset. + * There must be an entry in the offset array for each dataArray + * entry. For each bank, only elements offset through + * offset + size - 1 should be used by accessors of this + * DataBuffer. + *

+ * Note that {@code DataBuffer} objects created by this constructor + * may be incompatible with performance + * optimizations used by some implementations (such as caching + * an associated image in video memory). + * + * @param dataArray The byte arrays for the DataBuffer. + * @param size The size of the banks in the DataBuffer. + * @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. + *

+ * Note that calling this method may cause this {@code DataBuffer} + * object to be incompatible with performance + * optimizations 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. + *

+ * Note that calling this method may cause this {@code DataBuffer} + * object to be incompatible with performance + * optimizations 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. + *

+ * Note that calling this method may cause this {@code DataBuffer} + * object to be incompatible with performance + * optimizations 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(); + } +} diff -r bbe9212c7005 -r 17a5f29f1ae8 jdk/src/share/classes/java/awt/image/DataBufferInt.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/awt/image/DataBufferInt.java Thu Apr 10 18:31:26 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 DataBuffer and stores data internally + * as integers. + *

+ * + * 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. + * + */ +public final class DataBufferInt extends DataBuffer +{ + /** The default data bank. */ + int data[]; + + /** All data banks */ + int bankdata[][]; + + /** + * Constructs an integer-based DataBuffer with a single bank + * and the specified size. + * + * @param size The size of the DataBuffer. + */ + public DataBufferInt(int size) { + super(STABLE, TYPE_INT, size); + data = new int[size]; + bankdata = new int[1][]; + bankdata[0] = data; + } + + /** + * Constructs an integer-based DataBuffer with the specified number of + * banks, all of which are the specified size. + * + * @param size The size of the banks in the DataBuffer. + * @param numBanks The number of banks in the aDataBuffer. + */ + 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 DataBuffer with a single bank using the + * specified array. + * Only the first size elements should be used by accessors of + * this DataBuffer. dataArray must be large enough to + * hold size elements. + *

+ * Note that {@code DataBuffer} objects created by this constructor + * may be incompatible with performance + * optimizations used by some implementations (such as caching + * an associated image in video memory). + * + * @param dataArray The integer array for the DataBuffer. + * @param size The size of the DataBuffer 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 DataBuffer with a single bank using the + * specified array, size, and offset. dataArray must have at least + * offset + size elements. Only elements offset + * through offset + size - 1 + * should be used by accessors of this DataBuffer. + *

+ * Note that {@code DataBuffer} objects created by this constructor + * may be incompatible with performance + * optimizations used by some implementations (such as caching + * an associated image in video memory). + * + * @param dataArray The integer array for the DataBuffer. + * @param size The size of the DataBuffer bank. + * @param offset The offset into the dataArray. + */ + 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 DataBuffer with the specified arrays. + * The number of banks will be equal to dataArray.length. + * Only the first size elements of each array should be used by + * accessors of this DataBuffer. + *

+ * Note that {@code DataBuffer} objects created by this constructor + * may be incompatible with performance + * optimizations used by some implementations (such as caching + * an associated image in video memory). + * + * @param dataArray The integer arrays for the DataBuffer. + * @param size The size of the banks in the DataBuffer. + */ + public DataBufferInt(int dataArray[][], int size) { + super(UNTRACKABLE, TYPE_INT, size, dataArray.length); + bankdata = (int [][]) dataArray.clone(); + data = bankdata[0]; + } + + /** + * Constructs an integer-based DataBuffer with the specified arrays, size, + * and offsets. + * The number of banks is equal to dataArray.length. Each array must + * be at least as large as size + the corresponding offset. There must + * be an entry in the offset array for each dataArray entry. For each + * bank, only elements offset through + * offset + size - 1 should be + * used by accessors of this DataBuffer. + *

+ * Note that {@code DataBuffer} objects created by this constructor + * may be incompatible with performance + * optimizations used by some implementations (such as caching + * an associated image in video memory). + * + * @param dataArray The integer arrays for the DataBuffer. + * @param size The size of the banks in the DataBuffer. + * @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 DataBuffer. + *

+ * Note that calling this method may cause this {@code DataBuffer} + * object to be incompatible with performance + * optimizations 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. + *

+ * Note that calling this method may cause this {@code DataBuffer} + * object to be incompatible with performance + * optimizations 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. + *

+ * Note that calling this method may cause this {@code DataBuffer} + * object to be incompatible with performance + * optimizations 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 i. + * @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(); + } +} diff -r bbe9212c7005 -r 17a5f29f1ae8 jdk/src/share/classes/java/awt/image/DataBufferShort.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/awt/image/DataBufferShort.java Thu Apr 10 18:31:26 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 DataBuffer and stores data internally as shorts. + *

+ * + * 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. + * + */ +public final class DataBufferShort extends DataBuffer +{ + /** The default data bank. */ + short data[]; + + /** All data banks */ + short bankdata[][]; + + /** + * Constructs a short-based DataBuffer with a single bank and the + * specified size. + * + * @param size The size of the DataBuffer. + */ + public DataBufferShort(int size) { + super(STABLE, TYPE_SHORT,size); + data = new short[size]; + bankdata = new short[1][]; + bankdata[0] = data; + } + + /** + * Constructs a short-based DataBuffer with the specified number of + * banks all of which are the specified size. + * + * @param size The size of the banks in the DataBuffer. + * @param numBanks The number of banks in the aDataBuffer. + */ + 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 DataBuffer with a single bank using the + * specified array. + * Only the first size elements should be used by accessors of + * this DataBuffer. dataArray must be large enough to + * hold size elements. + *

+ * Note that {@code DataBuffer} objects created by this constructor + * may be incompatible with performance + * optimizations used by some implementations (such as caching + * an associated image in video memory). + * + * @param dataArray The short array for the DataBuffer. + * @param size The size of the DataBuffer 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 DataBuffer with a single bank using the + * specified array, size, and offset. dataArray must have at least + * offset + size elements. Only elements offset + * through offset + size - 1 + * should be used by accessors of this DataBuffer. + *

+ * Note that {@code DataBuffer} objects created by this constructor + * may be incompatible with performance + * optimizations used by some implementations (such as caching + * an associated image in video memory). + * + * @param dataArray The short array for the DataBuffer. + * @param size The size of the DataBuffer bank. + * @param offset The offset into the dataArray. + */ + 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 DataBuffer with the specified arrays. + * The number of banks will be equal to dataArray.length. + * Only the first size elements of each array should be used by + * accessors of this DataBuffer. + *

+ * Note that {@code DataBuffer} objects created by this constructor + * may be incompatible with performance + * optimizations used by some implementations (such as caching + * an associated image in video memory). + * + * @param dataArray The short arrays for the DataBuffer. + * @param size The size of the banks in the DataBuffer. + */ + public DataBufferShort(short dataArray[][], int size) { + super(UNTRACKABLE, TYPE_SHORT, size, dataArray.length); + bankdata = (short[][]) dataArray.clone(); + data = bankdata[0]; + } + + /** + * Constructs a short-based DataBuffer with the specified arrays, size, + * and offsets. + * The number of banks is equal to dataArray.length. Each array must + * be at least as large as size + the corresponding offset. There must + * be an entry in the offset array for each dataArray entry. For each + * bank, only elements offset through + * offset + size - 1 should be + * used by accessors of this DataBuffer. + *

+ * Note that {@code DataBuffer} objects created by this constructor + * may be incompatible with performance + * optimizations used by some implementations (such as caching + * an associated image in video memory). + * + * @param dataArray The short arrays for the DataBuffer. + * @param size The size of the banks in the DataBuffer. + * @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. + *

+ * Note that calling this method may cause this {@code DataBuffer} + * object to be incompatible with performance + * optimizations 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. + *

+ * Note that calling this method may cause this {@code DataBuffer} + * object to be incompatible with performance + * optimizations 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. + *

+ * Note that calling this method may cause this {@code DataBuffer} + * object to be incompatible with performance + * optimizations 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(); + } +} diff -r bbe9212c7005 -r 17a5f29f1ae8 jdk/src/share/classes/java/awt/image/DataBufferUShort.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/awt/image/DataBufferUShort.java Thu Apr 10 18:31:26 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 DataBuffer and stores data internally as + * shorts. Values stored in the short array(s) of this DataBuffer + * are treated as unsigned values. + *

+ * + * 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. + * + */ +public final class DataBufferUShort extends DataBuffer +{ + /** The default data bank. */ + short data[]; + + /** All data banks */ + short bankdata[][]; + + /** + * Constructs an unsigned-short based DataBuffer with a single bank and the + * specified size. + * + * @param size The size of the DataBuffer. + */ + 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 DataBuffer with the specified number of + * banks, all of which are the specified size. + * + * @param size The size of the banks in the DataBuffer. + * @param numBanks The number of banks in the aDataBuffer. + */ + 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 DataBuffer with a single bank + * using the specified array. + * Only the first size elements should be used by accessors of + * this DataBuffer. dataArray must be large enough to + * hold size elements. + *

+ * Note that {@code DataBuffer} objects created by this constructor + * may be incompatible with performance + * optimizations used by some implementations (such as caching + * an associated image in video memory). + * + * @param dataArray The unsigned-short array for the DataBuffer. + * @param size The size of the DataBuffer 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 DataBuffer with a single bank + * using the specified array, size, and offset. dataArray must have at + * least offset + size elements. Only elements + * offset through offset + size - 1 should + * be used by accessors of this DataBuffer. + *

+ * Note that {@code DataBuffer} objects created by this constructor + * may be incompatible with performance + * optimizations used by some implementations (such as caching + * an associated image in video memory). + * + * @param dataArray The unsigned-short array for the DataBuffer. + * @param size The size of the DataBuffer bank. + * @param offset The offset into the dataArray. + */ + 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 DataBuffer with the specified arrays. + * The number of banks will be equal to dataArray.length. + * Only the first size elements of each array should be used by + * accessors of this DataBuffer. + *

+ * Note that {@code DataBuffer} objects created by this constructor + * may be incompatible with performance + * optimizations used by some implementations (such as caching + * an associated image in video memory). + * + * @param dataArray The unsigned-short arrays for the DataBuffer. + * @param size The size of the banks in the DataBuffer. + */ + 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 DataBuffer with specified arrays, + * size, and offsets. + * The number of banks is equal to dataArray.length. Each array must + * be at least as large as size + the corresponding offset. There must + * be an entry in the offset array for each dataArray entry. For each + * bank, only elements offset through + * offset + size - 1 should be + * used by accessors of this DataBuffer. + *

+ * Note that {@code DataBuffer} objects created by this constructor + * may be incompatible with performance + * optimizations used by some implementations (such as caching + * an associated image in video memory). + * + * @param dataArray The unsigned-short arrays for the DataBuffer. + * @param size The size of the banks in the DataBuffer. + * @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. + *

+ * Note that calling this method may cause this {@code DataBuffer} + * object to be incompatible with performance + * optimizations 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. + *

+ * Note that calling this method may cause this {@code DataBuffer} + * object to be incompatible with performance + * optimizations 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. + *

+ * Note that calling this method may cause this {@code DataBuffer} + * object to be incompatible with performance + * optimizations 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(); + } +} diff -r bbe9212c7005 -r 17a5f29f1ae8 jdk/src/share/classes/java/awt/image/MultiPixelPackedSampleModel.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/awt/image/MultiPixelPackedSampleModel.java Thu Apr 10 18:31:26 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 MultiPixelPackedSampleModel 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. + *

+ * The following code illustrates extracting the bits for pixel + * x, y from DataBuffer data + * and storing the pixel data in data elements of type + * dataType: + *

+ *      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);
+ * 
+ */ + +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 MultiPixelPackedSampleModel 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 dataType is not + * either DataBuffer.TYPE_BYTE, + * DataBuffer.TYPE_USHORT, or + * DataBuffer.TYPE_INT + */ + 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 MultiPixelPackedSampleModel 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 w or + * h is not greater than 0 + * @throws IllegalArgumentException if dataType is not + * either DataBuffer.TYPE_BYTE, + * DataBuffer.TYPE_USHORT, or + * DataBuffer.TYPE_INT + */ + 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 MultiPixelPackedSampleModel with the + * specified width and height. The new + * MultiPixelPackedSampleModel has the + * same storage data type and number of bits per pixel as this + * MultiPixelPackedSampleModel. + * @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 MultiPixelPackedSampleModel. + * @throws IllegalArgumentException if w or + * h is not greater than 0 + */ + public SampleModel createCompatibleSampleModel(int w, int h) { + SampleModel sampleModel = + new MultiPixelPackedSampleModel(dataType, w, h, pixelBitStride); + return sampleModel; + } + + /** + * Creates a DataBuffer that corresponds to this + * MultiPixelPackedSampleModel. The + * DataBuffer object's data type and size + * is consistent with this MultiPixelPackedSampleModel. + * The DataBuffer has a single bank. + * @return a DataBuffer with the same data type and + * size as this MultiPixelPackedSampleModel. + */ + 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 MultiPixelPackedSampleModel, 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, 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 xth 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 + * MultiPixelPackedSampleModel. + */ + 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 pixelBitStride of this + * MultiPixelPackedSampleModel. + */ + public int getPixelBitStride() { + return pixelBitStride; + } + + /** + * Returns the data bit offset in bits. + * @return the dataBitOffset of this + * MultiPixelPackedSampleModel. + */ + public int getDataBitOffset() { + return dataBitOffset; + } + + /** + * Returns the TransferType used to transfer pixels by way of the + * getDataElements and setDataElements + * 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 MultiPixelPackedSampleModel with a + * subset of the bands of this + * MultiPixelPackedSampleModel. Since a + * MultiPixelPackedSampleModel 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 SampleModel with a subset of bands of + * this MultiPixelPackedSampleModel. + * @exception RasterFormatException if the number of bands requested + * is not one. + * @throws IllegalArgumentException if w or + * h 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 int the sample in a specified band for the + * pixel located at (x, y). An + * ArrayIndexOutOfBoundsException 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 DataBuffer 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, y) in the DataBuffer using an + * int for input. + * An ArrayIndexOutOfBoundsException 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 int + * @param data the DataBuffer 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 MultiPixelPackedSampleModel, + * 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, obj + * should be passed in as null, so that the + * Object is created automatically and is the + * correct primitive data type. + *

+ * The following code illustrates transferring data for one pixel from + * DataBuffer db1, whose storage layout is + * described by MultiPixelPackedSampleModel + * mppsm1, to DataBuffer db2, + * whose storage layout is described by + * MultiPixelPackedSampleModel mppsm2. + * The transfer is generally more efficient than using + * getPixel or setPixel. + *

+     *       MultiPixelPackedSampleModel mppsm1, mppsm2;
+     *       DataBufferInt db1, db2;
+     *       mppsm2.setDataElements(x, y, mppsm1.getDataElements(x, y, null,
+     *                              db1), db2);
+     * 
+ * Using getDataElements or 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. + *

+ * If obj is not null, it should be a + * primitive array of type TransferType. Otherwise, a + * ClassCastException is thrown. An + * ArrayIndexOutOfBoundsException is thrown if the + * coordinates are not in bounds, or if obj is not + * null 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 + * null. + * @param data the DataBuffer containing the image data. + * @return an Object containing data for the specified + * pixel. + * @exception ClassCastException if obj is not a + * primitive array of type TransferType or is not null + * @exception ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if obj is not null 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 int array. + * ArrayIndexOutOfBoundsException 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 + * null + * @param data the DataBuffer where image data is stored + * @return an array containing the specified pixel. + * @exception ArrayIndexOutOfBoundsException if the coordinates + * are not in bounds + * @see #setPixel(int, int, int[], DataBuffer) + */ + public int[] getPixel(int x, int y, int iArray[], DataBuffer data) { + if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { + throw new ArrayIndexOutOfBoundsException + ("Coordinate out of bounds!"); + } + int pixels[]; + if (iArray != null) { + pixels = iArray; + } else { + pixels = new int [numBands]; + } + int bitnum = dataBitOffset + x*pixelBitStride; + int element = data.getElem(y*scanlineStride + bitnum/dataElementSize); + int shift = dataElementSize - (bitnum & (dataElementSize-1)) + - pixelBitStride; + pixels[0] = (element >> shift) & bitMask; + return pixels; + } + + /** + * Sets the data for a single pixel in the specified + * DataBuffer from a primitive array of type + * TransferType. For a MultiPixelPackedSampleModel, + * only the first element of the array holds valid data, + * and the type must be the smallest of + * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT + * that can hold a single pixel. + *

+ * The following code illustrates transferring data for one pixel from + * DataBuffer db1, whose storage layout is + * described by MultiPixelPackedSampleModel + * mppsm1, to DataBuffer db2, + * whose storage layout is described by + * MultiPixelPackedSampleModel mppsm2. + * The transfer is generally more efficient than using + * getPixel or setPixel. + *

+     *       MultiPixelPackedSampleModel mppsm1, mppsm2;
+     *       DataBufferInt db1, db2;
+     *       mppsm2.setDataElements(x, y, mppsm1.getDataElements(x, y, null,
+     *                              db1), db2);
+     * 
+ * Using getDataElements or setDataElements to + * transfer between two DataBuffer/SampleModel pairs is + * legitimate if the SampleModel objects have + * the same number of bands, corresponding bands have the same number of + * bits per sample, and the TransferTypes are the same. + *

+ * obj must be a primitive array of type TransferType. + * Otherwise, a ClassCastException is thrown. An + * ArrayIndexOutOfBoundsException is thrown if the + * coordinates are not in bounds, or if obj is not large + * enough to hold the pixel data. + * @param x the X coordinate of the pixel location + * @param y the Y coordinate of the pixel location + * @param obj a primitive array containing pixel data + * @param data the DataBuffer containing the image data + * @see #getDataElements(int, int, Object, DataBuffer) + */ + public void setDataElements(int x, int y, Object obj, DataBuffer data) { + if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { + throw new ArrayIndexOutOfBoundsException + ("Coordinate out of bounds!"); + } + + int type = getTransferType(); + int bitnum = dataBitOffset + x * pixelBitStride; + int index = y * scanlineStride + (bitnum / dataElementSize); + int shift = dataElementSize - (bitnum & (dataElementSize-1)) + - pixelBitStride; + int element = data.getElem(index); + element &= ~(bitMask << shift); + + switch(type) { + + case DataBuffer.TYPE_BYTE: + + byte[] barray = (byte[])obj; + element |= ( ((int)(barray[0])&0xff) & bitMask) << shift; + data.setElem(index, element); + break; + + case DataBuffer.TYPE_USHORT: + + short[] sarray = (short[])obj; + element |= ( ((int)(sarray[0])&0xffff) & bitMask) << shift; + data.setElem(index, element); + break; + + case DataBuffer.TYPE_INT: + + int[] iarray = (int[])obj; + element |= (iarray[0] & bitMask) << shift; + data.setElem(index, element); + break; + } + } + + /** + * Sets a pixel in the DataBuffer using an + * int array for input. + * ArrayIndexOutOfBoundsException is thrown if + * the coordinates are not in bounds. + * @param x the X coordinate of the pixel location + * @param y the Y coordinate of the pixel location + * @param iArray the input pixel in an 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 bitnum = dataBitOffset + x * pixelBitStride; + int index = y * scanlineStride + (bitnum / dataElementSize); + int shift = dataElementSize - (bitnum & (dataElementSize-1)) + - pixelBitStride; + int element = data.getElem(index); + element &= ~(bitMask << shift); + element |= (iArray[0] & bitMask) << shift; + data.setElem(index,element); + } + + public boolean equals(Object o) { + if ((o == null) || !(o instanceof MultiPixelPackedSampleModel)) { + return false; + } + + MultiPixelPackedSampleModel that = (MultiPixelPackedSampleModel)o; + return this.width == that.width && + this.height == that.height && + this.numBands == that.numBands && + this.dataType == that.dataType && + this.pixelBitStride == that.pixelBitStride && + this.bitMask == that.bitMask && + this.pixelsPerDataElement == that.pixelsPerDataElement && + this.dataElementSize == that.dataElementSize && + this.dataBitOffset == that.dataBitOffset && + this.scanlineStride == that.scanlineStride; + } + + // If we implement equals() we must also implement hashCode + public int hashCode() { + int hash = 0; + hash = width; + hash <<= 8; + hash ^= height; + hash <<= 8; + hash ^= numBands; + hash <<= 8; + hash ^= dataType; + hash <<= 8; + hash ^= pixelBitStride; + hash <<= 8; + hash ^= bitMask; + hash <<= 8; + hash ^= pixelsPerDataElement; + hash <<= 8; + hash ^= dataElementSize; + hash <<= 8; + hash ^= dataBitOffset; + hash <<= 8; + hash ^= scanlineStride; + return hash; + } +} diff -r bbe9212c7005 -r 17a5f29f1ae8 jdk/src/share/classes/java/awt/image/Raster.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/awt/image/Raster.java Thu Apr 10 18:31:26 2008 -0700 @@ -0,0 +1,1777 @@ +/* + * Portions Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* **************************************************************** + ****************************************************************** + ****************************************************************** + *** COPYRIGHT (c) Eastman Kodak Company, 1997 + *** As an unpublished work pursuant to Title 17 of the United + *** States Code. All rights reserved. + ****************************************************************** + ****************************************************************** + ******************************************************************/ + + +package java.awt.image; +import java.awt.Rectangle; +import java.awt.Point; + +import sun.awt.image.ByteInterleavedRaster; +import sun.awt.image.ShortInterleavedRaster; +import sun.awt.image.IntegerInterleavedRaster; +import sun.awt.image.ByteBandedRaster; +import sun.awt.image.ShortBandedRaster; +import sun.awt.image.BytePackedRaster; +import sun.awt.image.SunWritableRaster; + +/** + * A class representing a rectangular array of pixels. A Raster + * encapsulates a DataBuffer that stores the sample values and a + * SampleModel that describes how to locate a given sample value in a + * DataBuffer. + *

+ * A Raster defines values for pixels occupying a particular + * rectangular area of the plane, not necessarily including (0, 0). + * The rectangle, known as the Raster's bounding rectangle and + * available by means of the getBounds method, is defined by minX, + * minY, width, and height values. The minX and minY values define + * the coordinate of the upper left corner of the Raster. References + * to pixels outside of the bounding rectangle may result in an + * exception being thrown, or may result in references to unintended + * elements of the Raster's associated DataBuffer. It is the user's + * responsibility to avoid accessing such pixels. + *

+ * A SampleModel describes how samples of a Raster + * are stored in the primitive array elements of a DataBuffer. + * Samples may be stored one per data element, as in a + * PixelInterleavedSampleModel or BandedSampleModel, or packed several to + * an element, as in a SinglePixelPackedSampleModel or + * MultiPixelPackedSampleModel. The SampleModel is also + * controls whether samples are sign extended, allowing unsigned + * data to be stored in signed Java data types such as byte, short, and + * int. + *

+ * Although a Raster may live anywhere in the plane, a SampleModel + * makes use of a simple coordinate system that starts at (0, 0). A + * Raster therefore contains a translation factor that allows pixel + * locations to be mapped between the Raster's coordinate system and + * that of the SampleModel. The translation from the SampleModel + * coordinate system to that of the Raster may be obtained by the + * getSampleModelTranslateX and getSampleModelTranslateY methods. + *

+ * A Raster may share a DataBuffer with another Raster either by + * explicit construction or by the use of the createChild and + * createTranslatedChild methods. Rasters created by these methods + * can return a reference to the Raster they were created from by + * means of the getParent method. For a Raster that was not + * constructed by means of a call to createTranslatedChild or + * createChild, getParent will return null. + *

+ * The createTranslatedChild method returns a new Raster that + * shares all of the data of the current Raster, but occupies a + * bounding rectangle of the same width and height but with a + * different starting point. For example, if the parent Raster + * occupied the region (10, 10) to (100, 100), and the translated + * Raster was defined to start at (50, 50), then pixel (20, 20) of the + * parent and pixel (60, 60) of the child occupy the same location in + * the DataBuffer shared by the two Rasters. In the first case, (-10, + * -10) should be added to a pixel coordinate to obtain the + * corresponding SampleModel coordinate, and in the second case (-50, + * -50) should be added. + *

+ * The translation between a parent and child Raster may be + * determined by subtracting the child's sampleModelTranslateX and + * sampleModelTranslateY values from those of the parent. + *

+ * The createChild method may be used to create a new Raster + * occupying only a subset of its parent's bounding rectangle + * (with the same or a translated coordinate system) or + * with a subset of the bands of its parent. + *

+ * All constructors are protected. The correct way to create a + * Raster is to use one of the static create methods defined in this + * class. These methods create instances of Raster that use the + * standard Interleaved, Banded, and Packed SampleModels and that may + * be processed more efficiently than a Raster created by combining + * an externally generated SampleModel and DataBuffer. + * @see java.awt.image.DataBuffer + * @see java.awt.image.SampleModel + * @see java.awt.image.PixelInterleavedSampleModel + * @see java.awt.image.BandedSampleModel + * @see java.awt.image.SinglePixelPackedSampleModel + * @see java.awt.image.MultiPixelPackedSampleModel + */ +public class Raster { + + /** + * The SampleModel that describes how pixels from this Raster + * are stored in the DataBuffer. + */ + protected SampleModel sampleModel; + + /** The DataBuffer that stores the image data. */ + protected DataBuffer dataBuffer; + + /** The X coordinate of the upper-left pixel of this Raster. */ + protected int minX; + + /** The Y coordinate of the upper-left pixel of this Raster. */ + protected int minY; + + /** The width of this Raster. */ + protected int width; + + /** The height of this Raster. */ + protected int height; + + /** + * The X translation from the coordinate space of the + * Raster's SampleModel to that of the Raster. + */ + protected int sampleModelTranslateX; + + /** + * The Y translation from the coordinate space of the + * Raster's SampleModel to that of the Raster. + */ + protected int sampleModelTranslateY; + + /** The number of bands in the Raster. */ + protected int numBands; + + /** The number of DataBuffer data elements per pixel. */ + protected int numDataElements; + + /** The parent of this Raster, or null. */ + protected Raster parent; + + static private native void initIDs(); + static { + ColorModel.loadLibraries(); + initIDs(); + } + + /** + * Creates a Raster based on a PixelInterleavedSampleModel with the + * specified data type, width, height, and number of bands. + * + *

The upper left corner of the Raster is given by the + * location argument. If location is null, (0, 0) will be used. + * The dataType parameter should be one of the enumerated values + * defined in the DataBuffer class. + * + *

Note that interleaved DataBuffer.TYPE_INT + * Rasters are not supported. To create a 1-band Raster of type + * DataBuffer.TYPE_INT, use + * Raster.createPackedRaster(). + *

The only dataTypes supported currently are TYPE_BYTE + * and TYPE_USHORT. + * @param dataType the data type for storing samples + * @param w the width in pixels of the image data + * @param h the height in pixels of the image data + * @param bands the number of bands + * @param location the upper-left corner of the Raster + * @return a WritableRaster object with the specified data type, + * width, height and number of bands. + * @throws RasterFormatException if w or h + * is less than or equal to zero, or computing either + * location.x + w or + * location.y + h results in integer + * overflow + */ + public static WritableRaster createInterleavedRaster(int dataType, + int w, int h, + int bands, + Point location) { + int[] bandOffsets = new int[bands]; + for (int i = 0; i < bands; i++) { + bandOffsets[i] = i; + } + return createInterleavedRaster(dataType, w, h, w*bands, bands, + bandOffsets, location); + } + + /** + * Creates a Raster based on a PixelInterleavedSampleModel with the + * specified data type, width, height, scanline stride, pixel + * stride, and band offsets. The number of bands is inferred from + * bandOffsets.length. + * + *

The upper left corner of the Raster is given by the + * location argument. If location is null, (0, 0) will be used. + * The dataType parameter should be one of the enumerated values + * defined in the DataBuffer class. + * + *

Note that interleaved DataBuffer.TYPE_INT + * Rasters are not supported. To create a 1-band Raster of type + * DataBuffer.TYPE_INT, use + * Raster.createPackedRaster(). + *

The only dataTypes supported currently are TYPE_BYTE + * and TYPE_USHORT. + * @param dataType the data type for storing samples + * @param w the width in pixels of the image data + * @param h the height in pixels of the image data + * @param scanlineStride the line stride of the image data + * @param pixelStride the pixel stride of the image data + * @param bandOffsets the offsets of all bands + * @param location the upper-left corner of the Raster + * @return a WritableRaster object with the specified data type, + * width, height, scanline stride, pixel stride and band + * offsets. + * @throws RasterFormatException if w or h + * is less than or equal to zero, or computing either + * location.x + w or + * location.y + h results in integer + * overflow + * @throws IllegalArgumentException if dataType is not + * one of the supported data types, which are + * DataBuffer.TYPE_BYTE, or + * DataBuffer.TYPE_USHORT. + */ + public static WritableRaster createInterleavedRaster(int dataType, + int w, int h, + int scanlineStride, + int pixelStride, + int bandOffsets[], + Point location) { + DataBuffer d; + int bands = bandOffsets.length; + + int maxBandOff = bandOffsets[0]; + for (int i=1; i < bands; i++) { + if (bandOffsets[i] > maxBandOff) { + maxBandOff = bandOffsets[i]; + } + } + int size = maxBandOff + scanlineStride*(h-1) + pixelStride*(w-1) + 1; + switch(dataType) { + case DataBuffer.TYPE_BYTE: + d = new DataBufferByte(size); + break; + + case DataBuffer.TYPE_USHORT: + d = new DataBufferUShort(size); + break; + + default: + throw new IllegalArgumentException("Unsupported data type " + + dataType); + } + + return createInterleavedRaster(d, w, h, scanlineStride, + pixelStride, bandOffsets, location); + } + + /** + * Creates a Raster based on a BandedSampleModel with the + * specified data type, width, height, and number of bands. + * + *

The upper left corner of the Raster is given by the + * location argument. If location is null, (0, 0) will be used. + * The dataType parameter should be one of the enumerated values + * defined in the DataBuffer class. + * + *

The only dataTypes supported currently are TYPE_BYTE, TYPE_USHORT, + * and TYPE_INT. + * @param dataType the data type for storing samples + * @param w the width in pixels of the image data + * @param h the height in pixels of the image data + * @param bands the number of bands + * @param location the upper-left corner of the Raster + * @return a WritableRaster object with the specified data type, + * width, height and number of bands. + * @throws RasterFormatException if w or h + * is less than or equal to zero, or computing either + * location.x + w or + * location.y + h results in integer + * overflow + * @throws ArrayIndexOutOfBoundsException if bands + * is less than 1 + */ + public static WritableRaster createBandedRaster(int dataType, + int w, int h, + int bands, + Point location) { + if (bands < 1) { + throw new ArrayIndexOutOfBoundsException("Number of bands ("+ + bands+") must"+ + " be greater than 0"); + } + int[] bankIndices = new int[bands]; + int[] bandOffsets = new int[bands]; + for (int i = 0; i < bands; i++) { + bankIndices[i] = i; + bandOffsets[i] = 0; + } + + return createBandedRaster(dataType, w, h, w, + bankIndices, bandOffsets, + location); + } + + /** + * Creates a Raster based on a BandedSampleModel with the + * specified data type, width, height, scanline stride, bank + * indices and band offsets. The number of bands is inferred from + * bankIndices.length and bandOffsets.length, which must be the + * same. + * + *

The upper left corner of the Raster is given by the + * location argument. The dataType parameter should be one of the + * enumerated values defined in the DataBuffer class. + * + *

The only dataTypes supported currently are TYPE_BYTE, TYPE_USHORT, + * and TYPE_INT. + * @param dataType the data type for storing samples + * @param w the width in pixels of the image data + * @param h the height in pixels of the image data + * @param scanlineStride the line stride of the image data + * @param bankIndices the bank indices for each band + * @param bandOffsets the offsets of all bands + * @param location the upper-left corner of the Raster + * @return a WritableRaster object with the specified data type, + * width, height, scanline stride, bank indices and band + * offsets. + * @throws RasterFormatException if w or h + * is less than or equal to zero, or computing either + * location.x + w or + * location.y + h results in integer + * overflow + * @throws IllegalArgumentException if dataType is not + * one of the supported data types, which are + * DataBuffer.TYPE_BYTE, + * DataBuffer.TYPE_USHORT + * or DataBuffer.TYPE_INT + * @throws ArrayIndexOutOfBoundsException if bankIndices + * or bandOffsets is null + */ + public static WritableRaster createBandedRaster(int dataType, + int w, int h, + int scanlineStride, + int bankIndices[], + int bandOffsets[], + Point location) { + DataBuffer d; + int bands = bandOffsets.length; + + if (bankIndices == null) { + throw new + ArrayIndexOutOfBoundsException("Bank indices array is null"); + } + if (bandOffsets == null) { + throw new + ArrayIndexOutOfBoundsException("Band offsets array is null"); + } + + // Figure out the #banks and the largest band offset + int maxBank = bankIndices[0]; + int maxBandOff = bandOffsets[0]; + for (int i = 1; i < bands; i++) { + if (bankIndices[i] > maxBank) { + maxBank = bankIndices[i]; + } + if (bandOffsets[i] > maxBandOff) { + maxBandOff = bandOffsets[i]; + } + } + int banks = maxBank + 1; + int size = maxBandOff + scanlineStride*(h-1) + (w-1) + 1; + + switch(dataType) { + case DataBuffer.TYPE_BYTE: + d = new DataBufferByte(size, banks); + break; + + case DataBuffer.TYPE_USHORT: + d = new DataBufferUShort(size, banks); + break; + + case DataBuffer.TYPE_INT: + d = new DataBufferInt(size, banks); + break; + + default: + throw new IllegalArgumentException("Unsupported data type " + + dataType); + } + + return createBandedRaster(d, w, h, scanlineStride, + bankIndices, bandOffsets, location); + } + + /** + * Creates a Raster based on a SinglePixelPackedSampleModel with + * the specified data type, width, height, and band masks. + * The number of bands is inferred from bandMasks.length. + * + *

The upper left corner of the Raster is given by the + * location argument. If location is null, (0, 0) will be used. + * The dataType parameter should be one of the enumerated values + * defined in the DataBuffer class. + * + *

The only dataTypes supported currently are TYPE_BYTE, TYPE_USHORT, + * and TYPE_INT. + * @param dataType the data type for storing samples + * @param w the width in pixels of the image data + * @param h the height in pixels of the image data + * @param bandMasks an array containing an entry for each band + * @param location the upper-left corner of the Raster + * @return a WritableRaster object with the specified data type, + * width, height, and band masks. + * @throws RasterFormatException if w or h + * is less than or equal to zero, or computing either + * location.x + w or + * location.y + h results in integer + * overflow + * @throws IllegalArgumentException if dataType is not + * one of the supported data types, which are + * DataBuffer.TYPE_BYTE, + * DataBuffer.TYPE_USHORT + * or DataBuffer.TYPE_INT + */ + public static WritableRaster createPackedRaster(int dataType, + int w, int h, + int bandMasks[], + Point location) { + DataBuffer d; + + switch(dataType) { + case DataBuffer.TYPE_BYTE: + d = new DataBufferByte(w*h); + break; + + case DataBuffer.TYPE_USHORT: + d = new DataBufferUShort(w*h); + break; + + case DataBuffer.TYPE_INT: + d = new DataBufferInt(w*h); + break; + + default: + throw new IllegalArgumentException("Unsupported data type " + + dataType); + } + + return createPackedRaster(d, w, h, w, bandMasks, location); + } + + /** + * Creates a Raster based on a packed SampleModel with the + * specified data type, width, height, number of bands, and bits + * per band. If the number of bands is one, the SampleModel will + * be a MultiPixelPackedSampleModel. + * + *

If the number of bands is more than one, the SampleModel + * will be a SinglePixelPackedSampleModel, with each band having + * bitsPerBand bits. In either case, the requirements on dataType + * and bitsPerBand imposed by the corresponding SampleModel must + * be met. + * + *

The upper left corner of the Raster is given by the + * location argument. If location is null, (0, 0) will be used. + * The dataType parameter should be one of the enumerated values + * defined in the DataBuffer class. + * + *

The only dataTypes supported currently are TYPE_BYTE, TYPE_USHORT, + * and TYPE_INT. + * @param dataType the data type for storing samples + * @param w the width in pixels of the image data + * @param h the height in pixels of the image data + * @param bands the number of bands + * @param bitsPerBand the number of bits per band + * @param location the upper-left corner of the Raster + * @return a WritableRaster object with the specified data type, + * width, height, number of bands, and bits per band. + * @throws RasterFormatException if w or h + * is less than or equal to zero, or computing either + * location.x + w or + * location.y + h results in integer + * overflow + * @throws IllegalArgumentException if the product of + * bitsPerBand and bands is + * greater than the number of bits held by + * dataType + * @throws IllegalArgumentException if bitsPerBand or + * bands is not greater than zero + * @throws IllegalArgumentException if dataType is not + * one of the supported data types, which are + * DataBuffer.TYPE_BYTE, + * DataBuffer.TYPE_USHORT + * or DataBuffer.TYPE_INT + */ + public static WritableRaster createPackedRaster(int dataType, + int w, int h, + int bands, + int bitsPerBand, + Point location) { + DataBuffer d; + + if (bands <= 0) { + throw new IllegalArgumentException("Number of bands ("+bands+ + ") must be greater than 0"); + } + + if (bitsPerBand <= 0) { + throw new IllegalArgumentException("Bits per band ("+bitsPerBand+ + ") must be greater than 0"); + } + + if (bands != 1) { + int[] masks = new int[bands]; + int mask = (1 << bitsPerBand) - 1; + int shift = (bands-1)*bitsPerBand; + + /* Make sure the total mask size will fit in the data type */ + if (shift+bitsPerBand > DataBuffer.getDataTypeSize(dataType)) { + throw new IllegalArgumentException("bitsPerBand("+ + bitsPerBand+") * bands is "+ + " greater than data type "+ + "size."); + } + switch(dataType) { + case DataBuffer.TYPE_BYTE: + case DataBuffer.TYPE_USHORT: + case DataBuffer.TYPE_INT: + break; + default: + throw new IllegalArgumentException("Unsupported data type " + + dataType); + } + + for (int i = 0; i < bands; i++) { + masks[i] = mask << shift; + shift = shift - bitsPerBand; + } + + return createPackedRaster(dataType, w, h, masks, location); + } + else { + double fw = w; + switch(dataType) { + case DataBuffer.TYPE_BYTE: + d = new DataBufferByte((int)(Math.ceil(fw/(8/bitsPerBand)))*h); + break; + + case DataBuffer.TYPE_USHORT: + d = new DataBufferUShort((int)(Math.ceil(fw/(16/bitsPerBand)))*h); + break; + + case DataBuffer.TYPE_INT: + d = new DataBufferInt((int)(Math.ceil(fw/(32/bitsPerBand)))*h); + break; + + default: + throw new IllegalArgumentException("Unsupported data type " + + dataType); + } + + return createPackedRaster(d, w, h, bitsPerBand, location); + } + } + + /** + * Creates a Raster based on a PixelInterleavedSampleModel with the + * specified DataBuffer, width, height, scanline stride, pixel + * stride, and band offsets. The number of bands is inferred from + * bandOffsets.length. The upper left corner of the Raster + * is given by the location argument. If location is null, (0, 0) + * will be used. + *

Note that interleaved DataBuffer.TYPE_INT + * Rasters are not supported. To create a 1-band Raster of type + * DataBuffer.TYPE_INT, use + * Raster.createPackedRaster(). + * @param dataBuffer the DataBuffer that contains the + * image data + * @param w the width in pixels of the image data + * @param h the height in pixels of the image data + * @param scanlineStride the line stride of the image data + * @param pixelStride the pixel stride of the image data + * @param bandOffsets the offsets of all bands + * @param location the upper-left corner of the Raster + * @return a WritableRaster object with the specified + * DataBuffer, width, height, scanline stride, + * pixel stride and band offsets. + * @throws RasterFormatException if w or h + * is less than or equal to zero, or computing either + * location.x + w or + * location.y + h results in integer + * overflow + * @throws IllegalArgumentException if dataType is not + * one of the supported data types, which are + * DataBuffer.TYPE_BYTE, + * DataBuffer.TYPE_USHORT + * @throws RasterFormatException if dataBuffer has more + * than one bank. + * @throws NullPointerException if dataBuffer is null + */ + public static WritableRaster createInterleavedRaster(DataBuffer dataBuffer, + int w, int h, + int scanlineStride, + int pixelStride, + int bandOffsets[], + Point location) { + if (dataBuffer == null) { + throw new NullPointerException("DataBuffer cannot be null"); + } + if (location == null) { + location = new Point(0, 0); + } + int dataType = dataBuffer.getDataType(); + + PixelInterleavedSampleModel csm = + new PixelInterleavedSampleModel(dataType, w, h, + pixelStride, + scanlineStride, + bandOffsets); + switch(dataType) { + case DataBuffer.TYPE_BYTE: + return new ByteInterleavedRaster(csm, dataBuffer, location); + + case DataBuffer.TYPE_USHORT: + return new ShortInterleavedRaster(csm, dataBuffer, location); + + default: + throw new IllegalArgumentException("Unsupported data type " + + dataType); + } + } + + /** + * Creates a Raster based on a BandedSampleModel with the + * specified DataBuffer, width, height, scanline stride, bank + * indices, and band offsets. The number of bands is inferred + * from bankIndices.length and bandOffsets.length, which must be + * the same. The upper left corner of the Raster is given by the + * location argument. If location is null, (0, 0) will be used. + * @param dataBuffer the DataBuffer that contains the + * image data + * @param w the width in pixels of the image data + * @param h the height in pixels of the image data + * @param scanlineStride the line stride of the image data + * @param bankIndices the bank indices for each band + * @param bandOffsets the offsets of all bands + * @param location the upper-left corner of the Raster + * @return a WritableRaster object with the specified + * DataBuffer, width, height, scanline stride, + * bank indices and band offsets. + * @throws RasterFormatException if w or h + * is less than or equal to zero, or computing either + * location.x + w or + * location.y + h results in integer + * overflow + * @throws IllegalArgumentException if dataType is not + * one of the supported data types, which are + * DataBuffer.TYPE_BYTE, + * DataBuffer.TYPE_USHORT + * or DataBuffer.TYPE_INT + * @throws NullPointerException if dataBuffer is null + */ + public static WritableRaster createBandedRaster(DataBuffer dataBuffer, + int w, int h, + int scanlineStride, + int bankIndices[], + int bandOffsets[], + Point location) { + if (dataBuffer == null) { + throw new NullPointerException("DataBuffer cannot be null"); + } + if (location == null) { + location = new Point(0,0); + } + int dataType = dataBuffer.getDataType(); + + int bands = bankIndices.length; + if (bandOffsets.length != bands) { + throw new IllegalArgumentException( + "bankIndices.length != bandOffsets.length"); + } + + BandedSampleModel bsm = + new BandedSampleModel(dataType, w, h, + scanlineStride, + bankIndices, bandOffsets); + + switch(dataType) { + case DataBuffer.TYPE_BYTE: + return new ByteBandedRaster(bsm, dataBuffer, location); + + case DataBuffer.TYPE_USHORT: + return new ShortBandedRaster(bsm, dataBuffer, location); + + case DataBuffer.TYPE_INT: + return new SunWritableRaster(bsm, dataBuffer, location); + + default: + throw new IllegalArgumentException("Unsupported data type " + + dataType); + } + } + + /** + * Creates a Raster based on a SinglePixelPackedSampleModel with + * the specified DataBuffer, width, height, scanline stride, and + * band masks. The number of bands is inferred from bandMasks.length. + * The upper left corner of the Raster is given by + * the location argument. If location is null, (0, 0) will be used. + * @param dataBuffer the DataBuffer that contains the + * image data + * @param w the width in pixels of the image data + * @param h the height in pixels of the image data + * @param scanlineStride the line stride of the image data + * @param bandMasks an array containing an entry for each band + * @param location the upper-left corner of the Raster + * @return a WritableRaster object with the specified + * DataBuffer, width, height, scanline stride, + * and band masks. + * @throws RasterFormatException if w or h + * is less than or equal to zero, or computing either + * location.x + w or + * location.y + h results in integer + * overflow + * @throws IllegalArgumentException if dataType is not + * one of the supported data types, which are + * DataBuffer.TYPE_BYTE, + * DataBuffer.TYPE_USHORT + * or DataBuffer.TYPE_INT + * @throws RasterFormatException if dataBuffer has more + * than one bank. + * @throws NullPointerException if dataBuffer is null + */ + public static WritableRaster createPackedRaster(DataBuffer dataBuffer, + int w, int h, + int scanlineStride, + int bandMasks[], + Point location) { + if (dataBuffer == null) { + throw new NullPointerException("DataBuffer cannot be null"); + } + if (location == null) { + location = new Point(0,0); + } + int dataType = dataBuffer.getDataType(); + + SinglePixelPackedSampleModel sppsm = + new SinglePixelPackedSampleModel(dataType, w, h, scanlineStride, + bandMasks); + + switch(dataType) { + case DataBuffer.TYPE_BYTE: + return new ByteInterleavedRaster(sppsm, dataBuffer, location); + + case DataBuffer.TYPE_USHORT: + return new ShortInterleavedRaster(sppsm, dataBuffer, location); + + case DataBuffer.TYPE_INT: + return new IntegerInterleavedRaster(sppsm, dataBuffer, location); + + default: + throw new IllegalArgumentException("Unsupported data type " + + dataType); + } + } + + /** + * Creates a Raster based on a MultiPixelPackedSampleModel with the + * specified DataBuffer, width, height, and bits per pixel. The upper + * left corner of the Raster is given by the location argument. If + * location is null, (0, 0) will be used. + * @param dataBuffer the DataBuffer that contains the + * image data + * @param w the width in pixels of the image data + * @param h the height in pixels of the image data + * @param bitsPerPixel the number of bits for each pixel + * @param location the upper-left corner of the Raster + * @return a WritableRaster object with the specified + * DataBuffer, width, height, and + * bits per pixel. + * @throws RasterFormatException if w or h + * is less than or equal to zero, or computing either + * location.x + w or + * location.y + h results in integer + * overflow + * @throws IllegalArgumentException if dataType is not + * one of the supported data types, which are + * DataBuffer.TYPE_BYTE, + * DataBuffer.TYPE_USHORT + * or DataBuffer.TYPE_INT + * @throws RasterFormatException if dataBuffer has more + * than one bank. + * @throws NullPointerException if dataBuffer is null + */ + public static WritableRaster createPackedRaster(DataBuffer dataBuffer, + int w, int h, + int bitsPerPixel, + Point location) { + if (dataBuffer == null) { + throw new NullPointerException("DataBuffer cannot be null"); + } + if (location == null) { + location = new Point(0,0); + } + int dataType = dataBuffer.getDataType(); + + if (dataType != DataBuffer.TYPE_BYTE && + dataType != DataBuffer.TYPE_USHORT && + dataType != DataBuffer.TYPE_INT) { + throw new IllegalArgumentException("Unsupported data type " + + dataType); + } + + if (dataBuffer.getNumBanks() != 1) { + throw new + RasterFormatException("DataBuffer for packed Rasters"+ + " must only have 1 bank."); + } + + MultiPixelPackedSampleModel mppsm = + new MultiPixelPackedSampleModel(dataType, w, h, bitsPerPixel); + + if (dataType == DataBuffer.TYPE_BYTE && + (bitsPerPixel == 1 || bitsPerPixel == 2 || bitsPerPixel == 4)) { + return new BytePackedRaster(mppsm, dataBuffer, location); + } else { + return new SunWritableRaster(mppsm, dataBuffer, location); + } + } + + + /** + * Creates a Raster with the specified SampleModel and DataBuffer. + * The upper left corner of the Raster is given by the location argument. + * If location is null, (0, 0) will be used. + * @param sm the specified SampleModel + * @param db the specified DataBuffer + * @param location the upper-left corner of the Raster + * @return a Raster with the specified + * SampleModel, DataBuffer, and + * location. + * @throws RasterFormatException if computing either + * location.x + sm.getWidth() or + * location.y + sm.getHeight() results in integer + * overflow + * @throws RasterFormatException if db has more + * than one bank and sm is a + * PixelInterleavedSampleModel, SinglePixelPackedSampleModel, + * or MultiPixelPackedSampleModel. + * @throws NullPointerException if either SampleModel or DataBuffer is + * null + */ + public static Raster createRaster(SampleModel sm, + DataBuffer db, + Point location) { + if ((sm == null) || (db == null)) { + throw new NullPointerException("SampleModel and DataBuffer cannot be null"); + } + + if (location == null) { + location = new Point(0,0); + } + int dataType = sm.getDataType(); + + if (sm instanceof PixelInterleavedSampleModel) { + switch(dataType) { + case DataBuffer.TYPE_BYTE: + return new ByteInterleavedRaster(sm, db, location); + + case DataBuffer.TYPE_USHORT: + return new ShortInterleavedRaster(sm, db, location); + } + } else if (sm instanceof SinglePixelPackedSampleModel) { + switch(dataType) { + case DataBuffer.TYPE_BYTE: + return new ByteInterleavedRaster(sm, db, location); + + case DataBuffer.TYPE_USHORT: + return new ShortInterleavedRaster(sm, db, location); + + case DataBuffer.TYPE_INT: + return new IntegerInterleavedRaster(sm, db, location); + } + } else if (sm instanceof MultiPixelPackedSampleModel && + dataType == DataBuffer.TYPE_BYTE && + sm.getSampleSize(0) < 8) { + return new BytePackedRaster(sm, db, location); + } + + // we couldn't do anything special - do the generic thing + + return new Raster(sm,db,location); + } + + /** + * Creates a WritableRaster with the specified SampleModel. + * The upper left corner of the Raster is given by the location argument. + * If location is null, (0, 0) will be used. + * @param sm the specified SampleModel + * @param location the upper-left corner of the + * WritableRaster + * @return a WritableRaster with the specified + * SampleModel and location. + * @throws RasterFormatException if computing either + * location.x + sm.getWidth() or + * location.y + sm.getHeight() results in integer + * overflow + */ + public static WritableRaster createWritableRaster(SampleModel sm, + Point location) { + if (location == null) { + location = new Point(0,0); + } + + return createWritableRaster(sm, sm.createDataBuffer(), location); + } + + /** + * Creates a WritableRaster with the specified SampleModel and DataBuffer. + * The upper left corner of the Raster is given by the location argument. + * If location is null, (0, 0) will be used. + * @param sm the specified SampleModel + * @param db the specified DataBuffer + * @param location the upper-left corner of the + * WritableRaster + * @return a WritableRaster with the specified + * SampleModel, DataBuffer, and + * location. + * @throws RasterFormatException if computing either + * location.x + sm.getWidth() or + * location.y + sm.getHeight() results in integer + * overflow + * @throws RasterFormatException if db has more + * than one bank and sm is a + * PixelInterleavedSampleModel, SinglePixelPackedSampleModel, + * or MultiPixelPackedSampleModel. + * @throws NullPointerException if either SampleModel or DataBuffer is null + */ + public static WritableRaster createWritableRaster(SampleModel sm, + DataBuffer db, + Point location) { + if ((sm == null) || (db == null)) { + throw new NullPointerException("SampleModel and DataBuffer cannot be null"); + } + if (location == null) { + location = new Point(0,0); + } + + int dataType = sm.getDataType(); + + if (sm instanceof PixelInterleavedSampleModel) { + switch(dataType) { + case DataBuffer.TYPE_BYTE: + return new ByteInterleavedRaster(sm, db, location); + + case DataBuffer.TYPE_USHORT: + return new ShortInterleavedRaster(sm, db, location); + } + } else if (sm instanceof SinglePixelPackedSampleModel) { + switch(dataType) { + case DataBuffer.TYPE_BYTE: + return new ByteInterleavedRaster(sm, db, location); + + case DataBuffer.TYPE_USHORT: + return new ShortInterleavedRaster(sm, db, location); + + case DataBuffer.TYPE_INT: + return new IntegerInterleavedRaster(sm, db, location); + } + } else if (sm instanceof MultiPixelPackedSampleModel && + dataType == DataBuffer.TYPE_BYTE && + sm.getSampleSize(0) < 8) { + return new BytePackedRaster(sm, db, location); + } + + // we couldn't do anything special - do the generic thing + + return new SunWritableRaster(sm,db,location); + } + + /** + * Constructs a Raster with the given SampleModel. The Raster's + * upper left corner is origin and it is the same size as the + * SampleModel. A DataBuffer large enough to describe the + * Raster is automatically created. + * @param sampleModel The SampleModel that specifies the layout + * @param origin The Point that specified the origin + * @throws RasterFormatException if computing either + * origin.x + sampleModel.getWidth() or + * origin.y + sampleModel.getHeight() results in + * integer overflow + * @throws NullPointerException either sampleModel or + * origin is null + */ + protected Raster(SampleModel sampleModel, + Point origin) { + this(sampleModel, + sampleModel.createDataBuffer(), + new Rectangle(origin.x, + origin.y, + sampleModel.getWidth(), + sampleModel.getHeight()), + origin, + null); + } + + /** + * Constructs a Raster with the given SampleModel and DataBuffer. + * The Raster's upper left corner is origin and it is the same size + * as the SampleModel. The DataBuffer is not initialized and must + * be compatible with SampleModel. + * @param sampleModel The SampleModel that specifies the layout + * @param dataBuffer The DataBuffer that contains the image data + * @param origin The Point that specifies the origin + * @throws RasterFormatException if computing either + * origin.x + sampleModel.getWidth() or + * origin.y + sampleModel.getHeight() results in + * integer overflow + * @throws NullPointerException either sampleModel or + * origin is null + */ + protected Raster(SampleModel sampleModel, + DataBuffer dataBuffer, + Point origin) { + this(sampleModel, + dataBuffer, + new Rectangle(origin.x, + origin.y, + sampleModel.getWidth(), + sampleModel.getHeight()), + origin, + null); + } + + /** + * Constructs a Raster with the given SampleModel, DataBuffer, and + * parent. aRegion specifies the bounding rectangle of the new + * Raster. When translated into the base Raster's coordinate + * system, aRegion must be contained by the base Raster. + * (The base Raster is the Raster's ancestor which has no parent.) + * sampleModelTranslate specifies the sampleModelTranslateX and + * sampleModelTranslateY values of the new Raster. + * + * Note that this constructor should generally be called by other + * constructors or create methods, it should not be used directly. + * @param sampleModel The SampleModel that specifies the layout + * @param dataBuffer The DataBuffer that contains the image data + * @param aRegion The Rectangle that specifies the image area + * @param sampleModelTranslate The Point that specifies the translation + * from SampleModel to Raster coordinates + * @param parent The parent (if any) of this raster + * @throws NullPointerException if any of sampleModel, + * dataBuffer, aRegion or + * sampleModelTranslate is null + * @throws RasterFormatException if aRegion has width + * or height less than or equal to zero, or computing either + * aRegion.x + aRegion.width or + * aRegion.y + aRegion.height results in integer + * overflow + */ + protected Raster(SampleModel sampleModel, + DataBuffer dataBuffer, + Rectangle aRegion, + Point sampleModelTranslate, + Raster parent) { + + if ((sampleModel == null) || (dataBuffer == null) || + (aRegion == null) || (sampleModelTranslate == null)) { + throw new NullPointerException("SampleModel, dataBuffer, aRegion and " + + "sampleModelTranslate cannot be null"); + } + this.sampleModel = sampleModel; + this.dataBuffer = dataBuffer; + minX = aRegion.x; + minY = aRegion.y; + width = aRegion.width; + height = aRegion.height; + if (width <= 0 || height <= 0) { + throw new RasterFormatException("negative or zero " + + ((width <= 0) ? "width" : "height")); + } + if ((minX + width) < minX) { + throw new RasterFormatException( + "overflow condition for X coordinates of Raster"); + } + if ((minY + height) < minY) { + throw new RasterFormatException( + "overflow condition for Y coordinates of Raster"); + } + + sampleModelTranslateX = sampleModelTranslate.x; + sampleModelTranslateY = sampleModelTranslate.y; + + numBands = sampleModel.getNumBands(); + numDataElements = sampleModel.getNumDataElements(); + this.parent = parent; + } + + + /** + * Returns the parent Raster (if any) of this Raster or null. + * @return the parent Raster or null. + */ + public Raster getParent() { + return parent; + } + + /** + * Returns the X translation from the coordinate system of the + * SampleModel to that of the Raster. To convert a pixel's X + * coordinate from the Raster coordinate system to the SampleModel + * coordinate system, this value must be subtracted. + * @return the X translation from the coordinate space of the + * Raster's SampleModel to that of the Raster. + */ + final public int getSampleModelTranslateX() { + return sampleModelTranslateX; + } + + /** + * Returns the Y translation from the coordinate system of the + * SampleModel to that of the Raster. To convert a pixel's Y + * coordinate from the Raster coordinate system to the SampleModel + * coordinate system, this value must be subtracted. + * @return the Y translation from the coordinate space of the + * Raster's SampleModel to that of the Raster. + */ + final public int getSampleModelTranslateY() { + return sampleModelTranslateY; + } + + /** + * Create a compatible WritableRaster the same size as this Raster with + * the same SampleModel and a new initialized DataBuffer. + * @return a compatible WritableRaster with the same sample + * model and a new data buffer. + */ + public WritableRaster createCompatibleWritableRaster() { + return new SunWritableRaster(sampleModel, new Point(0,0)); + } + + /** + * Create a compatible WritableRaster with the specified size, a new + * SampleModel, and a new initialized DataBuffer. + * @param w the specified width of the new WritableRaster + * @param h the specified height of the new WritableRaster + * @return a compatible WritableRaster with the specified + * size and a new sample model and data buffer. + * @exception RasterFormatException if the width or height is less than + * or equal to zero. + */ + public WritableRaster createCompatibleWritableRaster(int w, int h) { + if (w <= 0 || h <=0) { + throw new RasterFormatException("negative " + + ((w <= 0) ? "width" : "height")); + } + + SampleModel sm = sampleModel.createCompatibleSampleModel(w,h); + + return new SunWritableRaster(sm, new Point(0,0)); + } + + /** + * Create a compatible WritableRaster with location (minX, minY) + * and size (width, height) specified by rect, a + * new SampleModel, and a new initialized DataBuffer. + * @param rect a Rectangle that specifies the size and + * location of the WritableRaster + * @return a compatible WritableRaster with the specified + * size and location and a new sample model and data buffer. + * @throws RasterFormatException if rect has width + * or height less than or equal to zero, or computing either + * rect.x + rect.width or + * rect.y + rect.height results in integer + * overflow + * @throws NullPointerException if rect is null + */ + public WritableRaster createCompatibleWritableRaster(Rectangle rect) { + if (rect == null) { + throw new NullPointerException("Rect cannot be null"); + } + return createCompatibleWritableRaster(rect.x, rect.y, + rect.width, rect.height); + } + + /** + * Create a compatible WritableRaster with the specified + * location (minX, minY) and size (width, height), a + * new SampleModel, and a new initialized DataBuffer. + * @param x the X coordinate of the upper-left corner of + * the WritableRaster + * @param y the Y coordinate of the upper-left corner of + * the WritableRaster + * @param w the specified width of the WritableRaster + * @param h the specified height of the WritableRaster + * @return a compatible WritableRaster with the specified + * size and location and a new sample model and data buffer. + * @throws RasterFormatException if w or h + * is less than or equal to zero, or computing either + * x + w or + * y + h results in integer + * overflow + */ + public WritableRaster createCompatibleWritableRaster(int x, int y, + int w, int h) { + WritableRaster ret = createCompatibleWritableRaster(w, h); + return ret.createWritableChild(0,0,w,h,x,y,null); + } + + /** + * Create a Raster with the same size, SampleModel and DataBuffer + * as this one, but with a different location. The new Raster + * will possess a reference to the current Raster, accessible + * through its getParent() method. + * + * @param childMinX the X coordinate of the upper-left + * corner of the new Raster + * @param childMinY the Y coordinate of the upper-left + * corner of the new Raster + * @return a new Raster with the same size, SampleModel, + * and DataBuffer as this Raster, but with the + * specified location. + * @throws RasterFormatException if computing either + * childMinX + this.getWidth() or + * childMinY + this.getHeight() results in integer + * overflow + */ + public Raster createTranslatedChild(int childMinX, int childMinY) { + return createChild(minX,minY,width,height, + childMinX,childMinY,null); + } + + /** + * Returns a new Raster which shares all or part of this Raster's + * DataBuffer. The new Raster will possess a reference to the + * current Raster, accessible through its getParent() method. + * + *

The parentX, parentY, width and height parameters + * form a Rectangle in this Raster's coordinate space, + * indicating the area of pixels to be shared. An error will + * be thrown if this Rectangle is not contained with the bounds + * of the current Raster. + * + *

The new Raster may additionally be translated to a + * different coordinate system for the plane than that used by the current + * Raster. The childMinX and childMinY parameters give the new + * (x, y) coordinate of the upper-left pixel of the returned + * Raster; the coordinate (childMinX, childMinY) in the new Raster + * will map to the same pixel as the coordinate (parentX, parentY) + * in the current Raster. + * + *

The new Raster may be defined to contain only a subset of + * the bands of the current Raster, possibly reordered, by means + * of the bandList parameter. If bandList is null, it is taken to + * include all of the bands of the current Raster in their current + * order. + * + *

To create a new Raster that contains a subregion of the current + * Raster, but shares its coordinate system and bands, + * this method should be called with childMinX equal to parentX, + * childMinY equal to parentY, and bandList equal to null. + * + * @param parentX The X coordinate of the upper-left corner + * in this Raster's coordinates + * @param parentY The Y coordinate of the upper-left corner + * in this Raster's coordinates + * @param width Width of the region starting at (parentX, parentY) + * @param height Height of the region starting at (parentX, parentY). + * @param childMinX The X coordinate of the upper-left corner + * of the returned Raster + * @param childMinY The Y coordinate of the upper-left corner + * of the returned Raster + * @param bandList Array of band indices, or null to use all bands + * @return a new Raster. + * @exception RasterFormatException if the specified subregion is outside + * of the raster bounds. + * @throws RasterFormatException if width or + * height + * is less than or equal to zero, or computing any of + * parentX + width, parentY + height, + * childMinX + width, or + * childMinY + height results in integer + * overflow + */ + public Raster createChild(int parentX, int parentY, + int width, int height, + int childMinX, int childMinY, + int bandList[]) { + if (parentX < this.minX) { + throw new RasterFormatException("parentX lies outside raster"); + } + if (parentY < this.minY) { + throw new RasterFormatException("parentY lies outside raster"); + } + if ((parentX + width < parentX) || + (parentX + width > this.width + this.minX)) { + throw new RasterFormatException("(parentX + width) is outside raster"); + } + if ((parentY + height < parentY) || + (parentY + height > this.height + this.minY)) { + throw new RasterFormatException("(parentY + height) is outside raster"); + } + + SampleModel subSampleModel; + // Note: the SampleModel for the child Raster should have the same + // width and height as that for the parent, since it represents + // the physical layout of the pixel data. The child Raster's width + // and height represent a "virtual" view of the pixel data, so + // they may be different than those of the SampleModel. + if (bandList == null) { + subSampleModel = sampleModel; + } else { + subSampleModel = sampleModel.createSubsetSampleModel(bandList); + } + + int deltaX = childMinX - parentX; + int deltaY = childMinY - parentY; + + return new Raster(subSampleModel, getDataBuffer(), + new Rectangle(childMinX, childMinY, width, height), + new Point(sampleModelTranslateX + deltaX, + sampleModelTranslateY + deltaY), this); + } + + /** + * Returns the bounding Rectangle of this Raster. This function returns + * the same information as getMinX/MinY/Width/Height. + * @return the bounding box of this Raster. + */ + public Rectangle getBounds() { + return new Rectangle(minX, minY, width, height); + } + + /** Returns the minimum valid X coordinate of the Raster. + * @return the minimum x coordinate of this Raster. + */ + final public int getMinX() { + return minX; + } + + /** Returns the minimum valid Y coordinate of the Raster. + * @return the minimum y coordinate of this Raster. + */ + final public int getMinY() { + return minY; + } + + /** Returns the width in pixels of the Raster. + * @return the width of this Raster. + */ + final public int getWidth() { + return width; + } + + /** Returns the height in pixels of the Raster. + * @return the height of this Raster. + */ + final public int getHeight() { + return height; + } + + /** Returns the number of bands (samples per pixel) in this Raster. + * @return the number of bands of this Raster. + */ + final public int getNumBands() { + return numBands; + } + + /** + * Returns the number of data elements needed to transfer one pixel + * via the getDataElements and setDataElements methods. When pixels + * are transferred via these methods, they may be transferred in a + * packed or unpacked format, depending on the implementation of the + * underlying SampleModel. Using these methods, pixels are transferred + * as an array of getNumDataElements() elements of a primitive type given + * by getTransferType(). The TransferType may or may not be the same + * as the storage data type of the DataBuffer. + * @return the number of data elements. + */ + final public int getNumDataElements() { + return sampleModel.getNumDataElements(); + } + + /** + * Returns the TransferType used to transfer pixels via the + * getDataElements and setDataElements methods. When pixels + * are transferred via these methods, they may be transferred in a + * packed or unpacked format, depending on the implementation of the + * underlying SampleModel. Using these methods, pixels are transferred + * as an array of getNumDataElements() elements of a primitive type given + * by getTransferType(). The TransferType may or may not be the same + * as the storage data type of the DataBuffer. The TransferType will + * be one of the types defined in DataBuffer. + * @return this transfer type. + */ + final public int getTransferType() { + return sampleModel.getTransferType(); + } + + /** Returns the DataBuffer associated with this Raster. + * @return the DataBuffer of this Raster. + */ + public DataBuffer getDataBuffer() { + return dataBuffer; + } + + /** Returns the SampleModel that describes the layout of the image data. + * @return the SampleModel of this Raster. + */ + public SampleModel getSampleModel() { + return sampleModel; + } + + /** + * Returns data for a single pixel in a primitive array of type + * TransferType. For image data supported by the Java 2D(tm) API, + * this will be one of DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, + * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, + * or DataBuffer.TYPE_DOUBLE. Data may be returned in a packed format, + * thus increasing efficiency for data transfers. + * An ArrayIndexOutOfBoundsException may be thrown + * if the coordinates are not in bounds. However, explicit bounds + * checking is not guaranteed. + * A ClassCastException will be thrown if the input object is non null + * and references anything other than an array of TransferType. + * @see java.awt.image.SampleModel#getDataElements(int, int, Object, DataBuffer) + * @param x The X coordinate of the pixel location + * @param y The Y coordinate of the pixel location + * @param outData An object reference to an array of type defined by + * getTransferType() and length getNumDataElements(). + * If null, an array of appropriate type and size will be + * allocated + * @return An object reference to an array of type defined by + * getTransferType() with the requested pixel data. + * + * @throws ArrayIndexOutOfBoundsException if the coordinates are not + * in bounds, or if outData is too small to hold the output. + */ + public Object getDataElements(int x, int y, Object outData) { + return sampleModel.getDataElements(x - sampleModelTranslateX, + y - sampleModelTranslateY, + outData, dataBuffer); + } + + /** + * Returns the pixel data for the specified rectangle of pixels in a + * primitive array of type TransferType. + * For image data supported by the Java 2D API, this + * will be one of DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, + * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, + * or DataBuffer.TYPE_DOUBLE. Data may be returned in a packed format, + * thus increasing efficiency for data transfers. + * An ArrayIndexOutOfBoundsException may be thrown + * if the coordinates are not in bounds. However, explicit bounds + * checking is not guaranteed. + * A ClassCastException will be thrown if the input object is non null + * and references anything other than an array of TransferType. + * @see java.awt.image.SampleModel#getDataElements(int, int, int, int, Object, DataBuffer) + * @param x The X coordinate of the upper-left pixel location + * @param y The Y coordinate of the upper-left pixel location + * @param w Width of the pixel rectangle + * @param h Height of the pixel rectangle + * @param outData An object reference to an array of type defined by + * getTransferType() and length w*h*getNumDataElements(). + * If null, an array of appropriate type and size will be + * allocated. + * @return An object reference to an array of type defined by + * getTransferType() with the requested pixel data. + * + * @throws ArrayIndexOutOfBoundsException if the coordinates are not + * in bounds, or if outData is too small to hold the output. + */ + public Object getDataElements(int x, int y, int w, int h, Object outData) { + return sampleModel.getDataElements(x - sampleModelTranslateX, + y - sampleModelTranslateY, + w, h, outData, dataBuffer); + } + + /** + * Returns the samples in an array of int for the specified pixel. + * An ArrayIndexOutOfBoundsException may be thrown + * if the coordinates are not in bounds. However, explicit bounds + * checking is not guaranteed. + * @param x The X coordinate of the pixel location + * @param y The Y coordinate of the pixel location + * @param iArray An optionally preallocated int array + * @return the samples for the specified pixel. + * + * @throws ArrayIndexOutOfBoundsException if the coordinates are not + * in bounds, or if iArray is too small to hold the output. + */ + public int[] getPixel(int x, int y, int iArray[]) { + return sampleModel.getPixel(x - sampleModelTranslateX, + y - sampleModelTranslateY, + iArray, dataBuffer); + } + + /** + * Returns the samples in an array of float for the + * specified pixel. + * An ArrayIndexOutOfBoundsException may be thrown + * if the coordinates are not in bounds. However, explicit bounds + * checking is not guaranteed. + * @param x The X coordinate of the pixel location + * @param y The Y coordinate of the pixel location + * @param fArray An optionally preallocated float array + * @return the samples for the specified pixel. + * + * @throws ArrayIndexOutOfBoundsException if the coordinates are not + * in bounds, or if fArray is too small to hold the output. + */ + public float[] getPixel(int x, int y, float fArray[]) { + return sampleModel.getPixel(x - sampleModelTranslateX, + y - sampleModelTranslateY, + fArray, dataBuffer); + } + + /** + * Returns the samples in an array of double for the specified pixel. + * An ArrayIndexOutOfBoundsException may be thrown + * if the coordinates are not in bounds. However, explicit bounds + * checking is not guaranteed. + * @param x The X coordinate of the pixel location + * @param y The Y coordinate of the pixel location + * @param dArray An optionally preallocated double array + * @return the samples for the specified pixel. + * + * @throws ArrayIndexOutOfBoundsException if the coordinates are not + * in bounds, or if dArray is too small to hold the output. + */ + public double[] getPixel(int x, int y, double dArray[]) { + return sampleModel.getPixel(x - sampleModelTranslateX, + y - sampleModelTranslateY, + dArray, dataBuffer); + } + + /** + * Returns an int array containing all samples for a rectangle of pixels, + * one sample per array element. + * An ArrayIndexOutOfBoundsException may be thrown + * if the coordinates are not in bounds. However, explicit bounds + * checking is not guaranteed. + * @param x The X coordinate of the upper-left pixel location + * @param y The Y coordinate of the upper-left pixel location + * @param w Width of the pixel rectangle + * @param h Height of the pixel rectangle + * @param iArray An optionally pre-allocated int array + * @return the samples for the specified rectangle of pixels. + * + * @throws ArrayIndexOutOfBoundsException if the coordinates are not + * in bounds, or if iArray is too small to hold the output. + */ + public int[] getPixels(int x, int y, int w, int h, int iArray[]) { + return sampleModel.getPixels(x - sampleModelTranslateX, + y - sampleModelTranslateY, w, h, + iArray, dataBuffer); + } + + /** + * Returns a float array containing all samples for a rectangle of pixels, + * one sample per array element. + * An ArrayIndexOutOfBoundsException may be thrown + * if the coordinates are not in bounds. However, explicit bounds + * checking is not guaranteed. + * @param x The X coordinate of the pixel location + * @param y The Y coordinate of the pixel location + * @param w Width of the pixel rectangle + * @param h Height of the pixel rectangle + * @param fArray An optionally pre-allocated float array + * @return the samples for the specified rectangle of pixels. + * + * @throws ArrayIndexOutOfBoundsException if the coordinates are not + * in bounds, or if fArray is too small to hold the output. + */ + public float[] getPixels(int x, int y, int w, int h, + float fArray[]) { + return sampleModel.getPixels(x - sampleModelTranslateX, + y - sampleModelTranslateY, w, h, + fArray, dataBuffer); + } + + /** + * Returns a double array containing all samples for a rectangle of pixels, + * one sample per array element. + * An ArrayIndexOutOfBoundsException may be thrown + * if the coordinates are not in bounds. However, explicit bounds + * checking is not guaranteed. + * @param x The X coordinate of the upper-left pixel location + * @param y The Y coordinate of the upper-left pixel location + * @param w Width of the pixel rectangle + * @param h Height of the pixel rectangle + * @param dArray An optionally pre-allocated double array + * @return the samples for the specified rectangle of pixels. + * + * @throws ArrayIndexOutOfBoundsException if the coordinates are not + * in bounds, or if dArray is too small to hold the output. + */ + public double[] getPixels(int x, int y, int w, int h, + double dArray[]) { + return sampleModel.getPixels(x - sampleModelTranslateX, + y - sampleModelTranslateY, + w, h, dArray, dataBuffer); + } + + + /** + * Returns the sample in a specified band for the pixel located + * at (x,y) as an int. + * An ArrayIndexOutOfBoundsException may be thrown + * if the coordinates are not in bounds. However, explicit bounds + * checking is not guaranteed. + * @param x The X coordinate of the pixel location + * @param y The Y coordinate of the pixel location + * @param b The band to return + * @return the sample in the specified band for the pixel at the + * specified coordinate. + * + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. + */ + public int getSample(int x, int y, int b) { + return sampleModel.getSample(x - sampleModelTranslateX, + y - sampleModelTranslateY, b, + dataBuffer); + } + + /** + * Returns the sample in a specified band + * for the pixel located at (x,y) as a float. + * An ArrayIndexOutOfBoundsException may be thrown + * if the coordinates are not in bounds. However, explicit bounds + * checking is not guaranteed. + * @param x The X coordinate of the pixel location + * @param y The Y coordinate of the pixel location + * @param b The band to return + * @return the sample in the specified band for the pixel at the + * specified coordinate. + * + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. + */ + public float getSampleFloat(int x, int y, int b) { + return sampleModel.getSampleFloat(x - sampleModelTranslateX, + y - sampleModelTranslateY, b, + dataBuffer); + } + + /** + * Returns the sample in a specified band + * for a pixel located at (x,y) as a double. + * An ArrayIndexOutOfBoundsException may be thrown + * if the coordinates are not in bounds. However, explicit bounds + * checking is not guaranteed. + * @param x The X coordinate of the pixel location + * @param y The Y coordinate of the pixel location + * @param b The band to return + * @return the sample in the specified band for the pixel at the + * specified coordinate. + * + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. + */ + public double getSampleDouble(int x, int y, int b) { + return sampleModel.getSampleDouble(x - sampleModelTranslateX, + y - sampleModelTranslateY, + b, dataBuffer); + } + + /** + * Returns the samples for a specified band for the specified rectangle + * of pixels in an int array, one sample per array element. + * An ArrayIndexOutOfBoundsException may be thrown + * if the coordinates are not in bounds. However, explicit bounds + * checking is not guaranteed. + * @param x The X coordinate of the upper-left pixel location + * @param y The Y coordinate of the upper-left pixel location + * @param w Width of the pixel rectangle + * @param h Height of the pixel rectangle + * @param b The band to return + * @param iArray An optionally pre-allocated int array + * @return the samples for the specified band for the specified + * rectangle of pixels. + * + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds, or if iArray is too small to + * hold the output. + */ + public int[] getSamples(int x, int y, int w, int h, int b, + int iArray[]) { + return sampleModel.getSamples(x - sampleModelTranslateX, + y - sampleModelTranslateY, + w, h, b, iArray, + dataBuffer); + } + + /** + * Returns the samples for a specified band for the specified rectangle + * of pixels in a float array, one sample per array element. + * An ArrayIndexOutOfBoundsException may be thrown + * if the coordinates are not in bounds. However, explicit bounds + * checking is not guaranteed. + * @param x The X coordinate of the upper-left pixel location + * @param y The Y coordinate of the upper-left pixel location + * @param w Width of the pixel rectangle + * @param h Height of the pixel rectangle + * @param b The band to return + * @param fArray An optionally pre-allocated float array + * @return the samples for the specified band for the specified + * rectangle of pixels. + * + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds, or if fArray is too small to + * hold the output. + */ + public float[] getSamples(int x, int y, int w, int h, int b, + float fArray[]) { + return sampleModel.getSamples(x - sampleModelTranslateX, + y - sampleModelTranslateY, + w, h, b, fArray, dataBuffer); + } + + /** + * Returns the samples for a specified band for a specified rectangle + * of pixels in a double array, one sample per array element. + * An ArrayIndexOutOfBoundsException may be thrown + * if the coordinates are not in bounds. However, explicit bounds + * checking is not guaranteed. + * @param x The X coordinate of the upper-left pixel location + * @param y The Y coordinate of the upper-left pixel location + * @param w Width of the pixel rectangle + * @param h Height of the pixel rectangle + * @param b The band to return + * @param dArray An optionally pre-allocated double array + * @return the samples for the specified band for the specified + * rectangle of pixels. + * + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds, or if dArray is too small to + * hold the output. + */ + public double[] getSamples(int x, int y, int w, int h, int b, + double dArray[]) { + return sampleModel.getSamples(x - sampleModelTranslateX, + y - sampleModelTranslateY, + w, h, b, dArray, dataBuffer); + } + +} diff -r bbe9212c7005 -r 17a5f29f1ae8 jdk/src/share/classes/java/awt/image/RenderedImage.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/awt/image/RenderedImage.java Thu Apr 10 18:31:26 2008 -0700 @@ -0,0 +1,217 @@ +/* + * Portions Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* **************************************************************** + ****************************************************************** + ****************************************************************** + *** COPYRIGHT (c) Eastman Kodak Company, 1997 + *** As an unpublished work pursuant to Title 17 of the United + *** States Code. All rights reserved. + ****************************************************************** + ****************************************************************** + ******************************************************************/ + +package java.awt.image; +import java.awt.Rectangle; +import java.util.Dictionary; +import java.util.Vector; + +/** + * RenderedImage is a common interface for objects which contain + * or can produce image data in the form of Rasters. The image + * data may be stored/produced as a single tile or a regular array + * of tiles. + */ + +public interface RenderedImage { + + /** + * Returns a vector of RenderedImages that are the immediate sources of + * image data for this RenderedImage. This method returns null if + * the RenderedImage object has no information about its immediate + * sources. It returns an empty Vector if the RenderedImage object has + * no immediate sources. + * @return a Vector of RenderedImage objects. + */ + Vector getSources(); + + /** + * Gets a property from the property set of this image. The set of + * properties and whether it is immutable is determined by the + * implementing class. This method returns + * java.awt.Image.UndefinedProperty if the specified property is + * not defined for this RenderedImage. + * @param name the name of the property + * @return the property indicated by the specified name. + * @see java.awt.Image#UndefinedProperty + */ + Object getProperty(String name); + + /** + * Returns an array of names recognized by + * {@link #getProperty(String) getProperty(String)} + * or null, if no property names are recognized. + * @return a String array containing all of the + * property names that getProperty(String) recognizes; + * or null if no property names are recognized. + */ + String[] getPropertyNames(); + + /** + * Returns the ColorModel associated with this image. All Rasters + * returned from this image will have this as their ColorModel. This + * can return null. + * @return the ColorModel of this image. + */ + ColorModel getColorModel(); + + /** + * Returns the SampleModel associated with this image. All Rasters + * returned from this image will have this as their SampleModel. + * @return the SampleModel of this image. + */ + SampleModel getSampleModel(); + + /** + * Returns the width of the RenderedImage. + * @return the width of this RenderedImage. + */ + int getWidth(); + + /** + * Returns the height of the RenderedImage. + * @return the height of this RenderedImage. + */ + int getHeight(); + + /** + * Returns the minimum X coordinate (inclusive) of the RenderedImage. + * @return the X coordinate of this RenderedImage. + */ + int getMinX(); + + /** + * Returns the minimum Y coordinate (inclusive) of the RenderedImage. + * @return the Y coordinate of this RenderedImage. + */ + int getMinY(); + + /** + * Returns the number of tiles in the X direction. + * @return the number of tiles in the X direction. + */ + int getNumXTiles(); + + /** + * Returns the number of tiles in the Y direction. + * @return the number of tiles in the Y direction. + */ + int getNumYTiles(); + + /** + * Returns the minimum tile index in the X direction. + * @return the minimum tile index in the X direction. + */ + int getMinTileX(); + + /** + * Returns the minimum tile index in the Y direction. + * @return the minimum tile index in the X direction. + */ + int getMinTileY(); + + /** + * Returns the tile width in pixels. All tiles must have the same + * width. + * @return the tile width in pixels. + */ + int getTileWidth(); + + /** + * Returns the tile height in pixels. All tiles must have the same + * height. + * @return the tile height in pixels. + */ + int getTileHeight(); + + /** + * Returns the X offset of the tile grid relative to the origin, + * i.e., the X coordinate of the upper-left pixel of tile (0, 0). + * (Note that tile (0, 0) may not actually exist.) + * @return the X offset of the tile grid relative to the origin. + */ + int getTileGridXOffset(); + + /** + * Returns the Y offset of the tile grid relative to the origin, + * i.e., the Y coordinate of the upper-left pixel of tile (0, 0). + * (Note that tile (0, 0) may not actually exist.) + * @return the Y offset of the tile grid relative to the origin. + */ + int getTileGridYOffset(); + + /** + * Returns tile (tileX, tileY). Note that tileX and tileY are indices + * into the tile array, not pixel locations. The Raster that is returned + * is live and will be updated if the image is changed. + * @param tileX the X index of the requested tile in the tile array + * @param tileY the Y index of the requested tile in the tile array + * @return the tile given the specified indices. + */ + Raster getTile(int tileX, int tileY); + + /** + * Returns the image as one large tile (for tile based + * images this will require fetching the whole image + * and copying the image data over). The Raster returned is + * a copy of the image data and will not be updated if the image + * is changed. + * @return the image as one large tile. + */ + Raster getData(); + + /** + * Computes and returns an arbitrary region of the RenderedImage. + * The Raster returned is a copy of the image data and will not + * be updated if the image is changed. + * @param rect the region of the RenderedImage to be returned. + * @return the region of the RenderedImage + * indicated by the specified Rectangle. + */ + Raster getData(Rectangle rect); + + /** + * Computes an arbitrary rectangular region of the RenderedImage + * and copies it into a caller-supplied WritableRaster. The region + * to be computed is determined from the bounds of the supplied + * WritableRaster. The supplied WritableRaster must have a + * SampleModel that is compatible with this image. If raster is null, + * an appropriate WritableRaster is created. + * @param raster a WritableRaster to hold the returned portion of the + * image, or null. + * @return a reference to the supplied or created WritableRaster. + */ + WritableRaster copyData(WritableRaster raster); +} diff -r bbe9212c7005 -r 17a5f29f1ae8 jdk/src/share/classes/java/awt/image/SampleModel.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/awt/image/SampleModel.java Thu Apr 10 18:31:26 2008 -0700 @@ -0,0 +1,1393 @@ +/* + * Portions Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* **************************************************************** + ****************************************************************** + ****************************************************************** + *** COPYRIGHT (c) Eastman Kodak Company, 1997 + *** As an unpublished work pursuant to Title 17 of the United + *** States Code. All rights reserved. + ****************************************************************** + ****************************************************************** + ******************************************************************/ + +package java.awt.image; + +/** + * This abstract class defines an interface for extracting samples of pixels + * in an image. All image data is expressed as a collection of pixels. + * Each pixel consists of a number of samples. A sample is a datum + * for one band of an image and a band consists of all samples of a + * particular type in an image. For example, a pixel might contain + * three samples representing its red, green and blue components. + * There are three bands in the image containing this pixel. One band + * consists of all the red samples from all pixels in the + * image. The second band consists of all the green samples and + * the remaining band consists of all of the blue samples. The pixel + * can be stored in various formats. For example, all samples from + * a particular band can be stored contiguously or all samples from a + * single pixel can be stored contiguously. + *

+ * Subclasses of SampleModel specify the types of samples they can + * represent (e.g. unsigned 8-bit byte, signed 16-bit short, etc.) + * and may specify how the samples are organized in memory. + * In the Java 2D(tm) API, built-in image processing operators may + * not operate on all possible sample types, but generally will work + * for unsigned integral samples of 16 bits or less. Some operators + * support a wider variety of sample types. + *

+ * A collection of pixels is represented as a Raster, which consists of + * a DataBuffer and a SampleModel. The SampleModel allows access to + * samples in the DataBuffer and may provide low-level information that + * a programmer can use to directly manipulate samples and pixels in the + * DataBuffer. + *

+ * This class is generally a fall back method for dealing with + * images. More efficient code will cast the SampleModel to the + * appropriate subclass and extract the information needed to directly + * manipulate pixels in the DataBuffer. + * + * @see java.awt.image.DataBuffer + * @see java.awt.image.Raster + * @see java.awt.image.ComponentSampleModel + * @see java.awt.image.PixelInterleavedSampleModel + * @see java.awt.image.BandedSampleModel + * @see java.awt.image.MultiPixelPackedSampleModel + * @see java.awt.image.SinglePixelPackedSampleModel + */ + +public abstract class SampleModel +{ + + /** Width in pixels of the region of image data that this SampleModel + * describes. + */ + protected int width; + + /** Height in pixels of the region of image data that this SampleModel + * describes. + */ + protected int height; + + /** Number of bands of the image data that this SampleModel describes. */ + protected int numBands; + + /** Data type of the DataBuffer storing the pixel data. + * @see java.awt.image.DataBuffer + */ + protected int dataType; + + static private native void initIDs(); + static { + ColorModel.loadLibraries(); + initIDs(); + } + + /** + * Constructs a SampleModel with the specified parameters. + * @param dataType The data type of the DataBuffer storing the pixel data. + * @param w The width (in pixels) of the region of image data. + * @param h The height (in pixels) of the region of image data. + * @param numBands The number of bands of the image data. + * @throws IllegalArgumentException if w or h + * is not greater than 0 + * @throws IllegalArgumentException if the product of w + * and h is greater than + * Integer.MAX_VALUE + * @throws IllegalArgumentException if dataType is not + * one of the supported data types + */ + public SampleModel(int dataType, int w, int h, int numBands) + { + float size = (float)w*h; + if (w <= 0 || h <= 0) { + throw new IllegalArgumentException("Width ("+w+") and height ("+ + h+") must be > 0"); + } + if (size >= Integer.MAX_VALUE) { + throw new IllegalArgumentException("Dimensions (width="+w+ + " height="+h+") are too large"); + } + + if (dataType < DataBuffer.TYPE_BYTE || + (dataType > DataBuffer.TYPE_DOUBLE && + dataType != DataBuffer.TYPE_UNDEFINED)) + { + throw new IllegalArgumentException("Unsupported dataType: "+ + dataType); + } + + if (numBands <= 0) { + throw new IllegalArgumentException("Number of bands must be > 0"); + } + + this.dataType = dataType; + this.width = w; + this.height = h; + this.numBands = numBands; + } + + /** Returns the width in pixels. + * @return the width in pixels of the region of image data + * that this SampleModel describes. + */ + final public int getWidth() { + return width; + } + + /** Returns the height in pixels. + * @return the height in pixels of the region of image data + * that this SampleModel describes. + */ + final public int getHeight() { + return height; + } + + /** Returns the total number of bands of image data. + * @return the number of bands of image data that this + * SampleModel describes. + */ + final public int getNumBands() { + return numBands; + } + + /** Returns the number of data elements needed to transfer a pixel + * via the getDataElements and setDataElements methods. When pixels + * are transferred via these methods, they may be transferred in a + * packed or unpacked format, depending on the implementation of the + * SampleModel. Using these methods, pixels are transferred as an + * array of getNumDataElements() elements of a primitive type given + * by getTransferType(). The TransferType may or may not be the same + * as the storage DataType. + * @return the number of data elements. + * @see #getDataElements(int, int, Object, DataBuffer) + * @see #getDataElements(int, int, int, int, Object, DataBuffer) + * @see #setDataElements(int, int, Object, DataBuffer) + * @see #setDataElements(int, int, int, int, Object, DataBuffer) + * @see #getTransferType + */ + public abstract int getNumDataElements(); + + /** Returns the data type of the DataBuffer storing the pixel data. + * @return the data type. + */ + final public int getDataType() { + return dataType; + } + + /** Returns the TransferType used to transfer pixels via the + * getDataElements and setDataElements methods. When pixels + * are transferred via these methods, they may be transferred in a + * packed or unpacked format, depending on the implementation of the + * SampleModel. Using these methods, pixels are transferred as an + * array of getNumDataElements() elements of a primitive type given + * by getTransferType(). The TransferType may or may not be the same + * as the storage DataType. The TransferType will be one of the types + * defined in DataBuffer. + * @return the transfer type. + * @see #getDataElements(int, int, Object, DataBuffer) + * @see #getDataElements(int, int, int, int, Object, DataBuffer) + * @see #setDataElements(int, int, Object, DataBuffer) + * @see #setDataElements(int, int, int, int, Object, DataBuffer) + * @see #getNumDataElements + * @see java.awt.image.DataBuffer + */ + public int getTransferType() { + return dataType; + } + + /** + * Returns the samples for a specified pixel in an int array, + * one sample per array element. + * ArrayIndexOutOfBoundsException may be thrown if the coordinates are + * not in bounds. + * @param x The X coordinate of the pixel location + * @param y The Y coordinate of the pixel location + * @param iArray If non-null, returns the samples in this array + * @param data The DataBuffer containing the image data + * @return the samples for the specified pixel. + * @see #setPixel(int, int, int[], DataBuffer) + * + * @throws NullPointerException if data is null. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if iArray is too small to hold the output. + */ + public int[] getPixel(int x, int y, int iArray[], DataBuffer data) { + + int pixels[]; + + if (iArray != null) + pixels = iArray; + else + pixels = new int[numBands]; + + for (int i=0; i + * The following code illustrates transferring data for one pixel from + * DataBuffer db1, whose storage layout is described by + * SampleModel sm1, to DataBuffer db2, whose + * storage layout is described by SampleModel sm2. + * The transfer will generally be more efficient than using + * getPixel/setPixel. + *

+     *       SampleModel sm1, sm2;
+     *       DataBuffer db1, db2;
+     *       sm2.setDataElements(x, y, sm1.getDataElements(x, y, null, db1), db2);
+     * 
+ * 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. + *

+ * If obj is non-null, it should be a primitive array of type TransferType. + * Otherwise, a ClassCastException is thrown. An + * ArrayIndexOutOfBoundsException may be thrown if the coordinates are + * not in bounds, or if obj is non-null and is not large enough to hold + * the pixel data. + * @param x The X coordinate of the pixel location. + * @param y The Y coordinate of the pixel location. + * @param obj If non-null, a primitive array in which to return + * the pixel data. + * @param data The DataBuffer containing the image data. + * @return the data elements for the specified pixel. + * @see #getNumDataElements + * @see #getTransferType + * @see java.awt.image.DataBuffer + * @see #setDataElements(int, int, Object, DataBuffer) + * + * @throws NullPointerException if data is null. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if obj is too small to hold the output. + */ + public abstract Object getDataElements(int x, int y, + Object obj, DataBuffer data); + + /** + * Returns the pixel data for the specified rectangle of pixels in a + * primitive array of type TransferType. + * For image data supported by the Java 2D API, this + * will be one of DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, + * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, + * or DataBuffer.TYPE_DOUBLE. Data may be returned in a packed format, + * thus increasing efficiency for data transfers. Generally, obj + * should be passed in as null, so that the Object will be created + * automatically and will be of the right primitive data type. + *

+ * The following code illustrates transferring data for a rectangular + * region of pixels from + * DataBuffer db1, whose storage layout is described by + * SampleModel sm1, to DataBuffer db2, whose + * storage layout is described by SampleModel sm2. + * The transfer will generally be more efficient than using + * getPixels/setPixels. + *

+     *       SampleModel sm1, sm2;
+     *       DataBuffer db1, db2;
+     *       sm2.setDataElements(x, y, w, h, sm1.getDataElements(x, y, w,
+     *                           h, null, db1), db2);
+     * 
+ * 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. + *

+ * If obj is non-null, it should be a primitive array of type TransferType. + * Otherwise, a ClassCastException is thrown. An + * ArrayIndexOutOfBoundsException may be thrown if the coordinates are + * not in bounds, or if obj is non-null and is not large enough to hold + * the pixel data. + * @param x The minimum X coordinate of the pixel rectangle. + * @param y The minimum Y coordinate of the pixel rectangle. + * @param w The width of the pixel rectangle. + * @param h The height of the pixel rectangle. + * @param obj If non-null, a primitive array in which to return + * the pixel data. + * @param data The DataBuffer containing the image data. + * @return the data elements for the specified region of pixels. + * @see #getNumDataElements + * @see #getTransferType + * @see #setDataElements(int, int, int, int, Object, DataBuffer) + * @see java.awt.image.DataBuffer + * + * @throws NullPointerException if data is null. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if obj is too small to hold the output. + */ + public Object getDataElements(int x, int y, int w, int h, + Object obj, DataBuffer data) { + + int type = getTransferType(); + int numDataElems = getNumDataElements(); + int cnt = 0; + Object o = null; + + switch(type) { + + case DataBuffer.TYPE_BYTE: + + byte[] btemp; + byte[] bdata; + + if (obj == null) + bdata = new byte[numDataElems*w*h]; + else + bdata = (byte[])obj; + + for (int i=y; i + * The following code illustrates transferring data for one pixel from + * DataBuffer db1, whose storage layout is described by + * SampleModel sm1, to DataBuffer db2, whose + * storage layout is described by SampleModel sm2. + * The transfer will generally be more efficient than using + * getPixel/setPixel. + *

+     *       SampleModel sm1, sm2;
+     *       DataBuffer db1, db2;
+     *       sm2.setDataElements(x, y, sm1.getDataElements(x, y, null, db1),
+     *                           db2);
+     * 
+ * 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. + *

+ * obj must be a primitive array of type TransferType. Otherwise, + * a ClassCastException is thrown. An + * ArrayIndexOutOfBoundsException may be thrown if the coordinates are + * not in bounds, or if obj is not large enough to hold the pixel data. + * @param x The X coordinate of the pixel location. + * @param y The Y coordinate of the pixel location. + * @param obj A primitive array containing pixel data. + * @param data The DataBuffer containing the image data. + * @see #getNumDataElements + * @see #getTransferType + * @see #getDataElements(int, int, Object, DataBuffer) + * @see java.awt.image.DataBuffer + * + * @throws NullPointerException if data is null. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if obj is too small to hold the input. + */ + public abstract void setDataElements(int x, int y, + Object obj, DataBuffer data); + + /** + * Sets the data for a rectangle of pixels in the specified DataBuffer + * from a primitive array of type TransferType. For image data supported + * by the Java 2D API, this will be one of DataBuffer.TYPE_BYTE, + * DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, + * DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE. Data in the array + * may be in a packed format, thus increasing efficiency for data + * transfers. + *

+ * The following code illustrates transferring data for a rectangular + * region of pixels from + * DataBuffer db1, whose storage layout is described by + * SampleModel sm1, to DataBuffer db2, whose + * storage layout is described by SampleModel sm2. + * The transfer will generally be more efficient than using + * getPixels/setPixels. + *

+     *       SampleModel sm1, sm2;
+     *       DataBuffer db1, db2;
+     *       sm2.setDataElements(x, y, w, h, sm1.getDataElements(x, y, w, h,
+     *                           null, db1), db2);
+     * 
+ * 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. + *

+ * obj must be a primitive array of type TransferType. Otherwise, + * a ClassCastException is thrown. An + * ArrayIndexOutOfBoundsException may be thrown if the coordinates are + * not in bounds, or if obj is not large enough to hold the pixel data. + * @param x The minimum X coordinate of the pixel rectangle. + * @param y The minimum Y coordinate of the pixel rectangle. + * @param w The width of the pixel rectangle. + * @param h The height of the pixel rectangle. + * @param obj A primitive array containing pixel data. + * @param data The DataBuffer containing the image data. + * @see #getNumDataElements + * @see #getTransferType + * @see #getDataElements(int, int, int, int, Object, DataBuffer) + * @see java.awt.image.DataBuffer + * + * @throws NullPointerException if data is null. + * @throws ArrayIndexOutOfBoundsException if the coordinates are + * not in bounds, or if obj is too small to hold the input. + */ + public void setDataElements(int x, int y, int w, int h, + Object obj, DataBuffer data) { + + int cnt = 0; + Object o = null; + int type = getTransferType(); + int numDataElems = getNumDataElements(); + + switch(type) { + + case DataBuffer.TYPE_BYTE: + + byte[] barray = (byte[])obj; + byte[] btemp = new byte[numDataElems]; + + for (int i=y; isetSample(int, int, int, DataBuffer) method using + * that int value. + * ArrayIndexOutOfBoundsException may be thrown if the coordinates are + * not in bounds. + * @param x The X coordinate of the pixel location. + * @param y The Y coordinate of the pixel location. + * @param b The band to set. + * @param s The input sample as a float. + * @param data The DataBuffer containing the image data. + * @see #getSample(int, int, int, DataBuffer) + * + * @throws NullPointerException if data is null. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. + */ + public void setSample(int x, int y, int b, + float s , + DataBuffer data) { + int sample = (int)s; + + setSample(x, y, b, sample, data); + } + + /** + * Sets a sample in the specified band for the pixel located at (x,y) + * in the DataBuffer using a double for input. + * The default implementation of this method casts the input + * double sample to an int and then calls the + * setSample(int, int, int, DataBuffer) method using + * that int value. + * ArrayIndexOutOfBoundsException may be thrown if the coordinates are + * not in bounds. + * @param x The X coordinate of the pixel location. + * @param y The Y coordinate of the pixel location. + * @param b The band to set. + * @param s The input sample as a double. + * @param data The DataBuffer containing the image data. + * @see #getSample(int, int, int, DataBuffer) + * + * @throws NullPointerException if data is null. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. + */ + public void setSample(int x, int y, int b, + double s, + DataBuffer data) { + int sample = (int)s; + + setSample(x, y, b, sample, data); + } + + /** + * Sets the samples in the specified band for the specified rectangle + * of pixels from an int array containing one sample per array element. + * ArrayIndexOutOfBoundsException may be thrown if the coordinates are + * not in bounds. + * @param x The X coordinate of the upper left pixel location. + * @param y The Y coordinate of the upper left pixel location. + * @param w The width of the pixel rectangle. + * @param h The height of the pixel rectangle. + * @param b The band to set. + * @param iArray The input samples in an int array. + * @param data The DataBuffer containing the image data. + * @see #getSamples(int, int, int, int, int, int[], DataBuffer) + * + * @throws NullPointerException if iArray or data is null. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds, or if iArray is too small to + * hold the input. + */ + public void setSamples(int x, int y, int w, int h, int b, + int iArray[], DataBuffer data) { + + int Offset=0; + + for (int i=y; i<(y+h); i++) { + for (int j=x; j<(x+w); j++) { + setSample(j, i, b, iArray[Offset++], data); + } + } + } + + /** + * Sets the samples in the specified band for the specified rectangle + * of pixels from a float array containing one sample per array element. + * ArrayIndexOutOfBoundsException may be thrown if the coordinates are + * not in bounds. + * @param x The X coordinate of the upper left pixel location. + * @param y The Y coordinate of the upper left pixel location. + * @param w The width of the pixel rectangle. + * @param h The height of the pixel rectangle. + * @param b The band to set. + * @param fArray The input samples in a float array. + * @param data The DataBuffer containing the image data. + * @see #getSamples(int, int, int, int, int, float[], DataBuffer) + * + * @throws NullPointerException if fArray or data is null. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds, or if fArray is too small to + * hold the input. + */ + public void setSamples(int x, int y, int w, int h, int b, + float fArray[], DataBuffer data) { + int Offset=0; + + for (int i=y; i<(y+h); i++) { + for (int j=x; j<(x+w); j++) { + setSample(j, i, b, fArray[Offset++], data); + } + } + } + + /** + * Sets the samples in the specified band for the specified rectangle + * of pixels from a double array containing one sample per array element. + * ArrayIndexOutOfBoundsException may be thrown if the coordinates are + * not in bounds. + * @param x The X coordinate of the upper left pixel location. + * @param y The Y coordinate of the upper left pixel location. + * @param w The width of the pixel rectangle. + * @param h The height of the pixel rectangle. + * @param b The band to set. + * @param dArray The input samples in a double array. + * @param data The DataBuffer containing the image data. + * @see #getSamples(int, int, int, int, int, double[], DataBuffer) + * + * @throws NullPointerException if dArray or data is null. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds, or if dArray is too small to + * hold the input. + */ + public void setSamples(int x, int y, int w, int h, int b, + double dArray[], DataBuffer data) { + int Offset=0; + + for (int i=y; i<(y+h); i++) { + for (int j=x; j<(x+w); j++) { + setSample(j, i, b, dArray[Offset++], data); + } + } + } + + /** + * Creates a SampleModel which describes data in this SampleModel's + * format, but with a different width and height. + * @param w the width of the image data + * @param h the height of the image data + * @return a SampleModel describing the same image + * data as this SampleModel, but with a + * different size. + */ + public abstract SampleModel createCompatibleSampleModel(int w, int h); + + /** + * Creates a new SampleModel + * with a subset of the bands of this + * SampleModel. + * @param bands the subset of bands of this SampleModel + * @return a SampleModel with a subset of bands of this + * SampleModel. + */ + public abstract SampleModel createSubsetSampleModel(int bands[]); + + /** + * Creates a DataBuffer that corresponds to this SampleModel. + * The DataBuffer's width and height will match this SampleModel's. + * @return a DataBuffer corresponding to this + * SampleModel. + */ + public abstract DataBuffer createDataBuffer(); + + /** Returns the size in bits of samples for all bands. + * @return the size of samples for all bands. + */ + public abstract int[] getSampleSize(); + + /** Returns the size in bits of samples for the specified band. + * @param band the specified band + * @return the size of the samples of the specified band. + */ + public abstract int getSampleSize(int band); + +} diff -r bbe9212c7005 -r 17a5f29f1ae8 jdk/src/share/classes/java/awt/image/SinglePixelPackedSampleModel.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/awt/image/SinglePixelPackedSampleModel.java Thu Apr 10 18:31:26 2008 -0700 @@ -0,0 +1,805 @@ +/* + * Portions Copyright 1997-2001 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* **************************************************************** + ****************************************************************** + ****************************************************************** + *** COPYRIGHT (c) Eastman Kodak Company, 1997 + *** As an unpublished work pursuant to Title 17 of the United + *** States Code. All rights reserved. + ****************************************************************** + ****************************************************************** + ******************************************************************/ + +package java.awt.image; + +import java.util.Arrays; + +/** + * This class represents pixel data packed such that the N samples which make + * up a single pixel are stored in a single data array element, and each data + * data array element holds samples for only one pixel. + * This class supports + * {@link DataBuffer#TYPE_BYTE TYPE_BYTE}, + * {@link DataBuffer#TYPE_USHORT TYPE_USHORT}, + * {@link DataBuffer#TYPE_INT TYPE_INT} data types. + * All data array elements reside + * in the first bank of a DataBuffer. Accessor methods are provided so + * that the image data can be manipulated directly. Scanline stride is the + * number of data array elements between a given sample and the corresponding + * sample in the same column of the next scanline. Bit masks are the masks + * required to extract the samples representing the bands of the pixel. + * Bit offsets are the offsets in bits into the data array + * element of the samples representing the bands of the pixel. + *

+ * The following code illustrates extracting the bits of the sample + * representing band b for pixel x,y + * from DataBuffer data: + *

+ *      int sample = data.getElem(y * scanlineStride + x);
+ *      sample = (sample & bitMasks[b]) >>> bitOffsets[b];
+ * 
+ */ + +public class SinglePixelPackedSampleModel extends SampleModel +{ + /** Bit masks for all bands of the image data. */ + private int bitMasks[]; + + /** Bit Offsets for all bands of the image data. */ + private int bitOffsets[]; + + /** Bit sizes for all the bands of the image data. */ + private int bitSizes[]; + + /** Maximum bit size. */ + private int maxBitSize; + + /** Line stride of the region of image data described by this + * SinglePixelPackedSampleModel. + */ + private int scanlineStride; + + private static native void initIDs(); + static { + ColorModel.loadLibraries(); + initIDs(); + } + + /** + * Constructs a SinglePixelPackedSampleModel with bitMasks.length bands. + * Each sample is stored in a data array element in the position of + * its corresponding bit mask. Each bit mask must be contiguous and + * masks must not overlap. + * @param dataType The data type for storing samples. + * @param w The width (in pixels) of the region of the + * image data described. + * @param h The height (in pixels) of the region of the + * image data described. + * @param bitMasks The bit masks for all bands. + * @throws IllegalArgumentException if dataType is not + * either DataBuffer.TYPE_BYTE, + * DataBuffer.TYPE_USHORT, or + * DataBuffer.TYPE_INT + */ + public SinglePixelPackedSampleModel(int dataType, int w, int h, + int bitMasks[]) { + this(dataType, w, h, w, bitMasks); + if (dataType != DataBuffer.TYPE_BYTE && + dataType != DataBuffer.TYPE_USHORT && + dataType != DataBuffer.TYPE_INT) { + throw new IllegalArgumentException("Unsupported data type "+ + dataType); + } + } + + /** + * Constructs a SinglePixelPackedSampleModel with bitMasks.length bands + * and a scanline stride equal to scanlineStride data array elements. + * Each sample is stored in a data array element in the position of + * its corresponding bit mask. Each bit mask must be contiguous and + * masks must not overlap. + * @param dataType The data type for storing samples. + * @param w The width (in pixels) of the region of + * image data described. + * @param h The height (in pixels) of the region of + * image data described. + * @param scanlineStride The line stride of the image data. + * @param bitMasks The bit masks for all bands. + * @throws IllegalArgumentException if w or + * h is not greater than 0 + * @throws IllegalArgumentException if any mask in + * bitMask is not contiguous + * @throws IllegalArgumentException if dataType is not + * either DataBuffer.TYPE_BYTE, + * DataBuffer.TYPE_USHORT, or + * DataBuffer.TYPE_INT + */ + public SinglePixelPackedSampleModel(int dataType, int w, int h, + int scanlineStride, int bitMasks[]) { + super(dataType, w, h, bitMasks.length); + if (dataType != DataBuffer.TYPE_BYTE && + dataType != DataBuffer.TYPE_USHORT && + dataType != DataBuffer.TYPE_INT) { + throw new IllegalArgumentException("Unsupported data type "+ + dataType); + } + this.dataType = dataType; + this.bitMasks = (int[]) bitMasks.clone(); + this.scanlineStride = scanlineStride; + + this.bitOffsets = new int[numBands]; + this.bitSizes = new int[numBands]; + + this.maxBitSize = 0; + for (int i=0; i>> 1; + bitOffset++; + } + while ((mask & 1) == 1) { + mask = mask >>> 1; + bitSize++; + } + if (mask != 0) { + throw new IllegalArgumentException("Mask "+bitMasks[i]+ + " must be contiguous"); + } + } + bitOffsets[i] = bitOffset; + bitSizes[i] = bitSize; + if (bitSize > maxBitSize) { + maxBitSize = bitSize; + } + } + } + + /** + * Returns the number of data elements needed to transfer one pixel + * via the getDataElements and setDataElements methods. + * For a SinglePixelPackedSampleModel, this is one. + */ + public int getNumDataElements() { + return 1; + } + + /** + * Returns the size of the buffer (in data array elements) + * needed for a data buffer that matches this + * SinglePixelPackedSampleModel. + */ + private long getBufferSize() { + long size = scanlineStride * (height-1) + width; + return size; + } + + /** + * Creates a new SinglePixelPackedSampleModel with the specified + * width and height. The new SinglePixelPackedSampleModel will have the + * same storage data type and bit masks as this + * SinglePixelPackedSampleModel. + * @param w the width of the resulting SampleModel + * @param h the height of the resulting SampleModel + * @return a SinglePixelPackedSampleModel with the + * specified width and height. + * @throws IllegalArgumentException if w or + * h is not greater than 0 + */ + public SampleModel createCompatibleSampleModel(int w, int h) { + SampleModel sampleModel = new SinglePixelPackedSampleModel(dataType, w, h, + bitMasks); + return sampleModel; + } + + /** + * Creates a DataBuffer that corresponds to this + * SinglePixelPackedSampleModel. The DataBuffer's data type and size + * will be consistent with this SinglePixelPackedSampleModel. The + * DataBuffer will have a single bank. + */ + public DataBuffer createDataBuffer() { + DataBuffer dataBuffer = null; + + int size = (int)getBufferSize(); + switch (dataType) { + case DataBuffer.TYPE_BYTE: + dataBuffer = new DataBufferByte(size); + break; + case DataBuffer.TYPE_USHORT: + dataBuffer = new DataBufferUShort(size); + break; + case DataBuffer.TYPE_INT: + dataBuffer = new DataBufferInt(size); + break; + } + return dataBuffer; + } + + /** Returns the number of bits per sample for all bands. */ + public int[] getSampleSize() { + int mask; + int sampleSize[] = new int [numBands]; + for (int i=0; i>> bitOffsets[i]; + while ((mask & 1) != 0) { + sampleSize[i] ++; + mask = mask >>> 1; + } + } + + return sampleSize; + } + + /** Returns the number of bits per sample for the specified band. */ + public int getSampleSize(int band) { + int sampleSize = 0; + int mask = bitMasks[band] >>> bitOffsets[band]; + while ((mask & 1) != 0) { + sampleSize ++; + mask = mask >>> 1; + } + + return sampleSize; + } + + /** Returns the offset (in data array elements) of pixel (x,y). + * The data element containing pixel x,y + * can be retrieved from a DataBuffer data with a + * SinglePixelPackedSampleModel sppsm as: + *
+     *        data.getElem(sppsm.getOffset(x, y));
+     * 
+ * @param x the X coordinate of the specified pixel + * @param y the Y coordinate of the specified pixel + * @return the offset of the specified pixel. + */ + public int getOffset(int x, int y) { + int offset = y * scanlineStride + x; + return offset; + } + + /** Returns the bit offsets into the data array element representing + * a pixel for all bands. + * @return the bit offsets representing a pixel for all bands. + */ + public int [] getBitOffsets() { + return (int[])bitOffsets.clone(); + } + + /** Returns the bit masks for all bands. + * @return the bit masks for all bands. + */ + public int [] getBitMasks() { + return (int[])bitMasks.clone(); + } + + /** Returns the scanline stride of this SinglePixelPackedSampleModel. + * @return the scanline stride of this + * SinglePixelPackedSampleModel. + */ + public int getScanlineStride() { + return scanlineStride; + } + + /** + * This creates a new SinglePixelPackedSampleModel with a subset of the + * bands of this SinglePixelPackedSampleModel. The new + * SinglePixelPackedSampleModel can be used with any DataBuffer that the + * existing SinglePixelPackedSampleModel can be used with. The new + * SinglePixelPackedSampleModel/DataBuffer combination will represent + * an image with a subset of the bands of the original + * SinglePixelPackedSampleModel/DataBuffer combination. + * @exception RasterFormatException if the length of the bands argument is + * greater than the number of bands in + * the sample model. + */ + public SampleModel createSubsetSampleModel(int bands[]) { + if (bands.length > numBands) + throw new RasterFormatException("There are only " + + numBands + + " bands"); + int newBitMasks[] = new int[bands.length]; + for (int i=0; i + * The following code illustrates transferring data for one pixel from + * DataBuffer db1, whose storage layout is described by + * SinglePixelPackedSampleModel sppsm1, to + * DataBuffer db2, whose storage layout is described by + * SinglePixelPackedSampleModel sppsm2. + * The transfer will generally be more efficient than using + * getPixel/setPixel. + *
+     *       SinglePixelPackedSampleModel sppsm1, sppsm2;
+     *       DataBufferInt db1, db2;
+     *       sppsm2.setDataElements(x, y, sppsm1.getDataElements(x, y, null,
+     *                              db1), db2);
+     * 
+ * 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. + *

+ * If obj is non-null, it should be a primitive array of type TransferType. + * Otherwise, a ClassCastException is thrown. An + * ArrayIndexOutOfBoundsException may be thrown if the coordinates are + * not in bounds, or if obj is non-null and is not large enough to hold + * the pixel data. + * @param x The X coordinate of the pixel location. + * @param y The Y coordinate of the pixel location. + * @param obj If non-null, a primitive array in which to return + * the pixel data. + * @param data The DataBuffer containing the image data. + * @return the data for the specified pixel. + * @see #setDataElements(int, int, Object, DataBuffer) + */ + public Object getDataElements(int x, int y, Object obj, DataBuffer data) { + // Bounds check for 'b' will be performed automatically + if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { + throw new ArrayIndexOutOfBoundsException + ("Coordinate out of bounds!"); + } + + int type = getTransferType(); + + switch(type) { + + case DataBuffer.TYPE_BYTE: + + byte[] bdata; + + if (obj == null) + bdata = new byte[1]; + else + bdata = (byte[])obj; + + bdata[0] = (byte)data.getElem(y * scanlineStride + x); + + obj = (Object)bdata; + break; + + case DataBuffer.TYPE_USHORT: + + short[] sdata; + + if (obj == null) + sdata = new short[1]; + else + sdata = (short[])obj; + + sdata[0] = (short)data.getElem(y * scanlineStride + x); + + obj = (Object)sdata; + break; + + case DataBuffer.TYPE_INT: + + int[] idata; + + if (obj == null) + idata = new int[1]; + else + idata = (int[])obj; + + idata[0] = data.getElem(y * scanlineStride + x); + + obj = (Object)idata; + break; + } + + return obj; + } + + /** + * Returns all samples in for the specified pixel in an int array. + * ArrayIndexOutOfBoundsException may be thrown if the coordinates are + * not in bounds. + * @param x The X coordinate of the pixel location. + * @param y The Y coordinate of the pixel location. + * @param iArray If non-null, returns the samples in this array + * @param data The DataBuffer containing the image data. + * @return all samples for the specified pixel. + * @see #setPixel(int, int, int[], DataBuffer) + */ + public int [] getPixel(int x, int y, int iArray[], DataBuffer data) { + if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { + throw new ArrayIndexOutOfBoundsException + ("Coordinate out of bounds!"); + } + int pixels[]; + if (iArray == null) { + pixels = new int [numBands]; + } else { + pixels = iArray; + } + + int value = data.getElem(y * scanlineStride + x); + for (int i=0; i>> bitOffsets[i]; + } + return pixels; + } + + /** + * Returns all samples for the specified rectangle of pixels in + * an int array, one sample per array element. + * ArrayIndexOutOfBoundsException may be thrown if the coordinates are + * not in bounds. + * @param x The X coordinate of the upper left pixel location. + * @param y The Y coordinate of the upper left pixel location. + * @param w The width of the pixel rectangle. + * @param h The height of the pixel rectangle. + * @param iArray If non-null, returns the samples in this array. + * @param data The DataBuffer containing the image data. + * @return all samples for the specified region of pixels. + * @see #setPixels(int, int, int, int, int[], DataBuffer) + */ + public int[] getPixels(int x, int y, int w, int h, + int iArray[], DataBuffer data) { + if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) { + throw new ArrayIndexOutOfBoundsException + ("Coordinate out of bounds!"); + } + int pixels[]; + if (iArray != null) { + pixels = iArray; + } else { + pixels = new int [w*h*numBands]; + } + int lineOffset = y*scanlineStride + x; + int dstOffset = 0; + + for (int i = 0; i < h; i++) { + for (int j = 0; j < w; j++) { + int value = data.getElem(lineOffset+j); + for (int k=0; k < numBands; k++) { + pixels[dstOffset++] = + ((value & bitMasks[k]) >>> bitOffsets[k]); + } + } + lineOffset += scanlineStride; + } + return pixels; + } + + /** + * Returns as int the sample in a specified band for the pixel + * located at (x,y). + * ArrayIndexOutOfBoundsException may be thrown if the coordinates are + * not in bounds. + * @param x The X coordinate of the pixel location. + * @param y The Y coordinate of the pixel location. + * @param b The band to return. + * @param data The DataBuffer containing the image data. + * @return the sample in a specified band for the specified + * pixel. + * @see #setSample(int, int, int, int, DataBuffer) + */ + public int getSample(int x, int y, int b, DataBuffer data) { + // Bounds check for 'b' will be performed automatically + if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { + throw new ArrayIndexOutOfBoundsException + ("Coordinate out of bounds!"); + } + int sample = data.getElem(y * scanlineStride + x); + return ((sample & bitMasks[b]) >>> bitOffsets[b]); + } + + /** + * Returns the samples for a specified band for the specified rectangle + * of pixels in an int array, one sample per array element. + * ArrayIndexOutOfBoundsException may be thrown if the coordinates are + * not in bounds. + * @param x The X coordinate of the upper left pixel location. + * @param y The Y coordinate of the upper left pixel location. + * @param w The width of the pixel rectangle. + * @param h The height of the pixel rectangle. + * @param b The band to return. + * @param iArray If non-null, returns the samples in this array. + * @param data The DataBuffer containing the image data. + * @return the samples for the specified band for the specified + * region of pixels. + * @see #setSamples(int, int, int, int, int, int[], DataBuffer) + */ + public int[] getSamples(int x, int y, int w, int h, int b, + int iArray[], DataBuffer data) { + // Bounds check for 'b' will be performed automatically + if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) { + throw new ArrayIndexOutOfBoundsException + ("Coordinate out of bounds!"); + } + int samples[]; + if (iArray != null) { + samples = iArray; + } else { + samples = new int [w*h]; + } + int lineOffset = y*scanlineStride + x; + int dstOffset = 0; + + for (int i = 0; i < h; i++) { + for (int j = 0; j < w; j++) { + int value = data.getElem(lineOffset+j); + samples[dstOffset++] = + ((value & bitMasks[b]) >>> bitOffsets[b]); + } + lineOffset += scanlineStride; + } + return samples; + } + + /** + * Sets the data for a single pixel in the specified DataBuffer from a + * primitive array of type TransferType. For a + * SinglePixelPackedSampleModel, only the first element of the array + * will hold valid data, and the type of the array must be the same as + * the storage data type of the SinglePixelPackedSampleModel. + *

+ * The following code illustrates transferring data for one pixel from + * DataBuffer db1, whose storage layout is described by + * SinglePixelPackedSampleModel sppsm1, + * to DataBuffer db2, whose storage layout is described by + * SinglePixelPackedSampleModel sppsm2. + * The transfer will generally be more efficient than using + * getPixel/setPixel. + *

+     *       SinglePixelPackedSampleModel sppsm1, sppsm2;
+     *       DataBufferInt db1, db2;
+     *       sppsm2.setDataElements(x, y, sppsm1.getDataElements(x, y, null,
+     *                              db1), db2);
+     * 
+ * 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. + *

+ * obj must be a primitive array of type TransferType. Otherwise, + * a ClassCastException is thrown. An + * ArrayIndexOutOfBoundsException may be thrown if the coordinates are + * not in bounds, or if obj is not large enough to hold the pixel data. + * @param x The X coordinate of the pixel location. + * @param y The Y coordinate of the pixel location. + * @param obj A primitive array containing pixel data. + * @param data The DataBuffer containing the image data. + * @see #getDataElements(int, int, Object, DataBuffer) + */ + public void setDataElements(int x, int y, Object obj, DataBuffer data) { + if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { + throw new ArrayIndexOutOfBoundsException + ("Coordinate out of bounds!"); + } + + int type = getTransferType(); + + switch(type) { + + case DataBuffer.TYPE_BYTE: + + byte[] barray = (byte[])obj; + data.setElem(y*scanlineStride+x, ((int)barray[0])&0xff); + break; + + case DataBuffer.TYPE_USHORT: + + short[] sarray = (short[])obj; + data.setElem(y*scanlineStride+x, ((int)sarray[0])&0xffff); + break; + + case DataBuffer.TYPE_INT: + + int[] iarray = (int[])obj; + data.setElem(y*scanlineStride+x, iarray[0]); + break; + } + } + + /** + * Sets a pixel in the DataBuffer using an int array of samples for input. + * ArrayIndexOutOfBoundsException may be thrown if the coordinates are + * not in bounds. + * @param x The X coordinate of the pixel location. + * @param y The Y coordinate of the pixel location. + * @param iArray The input samples in an int array. + * @param data The DataBuffer containing the image data. + * @see #getPixel(int, int, int[], DataBuffer) + */ + public void setPixel(int x, int y, + int iArray[], + DataBuffer data) { + if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { + throw new ArrayIndexOutOfBoundsException + ("Coordinate out of bounds!"); + } + int lineOffset = y * scanlineStride + x; + int value = data.getElem(lineOffset); + for (int i=0; i < numBands; i++) { + value &= ~bitMasks[i]; + value |= ((iArray[i] << bitOffsets[i]) & bitMasks[i]); + } + data.setElem(lineOffset, value); + } + + /** + * Sets all samples for a rectangle of pixels from an int array containing + * one sample per array element. + * ArrayIndexOutOfBoundsException may be thrown if the coordinates are + * not in bounds. + * @param x The X coordinate of the upper left pixel location. + * @param y The Y coordinate of the upper left pixel location. + * @param w The width of the pixel rectangle. + * @param h The height of the pixel rectangle. + * @param iArray The input samples in an int array. + * @param data The DataBuffer containing the image data. + * @see #getPixels(int, int, int, int, int[], DataBuffer) + */ + public void setPixels(int x, int y, int w, int h, + int iArray[], DataBuffer data) { + if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) { + throw new ArrayIndexOutOfBoundsException + ("Coordinate out of bounds!"); + } + + int lineOffset = y*scanlineStride + x; + int srcOffset = 0; + + for (int i = 0; i < h; i++) { + for (int j = 0; j < w; j++) { + int value = data.getElem(lineOffset+j); + for (int k=0; k < numBands; k++) { + value &= ~bitMasks[k]; + int srcValue = iArray[srcOffset++]; + value |= ((srcValue << bitOffsets[k]) + & bitMasks[k]); + } + data.setElem(lineOffset+j, value); + } + lineOffset += scanlineStride; + } + } + + /** + * Sets a sample in the specified band for the pixel located at (x,y) + * in the DataBuffer using an int for input. + * ArrayIndexOutOfBoundsException may be thrown if the coordinates are + * not in bounds. + * @param x The X coordinate of the pixel location. + * @param y The Y coordinate of the pixel location. + * @param b The band to set. + * @param s The input sample as an int. + * @param data The DataBuffer containing the image data. + * @see #getSample(int, int, int, DataBuffer) + */ + public void setSample(int x, int y, int b, int s, + DataBuffer data) { + // Bounds check for 'b' will be performed automatically + if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { + throw new ArrayIndexOutOfBoundsException + ("Coordinate out of bounds!"); + } + int value = data.getElem(y*scanlineStride + x); + value &= ~bitMasks[b]; + value |= (s << bitOffsets[b]) & bitMasks[b]; + data.setElem(y*scanlineStride + x,value); + } + + /** + * Sets the samples in the specified band for the specified rectangle + * of pixels from an int array containing one sample per array element. + * ArrayIndexOutOfBoundsException may be thrown if the coordinates are + * not in bounds. + * @param x The X coordinate of the upper left pixel location. + * @param y The Y coordinate of the upper left pixel location. + * @param w The width of the pixel rectangle. + * @param h The height of the pixel rectangle. + * @param b The band to set. + * @param iArray The input samples in an int array. + * @param data The DataBuffer containing the image data. + * @see #getSamples(int, int, int, int, int, int[], DataBuffer) + */ + public void setSamples(int x, int y, int w, int h, int b, + int iArray[], DataBuffer data) { + // Bounds check for 'b' will be performed automatically + if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) { + throw new ArrayIndexOutOfBoundsException + ("Coordinate out of bounds!"); + } + int lineOffset = y*scanlineStride + x; + int srcOffset = 0; + + for (int i = 0; i < h; i++) { + for (int j = 0; j < w; j++) { + int value = data.getElem(lineOffset+j); + value &= ~bitMasks[b]; + int sample = iArray[srcOffset++]; + value |= ((int)sample << bitOffsets[b]) & bitMasks[b]; + data.setElem(lineOffset+j,value); + } + lineOffset += scanlineStride; + } + } + + public boolean equals(Object o) { + if ((o == null) || !(o instanceof SinglePixelPackedSampleModel)) { + return false; + } + + SinglePixelPackedSampleModel that = (SinglePixelPackedSampleModel)o; + return this.width == that.width && + this.height == that.height && + this.numBands == that.numBands && + this.dataType == that.dataType && + Arrays.equals(this.bitMasks, that.bitMasks) && + Arrays.equals(this.bitOffsets, that.bitOffsets) && + Arrays.equals(this.bitSizes, that.bitSizes) && + this.maxBitSize == that.maxBitSize && + this.scanlineStride == that.scanlineStride; + } + + // If we implement equals() we must also implement hashCode + public int hashCode() { + int hash = 0; + hash = width; + hash <<= 8; + hash ^= height; + hash <<= 8; + hash ^= numBands; + hash <<= 8; + hash ^= dataType; + hash <<= 8; + for (int i = 0; i < bitMasks.length; i++) { + hash ^= bitMasks[i]; + hash <<= 8; + } + for (int i = 0; i < bitOffsets.length; i++) { + hash ^= bitOffsets[i]; + hash <<= 8; + } + for (int i = 0; i < bitSizes.length; i++) { + hash ^= bitSizes[i]; + hash <<= 8; + } + hash ^= maxBitSize; + hash <<= 8; + hash ^= scanlineStride; + return hash; + } +} diff -r bbe9212c7005 -r 17a5f29f1ae8 jdk/src/share/classes/java/awt/image/WritableRaster.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/awt/image/WritableRaster.java Thu Apr 10 18:31:26 2008 -0700 @@ -0,0 +1,741 @@ +/* + * Portions Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* **************************************************************** + ****************************************************************** + ****************************************************************** + *** COPYRIGHT (c) Eastman Kodak Company, 1997 + *** As an unpublished work pursuant to Title 17 of the United + *** States Code. All rights reserved. + ****************************************************************** + ****************************************************************** + ******************************************************************/ + +package java.awt.image; +import java.awt.Rectangle; +import java.awt.Point; + +/** + * This class extends Raster to provide pixel writing capabilities. + * Refer to the class comment for Raster for descriptions of how + * a Raster stores pixels. + * + *

The constructors of this class are protected. To instantiate + * a WritableRaster, use one of the createWritableRaster factory methods + * in the Raster class. + */ +public class WritableRaster extends Raster { + + /** + * Constructs a WritableRaster with the given SampleModel. The + * WritableRaster's upper left corner is origin and it is the + * same size as the SampleModel. A DataBuffer large enough to + * describe the WritableRaster is automatically created. + * @param sampleModel The SampleModel that specifies the layout. + * @param origin The Point that specifies the origin. + * @throws RasterFormatException if computing either + * origin.x + sampleModel.getWidth() or + * origin.y + sampleModel.getHeight() results + * in integer overflow + */ + protected WritableRaster(SampleModel sampleModel, + Point origin) { + this(sampleModel, + sampleModel.createDataBuffer(), + new Rectangle(origin.x, + origin.y, + sampleModel.getWidth(), + sampleModel.getHeight()), + origin, + null); + } + + /** + * Constructs a WritableRaster with the given SampleModel and DataBuffer. + * The WritableRaster's upper left corner is origin and it is the same + * size as the SampleModel. The DataBuffer is not initialized and must + * be compatible with SampleModel. + * @param sampleModel The SampleModel that specifies the layout. + * @param dataBuffer The DataBuffer that contains the image data. + * @param origin The Point that specifies the origin. + * @throws RasterFormatException if computing either + * origin.x + sampleModel.getWidth() or + * origin.y + sampleModel.getHeight() results + * in integer overflow + */ + protected WritableRaster(SampleModel sampleModel, + DataBuffer dataBuffer, + Point origin) { + this(sampleModel, + dataBuffer, + new Rectangle(origin.x, + origin.y, + sampleModel.getWidth(), + sampleModel.getHeight()), + origin, + null); + } + + /** + * Constructs a WritableRaster with the given SampleModel, DataBuffer, + * and parent. aRegion specifies the bounding rectangle of the new + * Raster. When translated into the base Raster's coordinate + * system, aRegion must be contained by the base Raster. + * (The base Raster is the Raster's ancestor which has no parent.) + * sampleModelTranslate specifies the sampleModelTranslateX and + * sampleModelTranslateY values of the new Raster. + * + * Note that this constructor should generally be called by other + * constructors or create methods, it should not be used directly. + * @param sampleModel The SampleModel that specifies the layout. + * @param dataBuffer The DataBuffer that contains the image data. + * @param aRegion The Rectangle that specifies the image area. + * @param sampleModelTranslate The Point that specifies the translation + * from SampleModel to Raster coordinates. + * @param parent The parent (if any) of this raster. + * @throws RasterFormatException if aRegion has width + * or height less than or equal to zero, or computing either + * aRegion.x + aRegion.width or + * aRegion.y + aRegion.height results in integer + * overflow + */ + protected WritableRaster(SampleModel sampleModel, + DataBuffer dataBuffer, + Rectangle aRegion, + Point sampleModelTranslate, + WritableRaster parent){ + super(sampleModel,dataBuffer,aRegion,sampleModelTranslate,parent); + } + + /** Returns the parent WritableRaster (if any) of this WritableRaster, + * or else null. + * @return the parent of this WritableRaster, or + * null. + */ + public WritableRaster getWritableParent() { + return (WritableRaster)parent; + } + + /** + * Create a WritableRaster with the same size, SampleModel and DataBuffer + * as this one, but with a different location. The new WritableRaster + * will possess a reference to the current WritableRaster, accessible + * through its getParent() and getWritableParent() methods. + * + * @param childMinX X coord of the upper left corner of the new Raster. + * @param childMinY Y coord of the upper left corner of the new Raster. + * @return a WritableRaster the same as this one except + * for the specified location. + * @throws RasterFormatException if computing either + * childMinX + this.getWidth() or + * childMinY + this.getHeight() results in integer + * overflow + */ + public WritableRaster createWritableTranslatedChild(int childMinX, + int childMinY) { + return createWritableChild(minX,minY,width,height, + childMinX,childMinY,null); + } + + /** + * Returns a new WritableRaster which shares all or part of this + * WritableRaster's DataBuffer. The new WritableRaster will + * possess a reference to the current WritableRaster, accessible + * through its getParent() and getWritableParent() methods. + * + *

The parentX, parentY, width and height parameters form a + * Rectangle in this WritableRaster's coordinate space, indicating + * the area of pixels to be shared. An error will be thrown if + * this Rectangle is not contained with the bounds of the current + * WritableRaster. + * + *

The new WritableRaster may additionally be translated to a + * different coordinate system for the plane than that used by the current + * WritableRaster. The childMinX and childMinY parameters give + * the new (x, y) coordinate of the upper-left pixel of the + * returned WritableRaster; the coordinate (childMinX, childMinY) + * in the new WritableRaster will map to the same pixel as the + * coordinate (parentX, parentY) in the current WritableRaster. + * + *

The new WritableRaster may be defined to contain only a + * subset of the bands of the current WritableRaster, possibly + * reordered, by means of the bandList parameter. If bandList is + * null, it is taken to include all of the bands of the current + * WritableRaster in their current order. + * + *

To create a new WritableRaster that contains a subregion of + * the current WritableRaster, but shares its coordinate system + * and bands, this method should be called with childMinX equal to + * parentX, childMinY equal to parentY, and bandList equal to + * null. + * + * @param parentX X coordinate of the upper left corner in this + * WritableRaster's coordinates. + * @param parentY Y coordinate of the upper left corner in this + * WritableRaster's coordinates. + * @param w Width of the region starting at (parentX, parentY). + * @param h Height of the region starting at (parentX, parentY). + * @param childMinX X coordinate of the upper left corner of + * the returned WritableRaster. + * @param childMinY Y coordinate of the upper left corner of + * the returned WritableRaster. + * @param bandList Array of band indices, or null to use all bands. + * @return a WritableRaster sharing all or part of the + * DataBuffer of this WritableRaster. + * @exception RasterFormatException if the subregion is outside of the + * raster bounds. + * @throws RasterFormatException if w or + * h + * is less than or equal to zero, or computing any of + * parentX + w, parentY + h, + * childMinX + w, or + * childMinY + h results in integer + * overflow + */ + public WritableRaster createWritableChild(int parentX, int parentY, + int w, int h, + int childMinX, int childMinY, + int bandList[]) { + if (parentX < this.minX) { + throw new RasterFormatException("parentX lies outside raster"); + } + if (parentY < this.minY) { + throw new RasterFormatException("parentY lies outside raster"); + } + if ((parentX+w < parentX) || (parentX+w > this.width + this.minX)) { + throw new RasterFormatException("(parentX + width) is outside raster"); + } + if ((parentY+h < parentY) || (parentY+h > this.height + this.minY)) { + throw new RasterFormatException("(parentY + height) is outside raster"); + } + + SampleModel sm; + // Note: the SampleModel for the child Raster should have the same + // width and height as that for the parent, since it represents + // the physical layout of the pixel data. The child Raster's width + // and height represent a "virtual" view of the pixel data, so + // they may be different than those of the SampleModel. + if (bandList != null) { + sm = sampleModel.createSubsetSampleModel(bandList); + } + else { + sm = sampleModel; + } + + int deltaX = childMinX - parentX; + int deltaY = childMinY - parentY; + + return new WritableRaster(sm, + getDataBuffer(), + new Rectangle(childMinX,childMinY, + w, h), + new Point(sampleModelTranslateX+deltaX, + sampleModelTranslateY+deltaY), + this); + } + + /** + * Sets the data for a single pixel from a + * primitive array of type TransferType. For image data supported by + * the Java 2D(tm) API, this will be one of DataBuffer.TYPE_BYTE, + * DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, + * DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE. Data in the array + * may be in a packed format, thus increasing efficiency for data + * transfers. + * An ArrayIndexOutOfBoundsException may be thrown if the coordinates are + * not in bounds, or if inData is not large enough to hold the pixel data. + * However, explicit bounds checking is not guaranteed. + * A ClassCastException will be thrown if the input object is not null + * and references anything other than an array of TransferType. + * @see java.awt.image.SampleModel#setDataElements(int, int, Object, DataBuffer) + * @param x The X coordinate of the pixel location. + * @param y The Y coordinate of the pixel location. + * @param inData An object reference to an array of type defined by + * getTransferType() and length getNumDataElements() + * containing the pixel data to place at x,y. + * + * @throws ArrayIndexOutOfBoundsException if the coordinates are not + * in bounds, or if inData is too small to hold the input. + */ + public void setDataElements(int x, int y, Object inData) { + sampleModel.setDataElements(x-sampleModelTranslateX, + y-sampleModelTranslateY, + inData, dataBuffer); + } + + /** + * Sets the data for a rectangle of pixels from an input Raster. + * The input Raster must be compatible with this WritableRaster + * in that they must have the same number of bands, corresponding bands + * must have the same number of bits per sample, the TransferTypes + * and NumDataElements must be the same, and the packing used by + * the getDataElements/setDataElements must be identical. + * An ArrayIndexOutOfBoundsException may be thrown if the coordinates are + * not in bounds. + * However, explicit bounds checking is not guaranteed. + * @param x The X coordinate of the pixel location. + * @param y The Y coordinate of the pixel location. + * @param inRaster Raster containing data to place at x,y. + * + * @throws NullPointerException if inRaster is null. + * @throws ArrayIndexOutOfBoundsException if the coordinates are not + * in bounds. + */ + public void setDataElements(int x, int y, Raster inRaster) { + int dstOffX = x+inRaster.getMinX(); + int dstOffY = y+inRaster.getMinY(); + int width = inRaster.getWidth(); + int height = inRaster.getHeight(); + if ((dstOffX < this.minX) || (dstOffY < this.minY) || + (dstOffX + width > this.minX + this.width) || + (dstOffY + height > this.minY + this.height)) { + throw new ArrayIndexOutOfBoundsException + ("Coordinate out of bounds!"); + } + + int srcOffX = inRaster.getMinX(); + int srcOffY = inRaster.getMinY(); + Object tdata = null; + + for (int startY=0; startY < height; startY++) { + tdata = inRaster.getDataElements(srcOffX, srcOffY+startY, + width, 1, tdata); + setDataElements(dstOffX, dstOffY+startY, + width, 1, tdata); + } + } + + /** + * Sets the data for a rectangle of pixels from a + * primitive array of type TransferType. For image data supported by + * the Java 2D API, this will be one of DataBuffer.TYPE_BYTE, + * DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, + * DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE. Data in the array + * may be in a packed format, thus increasing efficiency for data + * transfers. + * An ArrayIndexOutOfBoundsException may be thrown if the coordinates are + * not in bounds, or if inData is not large enough to hold the pixel data. + * However, explicit bounds checking is not guaranteed. + * A ClassCastException will be thrown if the input object is not null + * and references anything other than an array of TransferType. + * @see java.awt.image.SampleModel#setDataElements(int, int, int, int, Object, DataBuffer) + * @param x The X coordinate of the upper left pixel location. + * @param y The Y coordinate of the upper left pixel location. + * @param w Width of the pixel rectangle. + * @param h Height of the pixel rectangle. + * @param inData An object reference to an array of type defined by + * getTransferType() and length w*h*getNumDataElements() + * containing the pixel data to place between x,y and + * x+w-1, y+h-1. + * + * @throws NullPointerException if inData is null. + * @throws ArrayIndexOutOfBoundsException if the coordinates are not + * in bounds, or if inData is too small to hold the input. + */ + public void setDataElements(int x, int y, int w, int h, Object inData) { + sampleModel.setDataElements(x-sampleModelTranslateX, + y-sampleModelTranslateY, + w,h,inData,dataBuffer); + } + + /** + * Copies pixels from Raster srcRaster to this WritableRaster. Each pixel + * in srcRaster is copied to the same x,y address in this raster, unless + * the address falls outside the bounds of this raster. srcRaster + * must have the same number of bands as this WritableRaster. The + * copy is a simple copy of source samples to the corresponding destination + * samples. + *

+ * If all samples of both source and destination Rasters are of + * integral type and less than or equal to 32 bits in size, then calling + * this method is equivalent to executing the following code for all + * x,y addresses valid in both Rasters. + *

+     *       Raster srcRaster;
+     *       WritableRaster dstRaster;
+     *       for (int b = 0; b < srcRaster.getNumBands(); b++) {
+     *           dstRaster.setSample(x, y, b, srcRaster.getSample(x, y, b));
+     *       }
+     * 
+ * Thus, when copying an integral type source to an integral type + * destination, if the source sample size is greater than the destination + * sample size for a particular band, the high order bits of the source + * sample are truncated. If the source sample size is less than the + * destination size for a particular band, the high order bits of the + * destination are zero-extended or sign-extended depending on whether + * srcRaster's SampleModel treats the sample as a signed or unsigned + * quantity. + *

+ * When copying a float or double source to an integral type destination, + * each source sample is cast to the destination type. When copying an + * integral type source to a float or double destination, the source + * is first converted to a 32-bit int (if necessary), using the above + * rules for integral types, and then the int is cast to float or + * double. + *

+ * @param srcRaster The Raster from which to copy pixels. + * + * @throws NullPointerException if srcRaster is null. + */ + public void setRect(Raster srcRaster) { + setRect(0,0,srcRaster); + } + + /** + * Copies pixels from Raster srcRaster to this WritableRaster. + * For each (x, y) address in srcRaster, the corresponding pixel + * is copied to address (x+dx, y+dy) in this WritableRaster, + * unless (x+dx, y+dy) falls outside the bounds of this raster. + * srcRaster must have the same number of bands as this WritableRaster. + * The copy is a simple copy of source samples to the corresponding + * destination samples. For details, see + * {@link WritableRaster#setRect(Raster)}. + * + * @param dx The X translation factor from src space to dst space + * of the copy. + * @param dy The Y translation factor from src space to dst space + * of the copy. + * @param srcRaster The Raster from which to copy pixels. + * + * @throws NullPointerException if srcRaster is null. + */ + public void setRect(int dx, int dy, Raster srcRaster) { + int width = srcRaster.getWidth(); + int height = srcRaster.getHeight(); + int srcOffX = srcRaster.getMinX(); + int srcOffY = srcRaster.getMinY(); + int dstOffX = dx+srcOffX; + int dstOffY = dy+srcOffY; + + // Clip to this raster + if (dstOffX < this.minX) { + int skipX = this.minX - dstOffX; + width -= skipX; + srcOffX += skipX; + dstOffX = this.minX; + } + if (dstOffY < this.minY) { + int skipY = this.minY - dstOffY; + height -= skipY; + srcOffY += skipY; + dstOffY = this.minY; + } + if (dstOffX+width > this.minX+this.width) { + width = this.minX + this.width - dstOffX; + } + if (dstOffY+height > this.minY+this.height) { + height = this.minY + this.height - dstOffY; + } + + if (width <= 0 || height <= 0) { + return; + } + + switch (srcRaster.getSampleModel().getDataType()) { + case DataBuffer.TYPE_BYTE: + case DataBuffer.TYPE_SHORT: + case DataBuffer.TYPE_USHORT: + case DataBuffer.TYPE_INT: + int[] iData = null; + for (int startY=0; startY < height; startY++) { + // Grab one scanline at a time + iData = + srcRaster.getPixels(srcOffX, srcOffY+startY, width, 1, + iData); + setPixels(dstOffX, dstOffY+startY, width, 1, iData); + } + break; + + case DataBuffer.TYPE_FLOAT: + float[] fData = null; + for (int startY=0; startY < height; startY++) { + fData = + srcRaster.getPixels(srcOffX, srcOffY+startY, width, 1, + fData); + setPixels(dstOffX, dstOffY+startY, width, 1, fData); + } + break; + + case DataBuffer.TYPE_DOUBLE: + double[] dData = null; + for (int startY=0; startY < height; startY++) { + // Grab one scanline at a time + dData = + srcRaster.getPixels(srcOffX, srcOffY+startY, width, 1, + dData); + setPixels(dstOffX, dstOffY+startY, width, 1, dData); + } + break; + } + } + + /** + * Sets a pixel in the DataBuffer using an int array of samples for input. + * An ArrayIndexOutOfBoundsException may be thrown if the coordinates are + * not in bounds. + * However, explicit bounds checking is not guaranteed. + * @param x The X coordinate of the pixel location. + * @param y The Y coordinate of the pixel location. + * @param iArray The input samples in a int array. + * + * @throws NullPointerException if iArray is null. + * @throws ArrayIndexOutOfBoundsException if the coordinates are not + * in bounds, or if iArray is too small to hold the input. + */ + public void setPixel(int x, int y, int iArray[]) { + sampleModel.setPixel(x-sampleModelTranslateX,y-sampleModelTranslateY, + iArray,dataBuffer); + } + + /** + * Sets a pixel in the DataBuffer using a float array of samples for input. + * An ArrayIndexOutOfBoundsException may be thrown if the coordinates are + * not in bounds. + * However, explicit bounds checking is not guaranteed. + * @param x The X coordinate of the pixel location. + * @param y The Y coordinate of the pixel location. + * @param fArray The input samples in a float array. + * + * @throws NullPointerException if fArray is null. + * @throws ArrayIndexOutOfBoundsException if the coordinates are not + * in bounds, or if fArray is too small to hold the input. + */ + public void setPixel(int x, int y, float fArray[]) { + sampleModel.setPixel(x-sampleModelTranslateX,y-sampleModelTranslateY, + fArray,dataBuffer); + } + + /** + * Sets a pixel in the DataBuffer using a double array of samples for input. + * An ArrayIndexOutOfBoundsException may be thrown if the coordinates are + * not in bounds. + * However, explicit bounds checking is not guaranteed. + * @param x The X coordinate of the pixel location. + * @param y The Y coordinate of the pixel location. + * @param dArray The input samples in a double array. + * + * @throws NullPointerException if dArray is null. + * @throws ArrayIndexOutOfBoundsException if the coordinates are not + * in bounds, or if dArray is too small to hold the input. + */ + public void setPixel(int x, int y, double dArray[]) { + sampleModel.setPixel(x-sampleModelTranslateX,y-sampleModelTranslateY, + dArray,dataBuffer); + } + + /** + * Sets all samples for a rectangle of pixels from an int array containing + * one sample per array element. + * An ArrayIndexOutOfBoundsException may be thrown if the coordinates are + * not in bounds. + * However, explicit bounds checking is not guaranteed. + * @param x The X coordinate of the upper left pixel location. + * @param y The Y coordinate of the upper left pixel location. + * @param w Width of the pixel rectangle. + * @param h Height of the pixel rectangle. + * @param iArray The input int pixel array. + * + * @throws NullPointerException if iArray is null. + * @throws ArrayIndexOutOfBoundsException if the coordinates are not + * in bounds, or if iArray is too small to hold the input. + */ + public void setPixels(int x, int y, int w, int h, int iArray[]) { + sampleModel.setPixels(x-sampleModelTranslateX,y-sampleModelTranslateY, + w,h,iArray,dataBuffer); + } + + /** + * Sets all samples for a rectangle of pixels from a float array containing + * one sample per array element. + * An ArrayIndexOutOfBoundsException may be thrown if the coordinates are + * not in bounds. + * However, explicit bounds checking is not guaranteed. + * @param x The X coordinate of the upper left pixel location. + * @param y The Y coordinate of the upper left pixel location. + * @param w Width of the pixel rectangle. + * @param h Height of the pixel rectangle. + * @param fArray The input float pixel array. + * + * @throws NullPointerException if fArray is null. + * @throws ArrayIndexOutOfBoundsException if the coordinates are not + * in bounds, or if fArray is too small to hold the input. + */ + public void setPixels(int x, int y, int w, int h, float fArray[]) { + sampleModel.setPixels(x-sampleModelTranslateX,y-sampleModelTranslateY, + w,h,fArray,dataBuffer); + } + + /** + * Sets all samples for a rectangle of pixels from a double array containing + * one sample per array element. + * An ArrayIndexOutOfBoundsException may be thrown if the coordinates are + * not in bounds. + * However, explicit bounds checking is not guaranteed. + * @param x The X coordinate of the upper left pixel location. + * @param y The Y coordinate of the upper left pixel location. + * @param w Width of the pixel rectangle. + * @param h Height of the pixel rectangle. + * @param dArray The input double pixel array. + * + * @throws NullPointerException if dArray is null. + * @throws ArrayIndexOutOfBoundsException if the coordinates are not + * in bounds, or if dArray is too small to hold the input. + */ + public void setPixels(int x, int y, int w, int h, double dArray[]) { + sampleModel.setPixels(x-sampleModelTranslateX,y-sampleModelTranslateY, + w,h,dArray,dataBuffer); + } + + /** + * Sets a sample in the specified band for the pixel located at (x,y) + * in the DataBuffer using an int for input. + * An ArrayIndexOutOfBoundsException may be thrown if the coordinates are + * not in bounds. + * However, explicit bounds checking is not guaranteed. + * @param x The X coordinate of the pixel location. + * @param y The Y coordinate of the pixel location. + * @param b The band to set. + * @param s The input sample. + * + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. + */ + public void setSample(int x, int y, int b, int s) { + sampleModel.setSample(x-sampleModelTranslateX, + y-sampleModelTranslateY, b, s, + dataBuffer); + } + + /** + * Sets a sample in the specified band for the pixel located at (x,y) + * in the DataBuffer using a float for input. + * An ArrayIndexOutOfBoundsException may be thrown if the coordinates are + * not in bounds. + * However, explicit bounds checking is not guaranteed. + * @param x The X coordinate of the pixel location. + * @param y The Y coordinate of the pixel location. + * @param b The band to set. + * @param s The input sample as a float. + * + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. + */ + public void setSample(int x, int y, int b, float s){ + sampleModel.setSample(x-sampleModelTranslateX,y-sampleModelTranslateY, + b,s,dataBuffer); + } + + /** + * Sets a sample in the specified band for the pixel located at (x,y) + * in the DataBuffer using a double for input. + * An ArrayIndexOutOfBoundsException may be thrown if the coordinates are + * not in bounds. + * However, explicit bounds checking is not guaranteed. + * @param x The X coordinate of the pixel location. + * @param y The Y coordinate of the pixel location. + * @param b The band to set. + * @param s The input sample as a double. + * + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds. + */ + public void setSample(int x, int y, int b, double s){ + sampleModel.setSample(x-sampleModelTranslateX,y-sampleModelTranslateY, + b,s,dataBuffer); + } + + /** + * Sets the samples in the specified band for the specified rectangle + * of pixels from an int array containing one sample per array element. + * An ArrayIndexOutOfBoundsException may be thrown if the coordinates are + * not in bounds. + * However, explicit bounds checking is not guaranteed. + * @param x The X coordinate of the upper left pixel location. + * @param y The Y coordinate of the upper left pixel location. + * @param w Width of the pixel rectangle. + * @param h Height of the pixel rectangle. + * @param b The band to set. + * @param iArray The input int sample array. + * + * @throws NullPointerException if iArray is null. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds, or if iArray is too small to + * hold the input. + */ + public void setSamples(int x, int y, int w, int h, int b, + int iArray[]) { + sampleModel.setSamples(x-sampleModelTranslateX,y-sampleModelTranslateY, + w,h,b,iArray,dataBuffer); + } + + /** + * Sets the samples in the specified band for the specified rectangle + * of pixels from a float array containing one sample per array element. + * An ArrayIndexOutOfBoundsException may be thrown if the coordinates are + * not in bounds. + * However, explicit bounds checking is not guaranteed. + * @param x The X coordinate of the upper left pixel location. + * @param y The Y coordinate of the upper left pixel location. + * @param w Width of the pixel rectangle. + * @param h Height of the pixel rectangle. + * @param b The band to set. + * @param fArray The input float sample array. + * + * @throws NullPointerException if fArray is null. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds, or if fArray is too small to + * hold the input. + */ + public void setSamples(int x, int y, int w, int h, int b, + float fArray[]) { + sampleModel.setSamples(x-sampleModelTranslateX,y-sampleModelTranslateY, + w,h,b,fArray,dataBuffer); + } + + /** + * Sets the samples in the specified band for the specified rectangle + * of pixels from a double array containing one sample per array element. + * An ArrayIndexOutOfBoundsException may be thrown if the coordinates are + * not in bounds. + * However, explicit bounds checking is not guaranteed. + * @param x The X coordinate of the upper left pixel location. + * @param y The Y coordinate of the upper left pixel location. + * @param w Width of the pixel rectangle. + * @param h Height of the pixel rectangle. + * @param b The band to set. + * @param dArray The input double sample array. + * + * @throws NullPointerException if dArray is null. + * @throws ArrayIndexOutOfBoundsException if the coordinates or + * the band index are not in bounds, or if dArray is too small to + * hold the input. + */ + public void setSamples(int x, int y, int w, int h, int b, + double dArray[]) { + sampleModel.setSamples(x-sampleModelTranslateX,y-sampleModelTranslateY, + w,h,b,dArray,dataBuffer); + } + +} diff -r bbe9212c7005 -r 17a5f29f1ae8 jdk/src/share/classes/java/awt/image/WritableRenderedImage.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/awt/image/WritableRenderedImage.java Thu Apr 10 18:31:26 2008 -0700 @@ -0,0 +1,151 @@ +/* + * Portions Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* **************************************************************** + ****************************************************************** + ****************************************************************** + *** COPYRIGHT (c) Eastman Kodak Company, 1997 + *** As an unpublished work pursuant to Title 17 of the United + *** States Code. All rights reserved. + ****************************************************************** + ****************************************************************** + ******************************************************************/ + +package java.awt.image; +import java.awt.Point; + +/** + * WriteableRenderedImage is a common interface for objects which + * contain or can produce image data in the form of Rasters and + * which can be modified and/or written over. The image + * data may be stored/produced as a single tile or a regular array + * of tiles. + *

+ * WritableRenderedImage provides notification to other interested + * objects when a tile is checked out for writing (via the + * getWritableTile method) and when the last writer of a particular + * tile relinquishes its access (via a call to releaseWritableTile). + * Additionally, it allows any caller to determine whether any tiles + * are currently checked out (via hasTileWriters), and to obtain a + * list of such tiles (via getWritableTileIndices, in the form of a Vector + * of Point objects). + *

+ * Objects wishing to be notified of changes in tile writability must + * implement the TileObserver interface, and are added by a + * call to addTileObserver. Multiple calls to + * addTileObserver for the same object will result in multiple + * notifications. An existing observer may reduce its notifications + * by calling removeTileObserver; if the observer had no + * notifications the operation is a no-op. + *

+ * It is necessary for a WritableRenderedImage to ensure that + * notifications occur only when the first writer acquires a tile and + * the last writer releases it. + * + */ + +public interface WritableRenderedImage extends RenderedImage +{ + + /** + * Adds an observer. If the observer is already present, + * it will receive multiple notifications. + * @param to the specified TileObserver + */ + public void addTileObserver(TileObserver to); + + /** + * Removes an observer. If the observer was not registered, + * nothing happens. If the observer was registered for multiple + * notifications, it will now be registered for one fewer. + * @param to the specified TileObserver + */ + public void removeTileObserver(TileObserver to); + + /** + * Checks out a tile for writing. + * + * The WritableRenderedImage is responsible for notifying all + * of its TileObservers when a tile goes from having + * no writers to having one writer. + * + * @param tileX the X index of the tile. + * @param tileY the Y index of the tile. + * @return a writable tile. + */ + public WritableRaster getWritableTile(int tileX, int tileY); + + /** + * Relinquishes the right to write to a tile. If the caller + * continues to write to the tile, the results are undefined. + * Calls to this method should only appear in matching pairs + * with calls to getWritableTile; any other use will lead + * to undefined results. + * + * The WritableRenderedImage is responsible for notifying all of + * its TileObservers when a tile goes from having one writer + * to having no writers. + * + * @param tileX the X index of the tile. + * @param tileY the Y index of the tile. + */ + public void releaseWritableTile(int tileX, int tileY); + + /** + * Returns whether a tile is currently checked out for writing. + * + * @param tileX the X index of the tile. + * @param tileY the Y index of the tile. + * @return true if specified tile is checked out + * for writing; false otherwise. + */ + public boolean isTileWritable(int tileX, int tileY); + + /** + * Returns an array of Point objects indicating which tiles + * are checked out for writing. Returns null if none are + * checked out. + * @return an array containing the locations of tiles that are + * checked out for writing. + */ + public Point[] getWritableTileIndices(); + + /** + * Returns whether any tile is checked out for writing. + * Semantically equivalent to (getWritableTileIndices() != null). + * @return true if any tiles are checked out for + * writing; false otherwise. + */ + public boolean hasTileWriters(); + + /** + * Sets a rect of the image to the contents of the Raster r, which is + * assumed to be in the same coordinate space as the WritableRenderedImage. + * The operation is clipped to the bounds of the WritableRenderedImage. + * @param r the specified Raster + */ + public void setData(Raster r); + +} diff -r bbe9212c7005 -r 17a5f29f1ae8 jdk/src/share/classes/java/awt/image/renderable/ContextualRenderedImageFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/awt/image/renderable/ContextualRenderedImageFactory.java Thu Apr 10 18:31:26 2008 -0700 @@ -0,0 +1,143 @@ +/* + * Portions Copyright 1998-2000 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* ******************************************************************** + ********************************************************************** + ********************************************************************** + *** COPYRIGHT (c) Eastman Kodak Company, 1997 *** + *** As an unpublished work pursuant to Title 17 of the United *** + *** States Code. All rights reserved. *** + ********************************************************************** + ********************************************************************** + **********************************************************************/ + +package java.awt.image.renderable; +import java.awt.geom.Rectangle2D; +import java.awt.image.RenderedImage; + +/** + * ContextualRenderedImageFactory provides an interface for the + * functionality that may differ between instances of + * RenderableImageOp. Thus different operations on RenderableImages + * may be performed by a single class such as RenderedImageOp through + * the use of multiple instances of ContextualRenderedImageFactory. + * The name ContextualRenderedImageFactory is commonly shortened to + * "CRIF." + * + *

All operations that are to be used in a rendering-independent + * chain must implement ContextualRenderedImageFactory. + * + *

Classes that implement this interface must provide a + * constructor with no arguments. + */ +public interface ContextualRenderedImageFactory extends RenderedImageFactory { + + /** + * Maps the operation's output RenderContext into a RenderContext + * for each of the operation's sources. This is useful for + * operations that can be expressed in whole or in part simply as + * alterations in the RenderContext, such as an affine mapping, or + * operations that wish to obtain lower quality renderings of + * their sources in order to save processing effort or + * transmission bandwith. Some operations, such as blur, can also + * use this mechanism to avoid obtaining sources of higher quality + * than necessary. + * + * @param i the index of the source image. + * @param renderContext the RenderContext being applied to the operation. + * @param paramBlock a ParameterBlock containing the operation's + * sources and parameters. + * @param image the RenderableImage being rendered. + * @return a RenderContext for + * the source at the specified index of the parameters + * Vector contained in the specified ParameterBlock. + */ + RenderContext mapRenderContext(int i, + RenderContext renderContext, + ParameterBlock paramBlock, + RenderableImage image); + + /** + * Creates a rendering, given a RenderContext and a ParameterBlock + * containing the operation's sources and parameters. The output + * is a RenderedImage that takes the RenderContext into account to + * determine its dimensions and placement on the image plane. + * This method houses the "intelligence" that allows a + * rendering-independent operation to adapt to a specific + * RenderContext. + * + * @param renderContext The RenderContext specifying the rendering + * @param paramBlock a ParameterBlock containing the operation's + * sources and parameters + * @return a RenderedImage from the sources and parameters + * in the specified ParameterBlock and according to the + * rendering instructions in the specified RenderContext. + */ + RenderedImage create(RenderContext renderContext, + ParameterBlock paramBlock); + + /** + * Returns the bounding box for the output of the operation, + * performed on a given set of sources, in rendering-independent + * space. The bounds are returned as a Rectangle2D, that is, an + * axis-aligned rectangle with floating-point corner coordinates. + * + * @param paramBlock a ParameterBlock containing the operation's + * sources and parameters. + * @return a Rectangle2D specifying the rendering-independent + * bounding box of the output. + */ + Rectangle2D getBounds2D(ParameterBlock paramBlock); + + /** + * Gets the appropriate instance of the property specified by the name + * parameter. This method must determine which instance of a property to + * return when there are multiple sources that each specify the property. + * + * @param paramBlock a ParameterBlock containing the operation's + * sources and parameters. + * @param name a String naming the desired property. + * @return an object reference to the value of the property requested. + */ + Object getProperty(ParameterBlock paramBlock, String name); + + /** + * Returns a list of names recognized by getProperty. + * @return the list of property names. + */ + String[] getPropertyNames(); + + /** + * Returns true if successive renderings (that is, calls to + * create(RenderContext, ParameterBlock)) with the same arguments + * may produce different results. This method may be used to + * determine whether an existing rendering may be cached and + * reused. It is always safe to return true. + * @return true if successive renderings with the + * same arguments might produce different results; + * false otherwise. + */ + boolean isDynamic(); +} diff -r bbe9212c7005 -r 17a5f29f1ae8 jdk/src/share/classes/java/awt/image/renderable/RenderContext.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/awt/image/renderable/RenderContext.java Thu Apr 10 18:31:26 2008 -0700 @@ -0,0 +1,272 @@ +/* + * Portions Copyright 1998-2000 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* ******************************************************************** + ********************************************************************** + ********************************************************************** + *** COPYRIGHT (c) Eastman Kodak Company, 1997 *** + *** As an unpublished work pursuant to Title 17 of the United *** + *** States Code. All rights reserved. *** + ********************************************************************** + ********************************************************************** + **********************************************************************/ + +package java.awt.image.renderable; +import java.util.*; +import java.awt.geom.*; +import java.awt.*; +import java.awt.image.*; + +/** + * A RenderContext encapsulates the information needed to produce a + * specific rendering from a RenderableImage. It contains the area to + * be rendered specified in rendering-independent terms, the + * resolution at which the rendering is to be performed, and hints + * used to control the rendering process. + * + *

Users create RenderContexts and pass them to the + * RenderableImage via the createRendering method. Most of the methods of + * RenderContexts are not meant to be used directly by applications, + * but by the RenderableImage and operator classes to which it is + * passed. + * + *

The AffineTransform parameter passed into and out of this class + * are cloned. The RenderingHints and Shape parameters are not + * necessarily cloneable and are therefore only reference copied. + * Altering RenderingHints or Shape instances that are in use by + * instances of RenderContext may have undesired side effects. + */ +public class RenderContext implements Cloneable { + + /** Table of hints. May be null. */ + RenderingHints hints; + + /** Transform to convert user coordinates to device coordinates. */ + AffineTransform usr2dev; + + /** The area of interest. May be null. */ + Shape aoi; + + // Various constructors that allow different levels of + // specificity. If the Shape is missing the whole renderable area + // is assumed. If hints is missing no hints are assumed. + + /** + * Constructs a RenderContext with a given transform. + * The area of interest is supplied as a Shape, + * and the rendering hints are supplied as a RenderingHints object. + * + * @param usr2dev an AffineTransform. + * @param aoi a Shape representing the area of interest. + * @param hints a RenderingHints object containing rendering hints. + */ + public RenderContext(AffineTransform usr2dev, + Shape aoi, + RenderingHints hints) { + this.hints = hints; + this.aoi = aoi; + this.usr2dev = (AffineTransform)usr2dev.clone(); + } + + /** + * Constructs a RenderContext with a given transform. + * The area of interest is taken to be the entire renderable area. + * No rendering hints are used. + * + * @param usr2dev an AffineTransform. + */ + public RenderContext(AffineTransform usr2dev) { + this(usr2dev, null, null); + } + + /** + * Constructs a RenderContext with a given transform and rendering hints. + * The area of interest is taken to be the entire renderable area. + * + * @param usr2dev an AffineTransform. + * @param hints a RenderingHints object containing rendering hints. + */ + public RenderContext(AffineTransform usr2dev, RenderingHints hints) { + this(usr2dev, null, hints); + } + + /** + * Constructs a RenderContext with a given transform and area of interest. + * The area of interest is supplied as a Shape. + * No rendering hints are used. + * + * @param usr2dev an AffineTransform. + * @param aoi a Shape representing the area of interest. + */ + public RenderContext(AffineTransform usr2dev, Shape aoi) { + this(usr2dev, aoi, null); + } + + /** + * Gets the rendering hints of this RenderContext. + * @return a RenderingHints object that represents + * the rendering hints of this RenderContext. + * @see #setRenderingHints(RenderingHints) + */ + public RenderingHints getRenderingHints() { + return hints; + } + + /** + * Sets the rendering hints of this RenderContext. + * @param hints a RenderingHints object that represents + * the rendering hints to assign to this RenderContext. + * @see #getRenderingHints + */ + public void setRenderingHints(RenderingHints hints) { + this.hints = hints; + } + + /** + * Sets the current user-to-device AffineTransform contained + * in the RenderContext to a given transform. + * + * @param newTransform the new AffineTransform. + * @see #getTransform + */ + public void setTransform(AffineTransform newTransform) { + usr2dev = (AffineTransform)newTransform.clone(); + } + + /** + * Modifies the current user-to-device transform by prepending another + * transform. In matrix notation the operation is: + *

+     * [this] = [modTransform] x [this]
+     * 
+ * + * @param modTransform the AffineTransform to prepend to the + * current usr2dev transform. + * @since 1.3 + */ + public void preConcatenateTransform(AffineTransform modTransform) { + this.preConcetenateTransform(modTransform); + } + + /** + * Modifies the current user-to-device transform by prepending another + * transform. In matrix notation the operation is: + *
+     * [this] = [modTransform] x [this]
+     * 
+ * This method does the same thing as the preConcatenateTransform + * method. It is here for backward compatibility with previous releases + * which misspelled the method name. + * + * @param modTransform the AffineTransform to prepend to the + * current usr2dev transform. + * @deprecated replaced by + * preConcatenateTransform(AffineTransform). + */ + @Deprecated + public void preConcetenateTransform(AffineTransform modTransform) { + usr2dev.preConcatenate(modTransform); + } + + /** + * Modifies the current user-to-device transform by appending another + * transform. In matrix notation the operation is: + *
+     * [this] = [this] x [modTransform]
+     * 
+ * + * @param modTransform the AffineTransform to append to the + * current usr2dev transform. + * @since 1.3 + */ + public void concatenateTransform(AffineTransform modTransform) { + this.concetenateTransform(modTransform); + } + + /** + * Modifies the current user-to-device transform by appending another + * transform. In matrix notation the operation is: + *
+     * [this] = [this] x [modTransform]
+     * 
+ * This method does the same thing as the concatenateTransform + * method. It is here for backward compatibility with previous releases + * which misspelled the method name. + * + * @param modTransform the AffineTransform to append to the + * current usr2dev transform. + * @deprecated replaced by + * concatenateTransform(AffineTransform). + */ + @Deprecated + public void concetenateTransform(AffineTransform modTransform) { + usr2dev.concatenate(modTransform); + } + + /** + * Gets the current user-to-device AffineTransform. + * + * @return a reference to the current AffineTransform. + * @see #setTransform(AffineTransform) + */ + public AffineTransform getTransform() { + return (AffineTransform)usr2dev.clone(); + } + + /** + * Sets the current area of interest. The old area is discarded. + * + * @param newAoi The new area of interest. + * @see #getAreaOfInterest + */ + public void setAreaOfInterest(Shape newAoi) { + aoi = newAoi; + } + + /** + * Gets the ares of interest currently contained in the + * RenderContext. + * + * @return a reference to the area of interest of the RenderContext, + * or null if none is specified. + * @see #setAreaOfInterest(Shape) + */ + public Shape getAreaOfInterest() { + return aoi; + } + + /** + * Makes a copy of a RenderContext. The area of interest is copied + * by reference. The usr2dev AffineTransform and hints are cloned, + * while the area of interest is copied by reference. + * + * @return the new cloned RenderContext. + */ + public Object clone() { + RenderContext newRenderContext = new RenderContext(usr2dev, + aoi, hints); + return newRenderContext; + } +} diff -r bbe9212c7005 -r 17a5f29f1ae8 jdk/src/share/classes/java/awt/image/renderable/RenderableImage.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/awt/image/renderable/RenderableImage.java Thu Apr 10 18:31:26 2008 -0700 @@ -0,0 +1,198 @@ +/* + * Portions Copyright 1998-2000 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* ******************************************************************** + ********************************************************************** + ********************************************************************** + *** COPYRIGHT (c) Eastman Kodak Company, 1997 *** + *** As an unpublished work pursuant to Title 17 of the United *** + *** States Code. All rights reserved. *** + ********************************************************************** + ********************************************************************** + **********************************************************************/ + +package java.awt.image.renderable; +import java.util.Vector; +import java.awt.RenderingHints; +import java.awt.image.*; + +/** + * A RenderableImage is a common interface for rendering-independent + * images (a notion which subsumes resolution independence). That is, + * images which are described and have operations applied to them + * independent of any specific rendering of the image. For example, a + * RenderableImage can be rotated and cropped in + * resolution-independent terms. Then, it can be rendered for various + * specific contexts, such as a draft preview, a high-quality screen + * display, or a printer, each in an optimal fashion. + * + *

A RenderedImage is returned from a RenderableImage via the + * createRendering() method, which takes a RenderContext. The + * RenderContext specifies how the RenderedImage should be + * constructed. Note that it is not possible to extract pixels + * directly from a RenderableImage. + * + *

The createDefaultRendering() and createScaledRendering() methods are + * convenience methods that construct an appropriate RenderContext + * internally. All of the rendering methods may return a reference to a + * previously produced rendering. + */ +public interface RenderableImage { + + /** + * String constant that can be used to identify a property on + * a RenderedImage obtained via the createRendering or + * createScaledRendering methods. If such a property exists, + * the value of the propoery will be a RenderingHints object + * specifying which hints were observed in creating the rendering. + */ + static final String HINTS_OBSERVED = "HINTS_OBSERVED"; + + /** + * Returns a vector of RenderableImages that are the sources of + * image data for this RenderableImage. Note that this method may + * return an empty vector, to indicate that the image has no sources, + * or null, to indicate that no information is available. + * + * @return a (possibly empty) Vector of RenderableImages, or null. + */ + Vector getSources(); + + /** + * Gets a property from the property set of this image. + * If the property name is not recognized, java.awt.Image.UndefinedProperty + * will be returned. + * + * @param name the name of the property to get, as a String. + * @return a reference to the property Object, or the value + * java.awt.Image.UndefinedProperty. + */ + Object getProperty(String name); + + /** + * Returns a list of names recognized by getProperty. + * @return a list of property names. + */ + String[] getPropertyNames(); + + /** + * Returns true if successive renderings (that is, calls to + * createRendering() or createScaledRendering()) with the same arguments + * may produce different results. This method may be used to + * determine whether an existing rendering may be cached and + * reused. It is always safe to return true. + * @return true if successive renderings with the + * same arguments might produce different results; + * false otherwise. + */ + boolean isDynamic(); + + /** + * Gets the width in user coordinate space. By convention, the + * usual width of a RenderableImage is equal to the image's aspect + * ratio (width divided by height). + * + * @return the width of the image in user coordinates. + */ + float getWidth(); + + /** + * Gets the height in user coordinate space. By convention, the + * usual height of a RenderedImage is equal to 1.0F. + * + * @return the height of the image in user coordinates. + */ + float getHeight(); + + /** + * Gets the minimum X coordinate of the rendering-independent image data. + * @return the minimum X coordinate of the rendering-independent image + * data. + */ + float getMinX(); + + /** + * Gets the minimum Y coordinate of the rendering-independent image data. + * @return the minimum Y coordinate of the rendering-independent image + * data. + */ + float getMinY(); + + /** + * Creates a RenderedImage instance of this image with width w, and + * height h in pixels. The RenderContext is built automatically + * with an appropriate usr2dev transform and an area of interest + * of the full image. All the rendering hints come from hints + * passed in. + * + *

If w == 0, it will be taken to equal + * Math.round(h*(getWidth()/getHeight())). + * Similarly, if h == 0, it will be taken to equal + * Math.round(w*(getHeight()/getWidth())). One of + * w or h must be non-zero or else an IllegalArgumentException + * will be thrown. + * + *

The created RenderedImage may have a property identified + * by the String HINTS_OBSERVED to indicate which RenderingHints + * were used to create the image. In addition any RenderedImages + * that are obtained via the getSources() method on the created + * RenderedImage may have such a property. + * + * @param w the width of rendered image in pixels, or 0. + * @param h the height of rendered image in pixels, or 0. + * @param hints a RenderingHints object containg hints. + * @return a RenderedImage containing the rendered data. + */ + RenderedImage createScaledRendering(int w, int h, RenderingHints hints); + + /** + * Returnd a RenderedImage instance of this image with a default + * width and height in pixels. The RenderContext is built + * automatically with an appropriate usr2dev transform and an area + * of interest of the full image. The rendering hints are + * empty. createDefaultRendering may make use of a stored + * rendering for speed. + * + * @return a RenderedImage containing the rendered data. + */ + RenderedImage createDefaultRendering(); + + /** + * Creates a RenderedImage that represented a rendering of this image + * using a given RenderContext. This is the most general way to obtain a + * rendering of a RenderableImage. + * + *

The created RenderedImage may have a property identified + * by the String HINTS_OBSERVED to indicate which RenderingHints + * (from the RenderContext) were used to create the image. + * In addition any RenderedImages + * that are obtained via the getSources() method on the created + * RenderedImage may have such a property. + * + * @param renderContext the RenderContext to use to produce the rendering. + * @return a RenderedImage containing the rendered data. + */ + RenderedImage createRendering(RenderContext renderContext); +} diff -r bbe9212c7005 -r 17a5f29f1ae8 jdk/src/share/classes/java/awt/image/renderable/RenderableImageOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/awt/image/renderable/RenderableImageOp.java Thu Apr 10 18:31:26 2008 -0700 @@ -0,0 +1,350 @@ +/* + * Portions Copyright 1998-2000 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* ******************************************************************** + ********************************************************************** + ********************************************************************** + *** COPYRIGHT (c) Eastman Kodak Company, 1997 *** + *** As an unpublished work pursuant to Title 17 of the United *** + *** States Code. All rights reserved. *** + ********************************************************************** + ********************************************************************** + **********************************************************************/ + +package java.awt.image.renderable; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.image.RenderedImage; +import java.awt.RenderingHints; +import java.util.Hashtable; +import java.util.Vector; + +/** + * This class handles the renderable aspects of an operation with help + * from its associated instance of a ContextualRenderedImageFactory. + */ +public class RenderableImageOp implements RenderableImage { + + /** A ParameterBlock containing source and parameters. */ + ParameterBlock paramBlock; + + /** The associated ContextualRenderedImageFactory. */ + ContextualRenderedImageFactory myCRIF; + + /** The bounding box of the results of this RenderableImageOp. */ + Rectangle2D boundingBox; + + + /** + * Constructs a RenderedImageOp given a + * ContextualRenderedImageFactory object, and + * a ParameterBlock containing RenderableImage sources and other + * parameters. Any RenderedImage sources referenced by the + * ParameterBlock will be ignored. + * + * @param CRIF a ContextualRenderedImageFactory object + * @param paramBlock a ParameterBlock containing this operation's source + * images and other parameters necessary for the operation + * to run. + */ + public RenderableImageOp(ContextualRenderedImageFactory CRIF, + ParameterBlock paramBlock) { + this.myCRIF = CRIF; + this.paramBlock = (ParameterBlock) paramBlock.clone(); + } + + /** + * Returns a vector of RenderableImages that are the sources of + * image data for this RenderableImage. Note that this method may + * return an empty vector, to indicate that the image has no sources, + * or null, to indicate that no information is available. + * + * @return a (possibly empty) Vector of RenderableImages, or null. + */ + public Vector getSources() { + return getRenderableSources(); + } + + private Vector getRenderableSources() { + Vector sources = null; + + if (paramBlock.getNumSources() > 0) { + sources = new Vector(); + int i = 0; + while (i < paramBlock.getNumSources()) { + Object o = paramBlock.getSource(i); + if (o instanceof RenderableImage) { + sources.add((RenderableImage)o); + i++; + } else { + break; + } + } + } + return sources; + } + + /** + * Gets a property from the property set of this image. + * If the property name is not recognized, java.awt.Image.UndefinedProperty + * will be returned. + * + * @param name the name of the property to get, as a String. + * @return a reference to the property Object, or the value + * java.awt.Image.UndefinedProperty. + */ + public Object getProperty(String name) { + return myCRIF.getProperty(paramBlock, name); + } + + /** + * Return a list of names recognized by getProperty. + * @return a list of property names. + */ + public String[] getPropertyNames() { + return myCRIF.getPropertyNames(); + } + + /** + * Returns true if successive renderings (that is, calls to + * createRendering() or createScaledRendering()) with the same arguments + * may produce different results. This method may be used to + * determine whether an existing rendering may be cached and + * reused. The CRIF's isDynamic method will be called. + * @return true if successive renderings with the + * same arguments might produce different results; + * false otherwise. + */ + public boolean isDynamic() { + return myCRIF.isDynamic(); + } + + /** + * Gets the width in user coordinate space. By convention, the + * usual width of a RenderableImage is equal to the image's aspect + * ratio (width divided by height). + * + * @return the width of the image in user coordinates. + */ + public float getWidth() { + if (boundingBox == null) { + boundingBox = myCRIF.getBounds2D(paramBlock); + } + return (float)boundingBox.getWidth(); + } + + /** + * Gets the height in user coordinate space. By convention, the + * usual height of a RenderedImage is equal to 1.0F. + * + * @return the height of the image in user coordinates. + */ + public float getHeight() { + if (boundingBox == null) { + boundingBox = myCRIF.getBounds2D(paramBlock); + } + return (float)boundingBox.getHeight(); + } + + /** + * Gets the minimum X coordinate of the rendering-independent image data. + */ + public float getMinX() { + if (boundingBox == null) { + boundingBox = myCRIF.getBounds2D(paramBlock); + } + return (float)boundingBox.getMinX(); + } + + /** + * Gets the minimum Y coordinate of the rendering-independent image data. + */ + public float getMinY() { + if (boundingBox == null) { + boundingBox = myCRIF.getBounds2D(paramBlock); + } + return (float)boundingBox.getMinY(); + } + + /** + * Change the current ParameterBlock of the operation, allowing + * editing of image rendering chains. The effects of such a + * change will be visible when a new rendering is created from + * this RenderableImageOp or any dependent RenderableImageOp. + * + * @param paramBlock the new ParameterBlock. + * @return the old ParameterBlock. + * @see #getParameterBlock + */ + public ParameterBlock setParameterBlock(ParameterBlock paramBlock) { + ParameterBlock oldParamBlock = this.paramBlock; + this.paramBlock = (ParameterBlock)paramBlock.clone(); + return oldParamBlock; + } + + /** + * Returns a reference to the current parameter block. + * @return the ParameterBlock of this + * RenderableImageOp. + * @see #setParameterBlock(ParameterBlock) + */ + public ParameterBlock getParameterBlock() { + return paramBlock; + } + + /** + * Creates a RenderedImage instance of this image with width w, and + * height h in pixels. The RenderContext is built automatically + * with an appropriate usr2dev transform and an area of interest + * of the full image. All the rendering hints come from hints + * passed in. + * + *

If w == 0, it will be taken to equal + * Math.round(h*(getWidth()/getHeight())). + * Similarly, if h == 0, it will be taken to equal + * Math.round(w*(getHeight()/getWidth())). One of + * w or h must be non-zero or else an IllegalArgumentException + * will be thrown. + * + *

The created RenderedImage may have a property identified + * by the String HINTS_OBSERVED to indicate which RenderingHints + * were used to create the image. In addition any RenderedImages + * that are obtained via the getSources() method on the created + * RenderedImage may have such a property. + * + * @param w the width of rendered image in pixels, or 0. + * @param h the height of rendered image in pixels, or 0. + * @param hints a RenderingHints object containg hints. + * @return a RenderedImage containing the rendered data. + */ + public RenderedImage createScaledRendering(int w, int h, + RenderingHints hints) { + // DSR -- code to try to get a unit scale + double sx = (double)w/getWidth(); + double sy = (double)h/getHeight(); + if (Math.abs(sx/sy - 1.0) < 0.01) { + sx = sy; + } + AffineTransform usr2dev = AffineTransform.getScaleInstance(sx, sy); + RenderContext newRC = new RenderContext(usr2dev, hints); + return createRendering(newRC); + } + + /** + * Gets a RenderedImage instance of this image with a default + * width and height in pixels. The RenderContext is built + * automatically with an appropriate usr2dev transform and an area + * of interest of the full image. All the rendering hints come + * from hints passed in. Implementors of this interface must be + * sure that there is a defined default width and height. + * + * @return a RenderedImage containing the rendered data. + */ + public RenderedImage createDefaultRendering() { + AffineTransform usr2dev = new AffineTransform(); // Identity + RenderContext newRC = new RenderContext(usr2dev); + return createRendering(newRC); + } + + /** + * Creates a RenderedImage which represents this + * RenderableImageOp (including its Renderable sources) rendered + * according to the given RenderContext. + * + *

This method supports chaining of either Renderable or + * RenderedImage operations. If sources in + * the ParameterBlock used to construct the RenderableImageOp are + * RenderableImages, then a three step process is followed: + * + *

    + *
  1. mapRenderContext() is called on the associated CRIF for + * each RenderableImage source; + *
  2. createRendering() is called on each of the RenderableImage sources + * using the backwards-mapped RenderContexts obtained in step 1, + * resulting in a rendering of each source; + *
  3. ContextualRenderedImageFactory.create() is called + * with a new ParameterBlock containing the parameters of + * the RenderableImageOp and the RenderedImages that were created by the + * createRendering() calls. + *
+ * + *

If the elements of the source Vector of + * the ParameterBlock used to construct the RenderableImageOp are + * instances of RenderedImage, then the CRIF.create() method is + * called immediately using the original ParameterBlock. + * This provides a basis case for the recursion. + * + *

The created RenderedImage may have a property identified + * by the String HINTS_OBSERVED to indicate which RenderingHints + * (from the RenderContext) were used to create the image. + * In addition any RenderedImages + * that are obtained via the getSources() method on the created + * RenderedImage may have such a property. + * + * @param renderContext The RenderContext to use to perform the rendering. + * @return a RenderedImage containing the desired output image. + */ + public RenderedImage createRendering(RenderContext renderContext) { + RenderedImage image = null; + RenderContext rcOut = null; + + // Clone the original ParameterBlock; if the ParameterBlock + // contains RenderableImage sources, they will be replaced by + // RenderedImages. + ParameterBlock renderedParamBlock = (ParameterBlock)paramBlock.clone(); + Vector sources = getRenderableSources(); + + try { + // This assumes that if there is no renderable source, that there + // is a rendered source in paramBlock + + if (sources != null) { + Vector renderedSources = new Vector(); + for (int i = 0; i < sources.size(); i++) { + rcOut = myCRIF.mapRenderContext(i, renderContext, + paramBlock, this); + RenderedImage rdrdImage = + ((RenderableImage)sources.elementAt(i)).createRendering(rcOut); + if (rdrdImage == null) { + return null; + } + + // Add this rendered image to the ParameterBlock's + // list of RenderedImages. + renderedSources.addElement(rdrdImage); + } + + if (renderedSources.size() > 0) { + renderedParamBlock.setSources(renderedSources); + } + } + + return myCRIF.create(renderContext, renderedParamBlock); + } catch (ArrayIndexOutOfBoundsException e) { + // This should never happen + return null; + } + } +} diff -r bbe9212c7005 -r 17a5f29f1ae8 jdk/src/share/classes/java/awt/image/renderable/RenderableImageProducer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/awt/image/renderable/RenderableImageProducer.java Thu Apr 10 18:31:26 2008 -0700 @@ -0,0 +1,219 @@ +/* + * Portions Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* ******************************************************************** + ********************************************************************** + ********************************************************************** + *** COPYRIGHT (c) Eastman Kodak Company, 1997 *** + *** As an unpublished work pursuant to Title 17 of the United *** + *** States Code. All rights reserved. *** + ********************************************************************** + ********************************************************************** + **********************************************************************/ + +package java.awt.image.renderable; +import java.awt.color.ColorSpace; +import java.awt.image.ColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.DirectColorModel; +import java.awt.image.ImageConsumer; +import java.awt.image.ImageProducer; +import java.awt.image.Raster; +import java.awt.image.RenderedImage; +import java.awt.image.SampleModel; +import java.util.Enumeration; +import java.util.Vector; + +/** + * An adapter class that implements ImageProducer to allow the + * asynchronous production of a RenderableImage. The size of the + * ImageConsumer is determined by the scale factor of the usr2dev + * transform in the RenderContext. If the RenderContext is null, the + * default rendering of the RenderableImage is used. This class + * implements an asynchronous production that produces the image in + * one thread at one resolution. This class may be subclassed to + * implement versions that will render the image using several + * threads. These threads could render either the same image at + * progressively better quality, or different sections of the image at + * a single resolution. + */ +public class RenderableImageProducer implements ImageProducer, Runnable { + + /** The RenderableImage source for the producer. */ + RenderableImage rdblImage; + + /** The RenderContext to use for producing the image. */ + RenderContext rc; + + /** A Vector of image consumers. */ + Vector ics = new Vector(); + + /** + * Constructs a new RenderableImageProducer from a RenderableImage + * and a RenderContext. + * + * @param rdblImage the RenderableImage to be rendered. + * @param rc the RenderContext to use for producing the pixels. + */ + public RenderableImageProducer(RenderableImage rdblImage, + RenderContext rc) { + this.rdblImage = rdblImage; + this.rc = rc; + } + + /** + * Sets a new RenderContext to use for the next startProduction() call. + * + * @param rc the new RenderContext. + */ + public synchronized void setRenderContext(RenderContext rc) { + this.rc = rc; + } + + /** + * Adds an ImageConsumer to the list of consumers interested in + * data for this image. + * + * @param ic an ImageConsumer to be added to the interest list. + */ + public synchronized void addConsumer(ImageConsumer ic) { + if (!ics.contains(ic)) { + ics.addElement(ic); + } + } + + /** + * Determine if an ImageConsumer is on the list of consumers + * currently interested in data for this image. + * + * @param ic the ImageConsumer to be checked. + * @return true if the ImageConsumer is on the list; false otherwise. + */ + public synchronized boolean isConsumer(ImageConsumer ic) { + return ics.contains(ic); + } + + /** + * Remove an ImageConsumer from the list of consumers interested in + * data for this image. + * + * @param ic the ImageConsumer to be removed. + */ + public synchronized void removeConsumer(ImageConsumer ic) { + ics.removeElement(ic); + } + + /** + * Adds an ImageConsumer to the list of consumers interested in + * data for this image, and immediately starts delivery of the + * image data through the ImageConsumer interface. + * + * @param ic the ImageConsumer to be added to the list of consumers. + */ + public synchronized void startProduction(ImageConsumer ic) { + addConsumer(ic); + // Need to build a runnable object for the Thread. + Thread thread = new Thread(this, "RenderableImageProducer Thread"); + thread.start(); + } + + /** + * Requests that a given ImageConsumer have the image data delivered + * one more time in top-down, left-right order. + * + * @param ic the ImageConsumer requesting the resend. + */ + public void requestTopDownLeftRightResend(ImageConsumer ic) { + // So far, all pixels are already sent in TDLR order + } + + /** + * The runnable method for this class. This will produce an image using + * the current RenderableImage and RenderContext and send it to all the + * ImageConsumer currently registered with this class. + */ + public void run() { + // First get the rendered image + RenderedImage rdrdImage; + if (rc != null) { + rdrdImage = rdblImage.createRendering(rc); + } else { + rdrdImage = rdblImage.createDefaultRendering(); + } + + // And its ColorModel + ColorModel colorModel = rdrdImage.getColorModel(); + Raster raster = rdrdImage.getData(); + SampleModel sampleModel = raster.getSampleModel(); + DataBuffer dataBuffer = raster.getDataBuffer(); + + if (colorModel == null) { + colorModel = ColorModel.getRGBdefault(); + } + int minX = raster.getMinX(); + int minY = raster.getMinY(); + int width = raster.getWidth(); + int height = raster.getHeight(); + + Enumeration icList; + ImageConsumer ic; + // Set up the ImageConsumers + icList = ics.elements(); + while (icList.hasMoreElements()) { + ic = (ImageConsumer)icList.nextElement(); + ic.setDimensions(width,height); + ic.setHints(ImageConsumer.TOPDOWNLEFTRIGHT | + ImageConsumer.COMPLETESCANLINES | + ImageConsumer.SINGLEPASS | + ImageConsumer.SINGLEFRAME); + } + + // Get RGB pixels from the raster scanline by scanline and + // send to consumers. + int pix[] = new int[width]; + int i,j; + int numBands = sampleModel.getNumBands(); + int tmpPixel[] = new int[numBands]; + for (j = 0; j < height; j++) { + for(i = 0; i < width; i++) { + sampleModel.getPixel(i, j, tmpPixel, dataBuffer); + pix[i] = colorModel.getDataElement(tmpPixel, 0); + } + // Now send the scanline to the Consumers + icList = ics.elements(); + while (icList.hasMoreElements()) { + ic = (ImageConsumer)icList.nextElement(); + ic.setPixels(0, j, width, 1, colorModel, pix, 0, width); + } + } + + // Now tell the consumers we're done. + icList = ics.elements(); + while (icList.hasMoreElements()) { + ic = (ImageConsumer)icList.nextElement(); + ic.imageComplete(ImageConsumer.STATICIMAGEDONE); + } + } +} diff -r bbe9212c7005 -r 17a5f29f1ae8 jdk/src/share/classes/java/awt/image/renderable/RenderedImageFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/awt/image/renderable/RenderedImageFactory.java Thu Apr 10 18:31:26 2008 -0700 @@ -0,0 +1,78 @@ +/* + * Portions Copyright 1998 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* ******************************************************************** + ********************************************************************** + ********************************************************************** + *** COPYRIGHT (c) Eastman Kodak Company, 1997 *** + *** As an unpublished work pursuant to Title 17 of the United *** + *** States Code. All rights reserved. *** + ********************************************************************** + ********************************************************************** + **********************************************************************/ + +package java.awt.image.renderable; +import java.awt.image.RenderedImage; +import java.awt.RenderingHints; + +/** + * The RenderedImageFactory interface (often abbreviated RIF) is + * intended to be implemented by classes that wish to act as factories + * to produce different renderings, for example by executing a series + * of BufferedImageOps on a set of sources, depending on a specific + * set of parameters, properties, and rendering hints. + */ +public interface RenderedImageFactory { + + /** + * Creates a RenderedImage representing the results of an imaging + * operation (or chain of operations) for a given ParameterBlock and + * RenderingHints. The RIF may also query any source images + * referenced by the ParameterBlock for their dimensions, + * SampleModels, properties, etc., as necessary. + * + *

The create() method can return null if the + * RenderedImageFactory is not capable of producing output for the + * given set of source images and parameters. For example, if a + * RenderedImageFactory is only capable of performing a 3x3 + * convolution on single-banded image data, and the source image has + * multiple bands or the convolution Kernel is 5x5, null should be + * returned. + * + *

Hints should be taken into account, but can be ignored. + * The created RenderedImage may have a property identified + * by the String HINTS_OBSERVED to indicate which RenderingHints + * were used to create the image. In addition any RenderedImages + * that are obtained via the getSources() method on the created + * RenderedImage may have such a property. + * + * @param paramBlock a ParameterBlock containing sources and parameters + * for the RenderedImage to be created. + * @param hints a RenderingHints object containing hints. + * @return A RenderedImage containing the desired output. + */ + RenderedImage create(ParameterBlock paramBlock, + RenderingHints hints); +}