6662775: Move imaging and color classes from closed to open
authorprr
Thu Apr 10 16:28:45 2008 -0700 (23 months ago)
changeset 30291087975bff7
parent 301bda7549ac1d0
child 304aaa5637a841d
6662775: Move imaging and color classes from closed to open
Reviewed-by: tdv, campbell
make/common/internal/BinaryPlugs.gmk
make/java/awt/Makefile
src/share/classes/java/awt/color/CMMException.java
src/share/classes/java/awt/color/ColorSpace.java
src/share/classes/java/awt/color/ICC_ColorSpace.java
src/share/classes/java/awt/color/ICC_Profile.java
src/share/classes/java/awt/color/ICC_ProfileGray.java
src/share/classes/java/awt/color/ICC_ProfileRGB.java
src/share/classes/java/awt/image/BandedSampleModel.java
src/share/classes/java/awt/image/ColorConvertOp.java
src/share/classes/java/awt/image/ComponentSampleModel.java
src/share/classes/java/awt/image/DataBuffer.java
src/share/classes/java/awt/image/DataBufferByte.java
src/share/classes/java/awt/image/DataBufferInt.java
src/share/classes/java/awt/image/DataBufferShort.java
src/share/classes/java/awt/image/DataBufferUShort.java
src/share/classes/java/awt/image/MultiPixelPackedSampleModel.java
src/share/classes/java/awt/image/Raster.java
src/share/classes/java/awt/image/RenderedImage.java
src/share/classes/java/awt/image/SampleModel.java
src/share/classes/java/awt/image/SinglePixelPackedSampleModel.java
src/share/classes/java/awt/image/WritableRaster.java
src/share/classes/java/awt/image/WritableRenderedImage.java
src/share/classes/java/awt/image/renderable/ContextualRenderedImageFactory.java
src/share/classes/java/awt/image/renderable/RenderContext.java
src/share/classes/java/awt/image/renderable/RenderableImage.java
src/share/classes/java/awt/image/renderable/RenderableImageOp.java
src/share/classes/java/awt/image/renderable/RenderableImageProducer.java
src/share/classes/java/awt/image/renderable/RenderedImageFactory.java
--- a/make/common/internal/BinaryPlugs.gmk Thu Apr 10 10:32:31 2008 -0700
+++ b/make/common/internal/BinaryPlugs.gmk Thu Apr 10 16:28:45 2008 -0700
@@ -126,44 +126,10 @@ com/sun/media/sound/SimpleInputDevicePro
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
@@ -184,11 +150,6 @@ endef # plug-create-clist-jargs
$(PLUG_TEMPDIR)/sound.clist:
@$(prep-target)
@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)
@@ -198,8 +159,6 @@ endef # plug-create-clist-jargs
$(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 @@ import-binary-plug-jmf-classes: $(PLUG_I
$(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-plugs: \
import-binary-plug-jar \
import-binary-plug-jmf-classes \
import-binary-plug-sound-classes \
- import-binary-plug-awt-classes \
import-binary-plug-jsound-library
else # !OPENJDK
--- a/make/java/awt/Makefile Thu Apr 10 10:32:31 2008 -0700
+++ b/make/java/awt/Makefile Thu Apr 10 16:28:45 2008 -0700
@@ -28,23 +28,11 @@ PRODUCT = sun
PRODUCT = sun
include $(BUILDDIR)/common/Defs.gmk
-# WARNING: Make sure the OPENJDK plugs are up-to-date, see make/common/internal/BinaryPlugs.gmk
#
# Files
#
AUTO_FILES_JAVA_DIRS = java/awt sun/awt/geom
-
-#
-# Specific to OPENJDK
-#
-ifdef OPENJDK
-
-build: import-binary-plug-awt-classes
-
-include $(BUILDDIR)/common/internal/BinaryPlugs.gmk
-
-endif
build: properties cursors
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/awt/color/CMMException.java Thu Apr 10 16:28:45 2008 -0700
@@ -0,0 +1,57 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ Created by gbp, October 25, 1997
+
+ *
+ */
+/**********************************************************************
+ **********************************************************************
+ **********************************************************************
+ *** COPYRIGHT (c) Eastman Kodak Company, 1997 ***
+ *** As an unpublished work pursuant to Title 17 of the United ***
+ *** States Code. All rights reserved. ***
+ **********************************************************************
+ **********************************************************************
+ **********************************************************************/
+
+
+package java.awt.color;
+
+
+/**
+ * This exception is thrown if the native CMM returns an error.
+ */
+
+public class CMMException extends java.lang.RuntimeException {
+
+ /**
+ * Constructs a CMMException with the specified detail message.
+ * @param s the specified detail message
+ */
+ public CMMException (String s) {
+ super (s);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/awt/color/ColorSpace.java Thu Apr 10 16:28:45 2008 -0700
@@ -0,0 +1,611 @@
+/*
+ * Portions Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/**********************************************************************
+ **********************************************************************
+ **********************************************************************
+ *** COPYRIGHT (c) Eastman Kodak Company, 1997 ***
+ *** As an unpublished work pursuant to Title 17 of the United ***
+ *** States Code. All rights reserved. ***
+ **********************************************************************
+ **********************************************************************
+ **********************************************************************/
+
+package java.awt.color;
+
+import sun.java2d.cmm.PCMM;
+import sun.java2d.cmm.CMSManager;
+
+
+/**
+ * This abstract class is used to serve as a color space tag to identify the
+ * specific color space of a Color object or, via a ColorModel object,
+ * of an Image, a BufferedImage, or a GraphicsDevice. It contains
+ * methods that transform colors in a specific color space to/from sRGB
+ * and to/from a well-defined CIEXYZ color space.
+ * <p>
+ * For purposes of the methods in this class, colors are represented as
+ * arrays of color components represented as floats in a normalized range
+ * defined by each ColorSpace. For many ColorSpaces (e.g. sRGB), this
+ * range is 0.0 to 1.0. However, some ColorSpaces have components whose
+ * values have a different range. Methods are provided to inquire per
+ * component minimum and maximum normalized values.
+ * <p>
+ * Several variables are defined for purposes of referring to color
+ * space types (e.g. TYPE_RGB, TYPE_XYZ, etc.) and to refer to specific
+ * color spaces (e.g. CS_sRGB and CS_CIEXYZ).
+ * sRGB is a proposed standard RGB color space. For more information,
+ * see <A href="http://www.w3.org/pub/WWW/Graphics/Color/sRGB.html">
+ * http://www.w3.org/pub/WWW/Graphics/Color/sRGB.html
+ * </A>.
+ * <p>
+ * The purpose of the methods to transform to/from the well-defined
+ * CIEXYZ color space is to support conversions between any two color
+ * spaces at a reasonably high degree of accuracy. It is expected that
+ * particular implementations of subclasses of ColorSpace (e.g.
+ * ICC_ColorSpace) will support high performance conversion based on
+ * underlying platform color management systems.
+ * <p>
+ * The CS_CIEXYZ space used by the toCIEXYZ/fromCIEXYZ methods can be
+ * described as follows:
+<pre>
+
+&nbsp; CIEXYZ
+&nbsp; viewing illuminance: 200 lux
+&nbsp; viewing white point: CIE D50
+&nbsp; media white point: "that of a perfectly reflecting diffuser" -- D50
+&nbsp; media black point: 0 lux or 0 Reflectance
+&nbsp; flare: 1 percent
+&nbsp; surround: 20percent of the media white point
+&nbsp; media description: reflection print (i.e., RLAB, Hunt viewing media)
+&nbsp; note: For developers creating an ICC profile for this conversion
+&nbsp; space, the following is applicable. Use a simple Von Kries
+&nbsp; white point adaptation folded into the 3X3 matrix parameters
+&nbsp; and fold the flare and surround effects into the three
+&nbsp; one-dimensional lookup tables (assuming one uses the minimal
+&nbsp; model for monitors).
+
+</pre>
+ *
+ * <p>
+ * @see ICC_ColorSpace
+ */
+
+
+
+public abstract class ColorSpace implements java.io.Serializable {
+
+ static final long serialVersionUID = -409452704308689724L;
+
+ private int type;
+ private int numComponents;
+ private transient String [] compName = null;
+
+ // Cache of singletons for the predefined color spaces.
+ private static ColorSpace sRGBspace;
+ private static ColorSpace XYZspace;
+ private static ColorSpace PYCCspace;
+ private static ColorSpace GRAYspace;
+ private static ColorSpace LINEAR_RGBspace;
+
+ /**
+ * Any of the family of XYZ color spaces.
+ */
+ public static final int TYPE_XYZ = 0;
+
+ /**
+ * Any of the family of Lab color spaces.
+ */
+ public static final int TYPE_Lab = 1;
+
+ /**
+ * Any of the family of Luv color spaces.
+ */
+ public static final int TYPE_Luv = 2;
+
+ /**
+ * Any of the family of YCbCr color spaces.
+ */
+ public static final int TYPE_YCbCr = 3;
+
+ /**
+ * Any of the family of Yxy color spaces.
+ */
+ public static final int TYPE_Yxy = 4;
+
+ /**
+ * Any of the family of RGB color spaces.
+ */
+ public static final int TYPE_RGB = 5;
+
+ /**
+ * Any of the family of GRAY color spaces.
+ */
+ public static final int TYPE_GRAY = 6;
+
+ /**
+ * Any of the family of HSV color spaces.
+ */
+ public static final int TYPE_HSV = 7;
+
+ /**
+ * Any of the family of HLS color spaces.
+ */
+ public static final int TYPE_HLS = 8;
+
+ /**
+ * Any of the family of CMYK color spaces.
+ */
+ public static final int TYPE_CMYK = 9;
+
+ /**
+ * Any of the family of CMY color spaces.
+ */
+ public static final int TYPE_CMY = 11;
+
+ /**
+ * Generic 2 component color spaces.
+ */
+ public static final int TYPE_2CLR = 12;
+
+ /**
+ * Generic 3 component color spaces.
+ */
+ public static final int TYPE_3CLR = 13;
+
+ /**
+ * Generic 4 component color spaces.
+ */
+ public static final int TYPE_4CLR = 14;
+
+ /**
+ * Generic 5 component color spaces.
+ */
+ public static final int TYPE_5CLR = 15;
+
+ /**
+ * Generic 6 component color spaces.
+ */
+ public static final int TYPE_6CLR = 16;
+
+ /**
+ * Generic 7 component color spaces.
+ */
+ public static final int TYPE_7CLR = 17;
+
+ /**
+ * Generic 8 component color spaces.
+ */
+ public static final int TYPE_8CLR = 18;
+
+ /**
+ * Generic 9 component color spaces.
+ */
+ public static final int TYPE_9CLR = 19;
+
+ /**
+ * Generic 10 component color spaces.
+ */
+ public static final int TYPE_ACLR = 20;
+
+ /**
+ * Generic 11 component color spaces.
+ */
+ public static final int TYPE_BCLR = 21;
+
+ /**
+ * Generic 12 component color spaces.
+ */
+ public static final int TYPE_CCLR = 22;
+
+ /**
+ * Generic 13 component color spaces.
+ */
+ public static final int TYPE_DCLR = 23;
+
+ /**
+ * Generic 14 component color spaces.
+ */
+ public static final int TYPE_ECLR = 24;
+
+ /**
+ * Generic 15 component color spaces.
+ */
+ public static final int TYPE_FCLR = 25;
+
+ /**
+ * The sRGB color space defined at
+ * <A href="http://www.w3.org/pub/WWW/Graphics/Color/sRGB.html">
+ * http://www.w3.org/pub/WWW/Graphics/Color/sRGB.html
+ * </A>.
+ */
+ public static final int CS_sRGB = 1000;
+
+ /**
+ * A built-in linear RGB color space. This space is based on the
+ * same RGB primaries as CS_sRGB, but has a linear tone reproduction curve.
+ */
+ public static final int CS_LINEAR_RGB = 1004;
+
+ /**
+ * The CIEXYZ conversion color space defined above.
+ */
+ public static final int CS_CIEXYZ = 1001;
+
+ /**
+ * The Photo YCC conversion color space.
+ */
+ public static final int CS_PYCC = 1002;
+
+ /**
+ * The built-in linear gray scale color space.
+ */
+ public static final int CS_GRAY = 1003;
+
+
+ /**
+ * Constructs a ColorSpace object given a color space type
+ * and the number of components.
+ * @param type one of the <CODE>ColorSpace</CODE> type constants
+ * @param numcomponents the number of components in the color space
+ */
+ protected ColorSpace (int type, int numcomponents) {
+ this.type = type;
+ this.numComponents = numcomponents;
+ }
+
+
+ /**
+ * Returns a ColorSpace representing one of the specific
+ * predefined color spaces.
+ * @param colorspace a specific color space identified by one of
+ * the predefined class constants (e.g. CS_sRGB, CS_LINEAR_RGB,
+ * CS_CIEXYZ, CS_GRAY, or CS_PYCC)
+ * @return the requested <CODE>ColorSpace</CODE> object
+ */
+ // NOTE: This method may be called by privileged threads.
+ // DO NOT INVOKE CLIENT CODE ON THIS THREAD!
+ public static ColorSpace getInstance (int colorspace)
+ {
+ ColorSpace theColorSpace;
+
+ switch (colorspace) {
+ case CS_sRGB:
+ synchronized(ColorSpace.class) {
+ if (sRGBspace == null) {
+ ICC_Profile theProfile = ICC_Profile.getInstance (CS_sRGB);
+ sRGBspace = new ICC_ColorSpace (theProfile);
+ }
+
+ theColorSpace = sRGBspace;
+ }
+ break;
+
+ case CS_CIEXYZ:
+ synchronized(ColorSpace.class) {
+ if (XYZspace == null) {
+ ICC_Profile theProfile =
+ ICC_Profile.getInstance (CS_CIEXYZ);
+ XYZspace = new ICC_ColorSpace (theProfile);
+ }
+
+ theColorSpace = XYZspace;
+ }
+ break;
+
+ case CS_PYCC:
+ synchronized(ColorSpace.class) {
+ if (PYCCspace == null) {
+ ICC_Profile theProfile = ICC_Profile.getInstance (CS_PYCC);
+ PYCCspace = new ICC_ColorSpace (theProfile);
+ }
+
+ theColorSpace = PYCCspace;
+ }
+ break;
+
+
+ case CS_GRAY:
+ synchronized(ColorSpace.class) {
+ if (GRAYspace == null) {
+ ICC_Profile theProfile = ICC_Profile.getInstance (CS_GRAY);
+ GRAYspace = new ICC_ColorSpace (theProfile);
+ /* to allow access from java.awt.ColorModel */
+ CMSManager.GRAYspace = GRAYspace;
+ }
+
+ theColorSpace = GRAYspace;
+ }
+ break;
+
+
+ case CS_LINEAR_RGB:
+ synchronized(ColorSpace.class) {
+ if (LINEAR_RGBspace == null) {
+ ICC_Profile theProfile =
+ ICC_Profile.getInstance(CS_LINEAR_RGB);
+ LINEAR_RGBspace = new ICC_ColorSpace (theProfile);
+ /* to allow access from java.awt.ColorModel */
+ CMSManager.LINEAR_RGBspace = LINEAR_RGBspace;
+ }
+
+ theColorSpace = LINEAR_RGBspace;
+ }
+ break;
+
+
+ default:
+ throw new IllegalArgumentException ("Unknown color space");
+ }
+
+ return theColorSpace;
+ }
+
+
+ /**
+ * Returns true if the ColorSpace is CS_sRGB.
+ * @return <CODE>true</CODE> if this is a <CODE>CS_sRGB</CODE> color
+ * space, <code>false</code> if it is not
+ */
+ public boolean isCS_sRGB () {
+ /* REMIND - make sure we know sRGBspace exists already */
+ return (this == sRGBspace);
+ }
+
+ /**
+ * Transforms a color value assumed to be in this ColorSpace
+ * into a value in the default CS_sRGB color space.
+ * <p>
+ * This method transforms color values using algorithms designed
+ * to produce the best perceptual match between input and output
+ * colors. In order to do colorimetric conversion of color values,
+ * you should use the <code>toCIEXYZ</code>
+ * method of this color space to first convert from the input
+ * color space to the CS_CIEXYZ color space, and then use the
+ * <code>fromCIEXYZ</code> method of the CS_sRGB color space to
+ * convert from CS_CIEXYZ to the output color space.
+ * See {@link #toCIEXYZ(float[]) toCIEXYZ} and
+ * {@link #fromCIEXYZ(float[]) fromCIEXYZ} for further information.
+ * <p>
+ * @param colorvalue a float array with length of at least the number
+ * of components in this ColorSpace
+ * @return a float array of length 3
+ * @throws ArrayIndexOutOfBoundsException if array length is not
+ * at least the number of components in this ColorSpace
+ */
+ public abstract float[] toRGB(float[] colorvalue);
+
+
+ /**
+ * Transforms a color value assumed to be in the default CS_sRGB
+ * color space into this ColorSpace.
+ * <p>
+ * This method transforms color values using algorithms designed
+ * to produce the best perceptual match between input and output
+ * colors. In order to do colorimetric conversion of color values,
+ * you should use the <code>toCIEXYZ</code>
+ * method of the CS_sRGB color space to first convert from the input
+ * color space to the CS_CIEXYZ color space, and then use the
+ * <code>fromCIEXYZ</code> method of this color space to
+ * convert from CS_CIEXYZ to the output color space.
+ * See {@link #toCIEXYZ(float[]) toCIEXYZ} and
+ * {@link #fromCIEXYZ(float[]) fromCIEXYZ} for further information.
+ * <p>
+ * @param rgbvalue a float array with length of at least 3
+ * @return a float array with length equal to the number of
+ * components in this ColorSpace
+ * @throws ArrayIndexOutOfBoundsException if array length is not
+ * at least 3
+ */
+ public abstract float[] fromRGB(float[] rgbvalue);
+
+
+ /**
+ * Transforms a color value assumed to be in this ColorSpace
+ * into the CS_CIEXYZ conversion color space.
+ * <p>
+ * This method transforms color values using relative colorimetry,
+ * as defined by the International Color Consortium standard. This
+ * means that the XYZ values returned by this method are represented
+ * relative to the D50 white point of the CS_CIEXYZ color space.
+ * This representation is useful in a two-step color conversion
+ * process in which colors are transformed from an input color
+ * space to CS_CIEXYZ and then to an output color space. This
+ * representation is not the same as the XYZ values that would
+ * be measured from the given color value by a colorimeter.
+ * A further transformation is necessary to compute the XYZ values
+ * that would be measured using current CIE recommended practices.
+ * See the {@link ICC_ColorSpace#toCIEXYZ(float[]) toCIEXYZ} method of
+ * <code>ICC_ColorSpace</code> for further information.
+ * <p>
+ * @param colorvalue a float array with length of at least the number
+ * of components in this ColorSpace
+ * @return a float array of length 3
+ * @throws ArrayIndexOutOfBoundsException if array length is not
+ * at least the number of components in this ColorSpace.
+ */
+ public abstract float[] toCIEXYZ(float[] colorvalue);
+
+
+ /**
+ * Transforms a color value assumed to be in the CS_CIEXYZ conversion
+ * color space into this ColorSpace.
+ * <p>
+ * This method transforms color values using relative colorimetry,
+ * as defined by the International Color Consortium standard. This
+ * means that the XYZ argument values taken by this method are represented
+ * relative to the D50 white point of the CS_CIEXYZ color space.
+ * This representation is useful in a two-step color conversion
+ * process in which colors are transformed from an input color
+ * space to CS_CIEXYZ and then to an output color space. The color
+ * values returned by this method are not those that would produce
+ * the XYZ value passed to the method when measured by a colorimeter.
+ * If you have XYZ values corresponding to measurements made using
+ * current CIE recommended practices, they must be converted to D50
+ * relative values before being passed to this method.
+ * See the {@link ICC_ColorSpace#fromCIEXYZ(float[]) fromCIEXYZ} method of
+ * <code>ICC_ColorSpace</code> for further information.
+ * <p>
+ * @param colorvalue a float array with length of at least 3
+ * @return a float array with length equal to the number of
+ * components in this ColorSpace
+ * @throws ArrayIndexOutOfBoundsException if array length is not
+ * at least 3
+ */
+ public abstract float[] fromCIEXYZ(float[] colorvalue);
+
+ /**
+ * Returns the color space type of this ColorSpace (for example
+ * TYPE_RGB, TYPE_XYZ, ...). The type defines the
+ * number of components of the color space and the interpretation,
+ * e.g. TYPE_RGB identifies a color space with three components - red,
+ * green, and blue. It does not define the particular color
+ * characteristics of the space, e.g. the chromaticities of the
+ * primaries.
+ *
+ * @return the type constant that represents the type of this
+ * <CODE>ColorSpace</CODE>
+ */
+ public int getType() {
+ return type;
+ }
+
+ /**
+ * Returns the number of components of this ColorSpace.
+ * @return The number of components in this <CODE>ColorSpace</CODE>.
+ */
+ public int getNumComponents() {
+ return numComponents;
+ }
+
+ /**
+ * Returns the name of the component given the component index.
+ *
+ * @param idx the component index
+ * @return the name of the component at the specified index
+ * @throws IllegalArgumentException if <code>idx</code> is
+ * less than 0 or greater than numComponents - 1
+ */
+ public String getName (int idx) {
+ /* REMIND - handle common cases here */
+ if ((idx < 0) || (idx > numComponents - 1)) {
+ throw new IllegalArgumentException(
+ "Component index out of range: " + idx);
+ }
+
+ if (compName == null) {
+ switch (type) {
+ case ColorSpace.TYPE_XYZ:
+ compName = new String[] {"X", "Y", "Z"};
+ break;
+ case ColorSpace.TYPE_Lab:
+ compName = new String[] {"L", "a", "b"};
+ break;
+ case ColorSpace.TYPE_Luv:
+ compName = new String[] {"L", "u", "v"};
+ break;
+ case ColorSpace.TYPE_YCbCr:
+ compName = new String[] {"Y", "Cb", "Cr"};
+ break;
+ case ColorSpace.TYPE_Yxy:
+ compName = new String[] {"Y", "x", "y"};
+ break;
+ case ColorSpace.TYPE_RGB:
+ compName = new String[] {"Red", "Green", "Blue"};
+ break;
+ case ColorSpace.TYPE_GRAY:
+ compName = new String[] {"Gray"};
+ break;
+ case ColorSpace.TYPE_HSV:
+ compName = new String[] {"Hue", "Saturation", "Value"};
+ break;
+ case ColorSpace.TYPE_HLS:
+ compName = new String[] {"Hue", "Lightness",
+ "Saturation"};
+ break;
+ case ColorSpace.TYPE_CMYK:
+ compName = new String[] {"Cyan", "Magenta", "Yellow",
+ "Black"};
+ break;
+ case ColorSpace.TYPE_CMY:
+ compName = new String[] {"Cyan", "Magenta", "Yellow"};
+ break;
+ default:
+ String [] tmp = new String[numComponents];
+ for (int i = 0; i < tmp.length; i++) {
+ tmp[i] = "Unnamed color component(" + i + ")";
+ }
+ compName = tmp;
+ }
+ }
+ return compName[idx];
+ }
+
+ /**
+ * Returns the minimum normalized color component value for the
+ * specified component. The default implementation in this abstract
+ * class returns 0.0 for all components. Subclasses should override
+ * this method if necessary.
+ *
+ * @param component the component index
+ * @return the minimum normalized component value
+ * @throws IllegalArgumentException if component is less than 0 or
+ * greater than numComponents - 1
+ * @since 1.4
+ */
+ public float getMinValue(int component) {
+ if ((component < 0) || (component > numComponents - 1)) {
+ throw new IllegalArgumentException(
+ "Component index out of range: " + component);
+ }
+ return 0.0f;
+ }
+
+ /**
+ * Returns the maximum normalized color component value for the
+ * specified component. The default implementation in this abstract
+ * class returns 1.0 for all components. Subclasses should override
+ * this method if necessary.
+ *
+ * @param component the component index
+ * @return the maximum normalized component value
+ * @throws IllegalArgumentException if component is less than 0 or
+ * greater than numComponents - 1
+ * @since 1.4
+ */
+ public float getMaxValue(int component) {
+ if ((component < 0) || (component > numComponents - 1)) {
+ throw new IllegalArgumentException(
+ "Component index out of range: " + component);
+ }
+ return 1.0f;
+ }
+
+ /* Returns true if cspace is the XYZspace.
+ */
+ static boolean isCS_CIEXYZ(ColorSpace cspace) {
+ return (cspace == XYZspace);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/awt/color/ICC_ColorSpace.java Thu Apr 10 16:28:45 2008 -0700
@@ -0,0 +1,616 @@
+/*
+ * Portions Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/**********************************************************************
+ **********************************************************************
+ **********************************************************************
+ *** COPYRIGHT (c) Eastman Kodak Company, 1997 ***
+ *** As an unpublished work pursuant to Title 17 of the United ***
+ *** States Code. All rights reserved. ***
+ **********************************************************************
+ **********************************************************************
+ **********************************************************************/
+
+package java.awt.color;
+
+import sun.java2d.cmm.ColorTransform;
+import sun.java2d.cmm.CMSManager;
+import sun.java2d.cmm.PCMM;
+
+
+/**
+ *
+ * The ICC_ColorSpace class is an implementation of the abstract
+ * ColorSpace class. This representation of
+ * device independent and device dependent color spaces is based on the
+ * International Color Consortium Specification ICC.1:2001-12, File Format for
+ * Color Profiles (see <A href="http://www.color.org">http://www.color.org</A>).
+ * <p>
+ * Typically, a Color or ColorModel would be associated with an ICC
+ * Profile which is either an input, display, or output profile (see
+ * the ICC specification). There are other types of ICC Profiles, e.g.
+ * abstract profiles, device link profiles, and named color profiles,
+ * which do not contain information appropriate for representing the color
+ * space of a color, image, or device (see ICC_Profile).
+ * Attempting to create an ICC_ColorSpace object from an inappropriate ICC
+ * Profile is an error.
+ * <p>
+ * ICC Profiles represent transformations from the color space of
+ * the profile (e.g. a monitor) to a Profile Connection Space (PCS).
+ * Profiles of interest for tagging images or colors have a
+ * PCS which is one of the device independent
+ * spaces (one CIEXYZ space and two CIELab spaces) defined in the
+ * ICC Profile Format Specification. Most profiles of interest
+ * either have invertible transformations or explicitly specify
+ * transformations going both directions. Should an ICC_ColorSpace
+ * object be used in a way requiring a conversion from PCS to
+ * the profile's native space and there is inadequate data to
+ * correctly perform the conversion, the ICC_ColorSpace object will
+ * produce output in the specified type of color space (e.g. TYPE_RGB,
+ * TYPE_CMYK, etc.), but the specific color values of the output data
+ * will be undefined.
+ * <p>
+ * The details of this class are not important for simple applets,
+ * which draw in a default color space or manipulate and display
+ * imported images with a known color space. At most, such applets
+ * would need to get one of the default color spaces via
+ * ColorSpace.getInstance().
+ * <p>
+ * @see ColorSpace
+ * @see ICC_Profile
+ */
+
+
+
+public class ICC_ColorSpace extends ColorSpace {
+
+ static final long serialVersionUID = 3455889114070431483L;
+
+ private ICC_Profile thisProfile;
+ private float[] minVal;
+ private float[] maxVal;
+ private float[] diffMinMax;
+ private float[] invDiffMinMax;
+ private boolean needScaleInit = true;
+
+ // {to,from}{RGB,CIEXYZ} methods create and cache these when needed
+ private transient ColorTransform this2srgb;
+ private transient ColorTransform srgb2this;
+ private transient ColorTransform this2xyz;
+ private transient ColorTransform xyz2this;
+
+
+ /**
+ * Constructs a new ICC_ColorSpace from an ICC_Profile object.
+ * @param profile the specified ICC_Profile object
+ * @exception IllegalArgumentException if profile is inappropriate for
+ * representing a ColorSpace.
+ */
+ public ICC_ColorSpace (ICC_Profile profile) {
+ super (profile.getColorSpaceType(), profile.getNumComponents());
+
+ int profileClass = profile.getProfileClass();
+
+ /* REMIND - is NAMEDCOLOR OK? */
+ if ((profileClass != ICC_Profile.CLASS_INPUT) &&
+ (profileClass != ICC_Profile.CLASS_DISPLAY) &&
+ (profileClass != ICC_Profile.CLASS_OUTPUT) &&
+ (profileClass != ICC_Profile.CLASS_COLORSPACECONVERSION) &&
+ (profileClass != ICC_Profile.CLASS_NAMEDCOLOR) &&
+ (profileClass != ICC_Profile.CLASS_ABSTRACT)) {
+ throw new IllegalArgumentException("Invalid profile type");
+ }
+
+ thisProfile = profile;
+ setMinMax();
+ }
+
+ /**
+ * Returns the ICC_Profile for this ICC_ColorSpace.
+ * @return the ICC_Profile for this ICC_ColorSpace.
+ */
+ public ICC_Profile getProfile() {
+ return thisProfile;
+ }
+
+ /**
+ * Transforms a color value assumed to be in this ColorSpace
+ * into a value in the default CS_sRGB color space.
+ * <p>
+ * This method transforms color values using algorithms designed
+ * to produce the best perceptual match between input and output
+ * colors. In order to do colorimetric conversion of color values,
+ * you should use the <code>toCIEXYZ</code>
+ * method of this color space to first convert from the input
+ * color space to the CS_CIEXYZ color space, and then use the
+ * <code>fromCIEXYZ</code> method of the CS_sRGB color space to
+ * convert from CS_CIEXYZ to the output color space.
+ * See {@link #toCIEXYZ(float[]) toCIEXYZ} and
+ * {@link #fromCIEXYZ(float[]) fromCIEXYZ} for further information.
+ * <p>
+ * @param colorvalue a float array with length of at least the number
+ * of components in this ColorSpace.
+ * @return a float array of length 3.
+ * @throws ArrayIndexOutOfBoundsException if array length is not
+ * at least the number of components in this ColorSpace.
+ */
+ public float[] toRGB (float[] colorvalue) {
+
+ if (this2srgb == null) {
+ ColorTransform[] transformList = new ColorTransform [2];
+ ICC_ColorSpace srgbCS =
+ (ICC_ColorSpace) ColorSpace.getInstance (CS_sRGB);
+ PCMM mdl = CMSManager.getModule();
+ transformList[0] = mdl.createTransform(
+ thisProfile, ColorTransform.Any, ColorTransform.In);
+ transformList[1] = mdl.createTransform(
+ srgbCS.getProfile(), ColorTransform.Any, ColorTransform.Out);
+ this2srgb = mdl.createTransform(transformList);
+ if (needScaleInit) {
+ setComponentScaling();
+ }
+ }
+
+ int nc = this.getNumComponents();
+ short tmp[] = new short[nc];
+ for (int i = 0; i < nc; i++) {
+ tmp[i] = (short)
+ ((colorvalue[i] - minVal[i]) * invDiffMinMax[i] + 0.5f);
+ }
+ tmp = this2srgb.colorConvert(tmp, null);
+ float[] result = new float [3];
+ for (int i = 0; i < 3; i++) {
+ result[i] = ((float) (tmp[i] & 0xffff)) / 65535.0f;
+ }
+ return result;
+ }
+
+ /**
+ * Transforms a color value assumed to be in the default CS_sRGB
+ * color space into this ColorSpace.
+ * <p>
+ * This method transforms color values using algorithms designed
+ * to produce the best perceptual match between input and output
+ * colors. In order to do colorimetric conversion of color values,
+ * you should use the <code>toCIEXYZ</code>
+ * method of the CS_sRGB color space to first convert from the input
+ * color space to the CS_CIEXYZ color space, and then use the
+ * <code>fromCIEXYZ</code> method of this color space to
+ * convert from CS_CIEXYZ to the output color space.
+ * See {@link #toCIEXYZ(float[]) toCIEXYZ} and
+ * {@link #fromCIEXYZ(float[]) fromCIEXYZ} for further information.
+ * <p>
+ * @param rgbvalue a float array with length of at least 3.
+ * @return a float array with length equal to the number of
+ * components in this ColorSpace.
+ * @throws ArrayIndexOutOfBoundsException if array length is not
+ * at least 3.
+ */
+ public float[] fromRGB(float[] rgbvalue) {
+
+ if (srgb2this == null) {
+ ColorTransform[] transformList = new ColorTransform [2];
+ ICC_ColorSpace srgbCS =
+ (ICC_ColorSpace) ColorSpace.getInstance (CS_sRGB);
+ PCMM mdl = CMSManager.getModule();
+ transformList[0] = mdl.createTransform(
+ srgbCS.getProfile(), ColorTransform.Any, ColorTransform.In);
+ transformList[1] = mdl.createTransform(
+ thisProfile, ColorTransform.Any, ColorTransform.Out);
+ srgb2this = mdl.createTransform(transformList);
+ if (needScaleInit) {
+ setComponentScaling();
+ }
+ }
+
+ short tmp[] = new short[3];
+ for (int i = 0; i < 3; i++) {
+ tmp[i] = (short) ((rgbvalue[i] * 65535.0f) + 0.5f);
+ }
+ tmp = srgb2this.colorConvert(tmp, null);
+ int nc = this.getNumComponents();
+ float[] result = new float [nc];
+ for (int i = 0; i < nc; i++) {
+ result[i] = (((float) (tmp[i] & 0xffff)) / 65535.0f) *
+ diffMinMax[i] + minVal[i];
+ }
+ return result;
+ }
+
+
+ /**
+ * Transforms a color value assumed to be in this ColorSpace
+ * into the CS_CIEXYZ conversion color space.
+ * <p>
+ * This method transforms color values using relative colorimetry,
+ * as defined by the ICC Specification. This
+ * means that the XYZ values returned by this method are represented
+ * relative to the D50 white point of the CS_CIEXYZ color space.
+ * This representation is useful in a two-step color conversion
+ * process in which colors are transformed from an input color
+ * space to CS_CIEXYZ and then to an output color space. This
+ * representation is not the same as the XYZ values that would
+ * be measured from the given color value by a colorimeter.
+ * A further transformation is necessary to compute the XYZ values
+ * that would be measured using current CIE recommended practices.
+ * The paragraphs below explain this in more detail.
+ * <p>
+ * The ICC standard uses a device independent color space (DICS) as the
+ * mechanism for converting color from one device to another device. In
+ * this architecture, colors are converted from the source device's color
+ * space to the ICC DICS and then from the ICC DICS to the destination
+ * device's color space. The ICC standard defines device profiles which
+ * contain transforms which will convert between a device's color space
+ * and the ICC DICS. The overall conversion of colors from a source
+ * device to colors of a destination device is done by connecting the
+ * device-to-DICS transform of the profile for the source device to the
+ * DICS-to-device transform of the profile for the destination device.
+ * For this reason, the ICC DICS is commonly referred to as the profile
+ * connection space (PCS). The color space used in the methods
+ * toCIEXYZ and fromCIEXYZ is the CIEXYZ PCS defined by the ICC
+ * Specification. This is also the color space represented by
+ * ColorSpace.CS_CIEXYZ.
+ * <p>
+ * The XYZ values of a color are often represented as relative to some
+ * white point, so the actual meaning of the XYZ values cannot be known
+ * without knowing the white point of those values. This is known as
+ * relative colorimetry. The PCS uses a white point of D50, so the XYZ
+ * values of the PCS are relative to D50. For example, white in the PCS
+ * will have the XYZ values of D50, which is defined to be X=.9642,
+ * Y=1.000, and Z=0.8249. This white point is commonly used for graphic
+ * arts applications, but others are often used in other applications.
+ * <p>
+ * To quantify the color characteristics of a device such as a printer
+ * or monitor, measurements of XYZ values for particular device colors
+ * are typically made. For purposes of this discussion, the term
+ * device XYZ values is used to mean the XYZ values that would be
+ * measured from device colors using current CIE recommended practices.
+ * <p>
+ * Converting between device XYZ values and the PCS XYZ values returned
+ * by this method corresponds to converting between the device's color
+ * space, as represented by CIE colorimetric values, and the PCS. There
+ * are many factors involved in this process, some of which are quite
+ * subtle. The most important, however, is the adjustment made to account
+ * for differences between the device's white point and the white point of
+ * the PCS. There are many techniques for doing this and it is the
+ * subject of much current research and controversy. Some commonly used
+ * methods are XYZ scaling, the von Kries transform, and the Bradford
+ * transform. The proper method to use depends upon each particular
+ * application.
+ * <p>
+ * The simplest method is XYZ scaling. In this method each device XYZ
+ * value is converted to a PCS XYZ value by multiplying it by the ratio
+ * of the PCS white point (D50) to the device white point.
+ * <pre>
+ *
+ * Xd, Yd, Zd are the device XYZ values
+ * Xdw, Ydw, Zdw are the device XYZ white point values
+ * Xp, Yp, Zp are the PCS XYZ values
+ * Xd50, Yd50, Zd50 are the PCS XYZ white point values
+ *
+ * Xp = Xd * (Xd50 / Xdw)
+ * Yp = Yd * (Yd50 / Ydw)
+ * Zp = Zd * (Zd50 / Zdw)
+ *
+ * </pre>
+ * <p>
+ * Conversion from the PCS to the device would be done by inverting these
+ * equations:
+ * <pre>
+ *
+ * Xd = Xp * (Xdw / Xd50)
+ * Yd = Yp * (Ydw / Yd50)
+ * Zd = Zp * (Zdw / Zd50)
+ *
+ * </pre>
+ * <p>
+ * Note that the media white point tag in an ICC profile is not the same
+ * as the device white point. The media white point tag is expressed in
+ * PCS values and is used to represent the difference between the XYZ of
+ * device illuminant and the XYZ of the device media when measured under
+ * that illuminant. The device white point is expressed as the device
+ * XYZ values corresponding to white displayed on the device. For
+ * example, displaying the RGB color (1.0, 1.0, 1.0) on an sRGB device
+ * will result in a measured device XYZ value of D65. This will not
+ * be the same as the media white point tag XYZ value in the ICC
+ * profile for an sRGB device.
+ * <p>
+ * @param colorvalue a float array with length of at least the number
+ * of components in this ColorSpace.
+ * @return a float array of length 3.
+ * @throws ArrayIndexOutOfBoundsException if array length is not
+ * at least the number of components in this ColorSpace.
+ */
+ public float[] toCIEXYZ(float[] colorvalue) {
+
+ if (this2xyz == null) {
+ ColorTransform[] transformList = new ColorTransform [2];
+ ICC_ColorSpace xyzCS =
+ (ICC_ColorSpace) ColorSpace.getInstance (CS_CIEXYZ);
+ PCMM mdl = CMSManager.getModule();
+ try {
+ transformList[0] = mdl.createTransform(
+ thisProfile, ICC_Profile.icRelativeColorimetric,
+ ColorTransform.In);
+ } catch (CMMException e) {
+ transformList[0] = mdl.createTransform(
+ thisProfile, ColorTransform.Any, ColorTransform.In);
+ }
+ transformList[1] = mdl.createTransform(
+ xyzCS.getProfile(), ColorTransform.Any, ColorTransform.Out);
+ this2xyz = mdl.createTransform (transformList);
+ if (needScaleInit) {
+ setComponentScaling();
+ }
+ }
+
+ int nc = this.getNumComponents();
+ short tmp[] = new short[nc];
+ for (int i = 0; i < nc; i++) {
+ tmp[i] = (short)
+ ((colorvalue[i] - minVal[i]) * invDiffMinMax[i] + 0.5f);
+ }
+ tmp = this2xyz.colorConvert(tmp, null);
+ float ALMOST_TWO = 1.0f + (32767.0f / 32768.0f);
+ // For CIEXYZ, min = 0.0, max = ALMOST_TWO for all components
+ float[] result = new float [3];
+ for (int i = 0; i < 3; i++) {
+ result[i] = (((float) (tmp[i] & 0xffff)) / 65535.0f) * ALMOST_TWO;
+ }
+ return result;
+ }
+
+
+ /**
+ * Transforms a color value assumed to be in the CS_CIEXYZ conversion
+ * color space into this ColorSpace.
+ * <p>
+ * This method transforms color values using relative colorimetry,
+ * as defined by the ICC Specification. This
+ * means that the XYZ argument values taken by this method are represented
+ * relative to the D50 white point of the CS_CIEXYZ color space.
+ * This representation is useful in a two-step color conversion
+ * process in which colors are transformed from an input color
+ * space to CS_CIEXYZ and then to an output color space. The color
+ * values returned by this method are not those that would produce
+ * the XYZ value passed to the method when measured by a colorimeter.
+ * If you have XYZ values corresponding to measurements made using
+ * current CIE recommended practices, they must be converted to D50
+ * relative values before being passed to this method.
+ * The paragraphs below explain this in more detail.
+ * <p>
+ * The ICC standard uses a device independent color space (DICS) as the
+ * mechanism for converting color from one device to another device. In
+ * this architecture, colors are converted from the source device's color
+ * space to the ICC DICS and then from the ICC DICS to the destination
+ * device's color space. The ICC standard defines device profiles which
+ * contain transforms which will convert between a device's color space
+ * and the ICC DICS. The overall conversion of colors from a source
+ * device to colors of a destination device is done by connecting the
+ * device-to-DICS transform of the profile for the source device to the
+ * DICS-to-device transform of the profile for the destination device.
+ * For this reason, the ICC DICS is commonly referred to as the profile
+ * connection space (PCS). The color space used in the methods
+ * toCIEXYZ and fromCIEXYZ is the CIEXYZ PCS defined by the ICC
+ * Specification. This is also the color space represented by
+ * ColorSpace.CS_CIEXYZ.
+ * <p>
+ * The XYZ values of a color are often represented as relative to some
+ * white point, so the actual meaning of the XYZ values cannot be known
+ * without knowing the white point of those values. This is known as
+ * relative colorimetry. The PCS uses a white point of D50, so the XYZ
+ * values of the PCS are relative to D50. For example, white in the PCS
+ * will have the XYZ values of D50, which is defined to be X=.9642,
+ * Y=1.000, and Z=0.8249. This white point is commonly used for graphic
+ * arts applications, but others are often used in other applications.
+ * <p>
+ * To quantify the color characteristics of a device such as a printer
+ * or monitor, measurements of XYZ values for particular device colors
+ * are typically made. For purposes of this discussion, the term
+ * device XYZ values is used to mean the XYZ values that would be
+ * measured from device colors using current CIE recommended practices.
+ * <p>
+ * Converting between device XYZ values and the PCS XYZ values taken as
+ * arguments by this method corresponds to converting between the device's
+ * color space, as represented by CIE colorimetric values, and the PCS.
+ * There are many factors involved in this process, some of which are quite
+ * subtle. The most important, however, is the adjustment made to account
+ * for differences between the device's white point and the white point of
+ * the PCS. There are many techniques for doing this and it is the
+ * subject of much current research and controversy. Some commonly used
+ * methods are XYZ scaling, the von Kries transform, and the Bradford
+ * transform. The proper method to use depends upon each particular
+ * application.
+ * <p>
+ * The simplest method is XYZ scaling. In this method each device XYZ
+ * value is converted to a PCS XYZ value by multiplying it by the ratio
+ * of the PCS white point (D50) to the device white point.
+ * <pre>
+ *
+ * Xd, Yd, Zd are the device XYZ values
+ * Xdw, Ydw, Zdw are the device XYZ white point values
+ * Xp, Yp, Zp are the PCS XYZ values
+ * Xd50, Yd50, Zd50 are the PCS XYZ white point values
+ *
+ * Xp = Xd * (Xd50 / Xdw)
+ * Yp = Yd * (Yd50 / Ydw)
+ * Zp = Zd * (Zd50 / Zdw)
+ *
+ * </pre>
+ * <p>
+ * Conversion from the PCS to the device would be done by inverting these
+ * equations:
+ * <pre>
+ *
+ * Xd = Xp * (Xdw / Xd50)
+ * Yd = Yp * (Ydw / Yd50)
+ * Zd = Zp * (Zdw / Zd50)
+ *
+ * </pre>
+ * <p>
+ * Note that the media white point tag in an ICC profile is not the same
+ * as the device white point. The media white point tag is expressed in
+ * PCS values and is used to represent the difference between the XYZ of
+ * device illuminant and the XYZ of the device media when measured under
+ * that illuminant. The device white point is expressed as the device
+ * XYZ values corresponding to white displayed on the device. For
+ * example, displaying the RGB color (1.0, 1.0, 1.0) on an sRGB device
+ * will result in a measured device XYZ value of D65. This will not
+ * be the same as the media white point tag XYZ value in the ICC
+ * profile for an sRGB device.
+ * <p>
+ * <p>
+ * @param colorvalue a float array with length of at least 3.
+ * @return a float array with length equal to the number of
+ * components in this ColorSpace.
+ * @throws ArrayIndexOutOfBoundsException if array length is not
+ * at least 3.
+ */
+ public float[] fromCIEXYZ(float[] colorvalue) {
+
+ if (xyz2this == null) {
+ ColorTransform[] transformList = new ColorTransform [2];
+ ICC_ColorSpace xyzCS =
+ (ICC_ColorSpace) ColorSpace.getInstance (CS_CIEXYZ);
+ PCMM mdl = CMSManager.getModule();
+ transformList[0] = mdl.createTransform (
+ xyzCS.getProfile(), ColorTransform.Any, ColorTransform.In);
+ try {
+ transformList[1] = mdl.createTransform(
+ thisProfile, ICC_Profile.icRelativeColorimetric,
+ ColorTransform.Out);
+ } catch (CMMException e) {
+ transformList[1] = CMSManager.getModule().createTransform(
+ thisProfile, ColorTransform.Any, ColorTransform.Out);
+ }
+ xyz2this = mdl.createTransform(transformList);
+ if (needScaleInit) {
+ setComponentScaling();
+ }
+ }
+
+ short tmp[] = new short[3];
+ float ALMOST_TWO = 1.0f + (32767.0f / 32768.0f);
+ float factor = 65535.0f / ALMOST_TWO;
+ // For CIEXYZ, min = 0.0, max = ALMOST_TWO for all components
+ for (int i = 0; i < 3; i++) {
+ tmp[i] = (short) ((colorvalue[i] * factor) + 0.5f);
+ }
+ tmp = xyz2this.colorConvert(tmp, null);
+ int nc = this.getNumComponents();
+ float[] result = new float [nc];
+ for (int i = 0; i < nc; i++) {
+ result[i] = (((float) (tmp[i] & 0xffff)) / 65535.0f) *
+ diffMinMax[i] + minVal[i];
+ }
+ return result;
+ }
+
+ /**
+ * Returns the minimum normalized color component value for the
+ * specified component. For TYPE_XYZ spaces, this method returns
+ * minimum values of 0.0 for all components. For TYPE_Lab spaces,
+ * this method returns 0.0 for L and -128.0 for a and b components.
+ * This is consistent with the encoding of the XYZ and Lab Profile
+ * Connection Spaces in the ICC specification. For all other types, this
+ * method returns 0.0 for all components. When using an ICC_ColorSpace
+ * with a profile that requires different minimum component values,
+ * it is necessary to subclass this class and override this method.
+ * @param component The component index.
+ * @return The minimum normalized component value.
+ * @throws IllegalArgumentException if component is less than 0 or
+ * greater than numComponents - 1.
+ * @since 1.4
+ */
+ public float getMinValue(int component) {
+ if ((component < 0) || (component > this.getNumComponents() - 1)) {
+ throw new IllegalArgumentException(
+ "Component index out of range: + component");
+ }
+ return minVal[component];
+ }
+
+ /**
+ * Returns the maximum normalized color component value for the
+ * specified component. For TYPE_XYZ spaces, this method returns
+ * maximum values of 1.0 + (32767.0 / 32768.0) for all components.
+ * For TYPE_Lab spaces,
+ * this method returns 100.0 for L and 127.0 for a and b components.
+ * This is consistent with the encoding of the XYZ and Lab Profile
+ * Connection Spaces in the ICC specification. For all other types, this
+ * method returns 1.0 for all components. When using an ICC_ColorSpace
+ * with a profile that requires different maximum component values,
+ * it is necessary to subclass this class and override this method.
+ * @param component The component index.
+ * @return The maximum normalized component value.
+ * @throws IllegalArgumentException if component is less than 0 or
+ * greater than numComponents - 1.
+ * @since 1.4
+ */
+ public float getMaxValue(int component) {
+ if ((component < 0) || (component > this.getNumComponents() - 1)) {
+ throw new IllegalArgumentException(
+ "Component index out of range: + component");
+ }
+ return maxVal[component];
+ }
+
+ private void setMinMax() {
+ int nc = this.getNumComponents();
+ int type = this.getType();
+ minVal = new float[nc];
+ maxVal = new float[nc];
+ if (type == ColorSpace.TYPE_Lab) {
+ minVal[0] = 0.0f; // L
+ maxVal[0] = 100.0f;
+ minVal[1] = -128.0f; // a
+ maxVal[1] = 127.0f;
+ minVal[2] = -128.0f; // b
+ maxVal[2] = 127.0f;
+ } else if (type == ColorSpace.TYPE_XYZ) {
+ minVal[0] = minVal[1] = minVal[2] = 0.0f; // X, Y, Z
+ maxVal[0] = maxVal[1] = maxVal[2] = 1.0f + (32767.0f/ 32768.0f);
+ } else {
+ for (int i = 0; i < nc; i++) {
+ minVal[i] = 0.0f;
+ maxVal[i] = 1.0f;
+ }
+ }
+ }
+
+ private void setComponentScaling() {
+ int nc = this.getNumComponents();
+ diffMinMax = new float[nc];
+ invDiffMinMax = new float[nc];
+ for (int i = 0; i < nc; i++) {
+ minVal[i] = this.getMinValue(i); // in case getMinVal is overridden
+ maxVal[i] = this.getMaxValue(i); // in case getMaxVal is overridden
+ diffMinMax[i] = maxVal[i] - minVal[i];
+ invDiffMinMax[i] = 65535.0f / diffMinMax[i];
+ }
+ needScaleInit = false;
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/awt/color/ICC_Profile.java Thu Apr 10 16:28:45 2008 -0700
@@ -0,0 +1,2003 @@
+/*
+ * Portions Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/**********************************************************************
+ **********************************************************************
+ **********************************************************************
+ *** COPYRIGHT (c) Eastman Kodak Company, 1997 ***
+ *** As an unpublished work pursuant to Title 17 of the United ***
+ *** States Code. All rights reserved. ***
+ **********************************************************************
+ **********************************************************************
+ **********************************************************************/
+
+package java.awt.color;
+
+import sun.java2d.cmm.PCMM;
+import sun.java2d.cmm.CMSManager;
+import sun.java2d.cmm.ProfileDeferralMgr;
+import sun.java2d.cmm.ProfileDeferralInfo;
+import sun.java2d.cmm.ProfileActivator;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamException;
+import java.io.OutputStream;
+import java.io.Serializable;
+
+import java.util.StringTokenizer;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * A representation of color profile data for device independent and
+ * device dependent color spaces based on the International Color
+ * Consortium Specification ICC.1:2001-12, File Format for Color Profiles,
+ * (see <A href="http://www.color.org"> http://www.color.org</A>).
+ * <p>
+ * An ICC_ColorSpace object can be constructed from an appropriate
+ * ICC_Profile.
+ * Typically, an ICC_ColorSpace would be associated with an ICC
+ * Profile which is either an input, display, or output profile (see
+ * the ICC specification). There are also device link, abstract,
+ * color space conversion, and named color profiles. These are less
+ * useful for tagging a color or image, but are useful for other
+ * purposes (in particular device link profiles can provide improved
+ * performance for converting from one device's color space to
+ * another's).
+ * <p>
+ * ICC Profiles represent transformations from the color space of
+ * the profile (e.g. a monitor) to a Profile Connection Space (PCS).
+ * Profiles of interest for tagging images or colors have a PCS
+ * which is one of the two specific device independent
+ * spaces (one CIEXYZ space and one CIELab space) defined in the
+ * ICC Profile Format Specification. Most profiles of interest
+ * either have invertible transformations or explicitly specify
+ * transformations going both directions.
+ * <p>
+ * @see ICC_ColorSpace
+ */
+
+
+public class ICC_Profile implements Serializable {
+
+ private static final long serialVersionUID = -3938515861990936766L;
+
+ transient long ID;
+
+ private transient ProfileDeferralInfo deferralInfo;
+ private transient ProfileActivator profileActivator;
+
+ // Registry of singleton profile objects for specific color spaces
+ // defined in the ColorSpace class (e.g. CS_sRGB), see
+ // getInstance(int cspace) factory method.
+ private static ICC_Profile sRGBprofile;
+ private static ICC_Profile XYZprofile;
+ private static ICC_Profile PYCCprofile;
+ private static ICC_Profile GRAYprofile;
+ private static ICC_Profile LINEAR_RGBprofile;
+
+
+ /**
+ * Profile class is input.
+ */
+ public static final int CLASS_INPUT = 0;
+
+ /**
+ * Profile class is display.
+ */
+ public static final int CLASS_DISPLAY = 1;
+
+ /**
+ * Profile class is output.
+ */
+ public static final int CLASS_OUTPUT = 2;
+
+ /**
+ * Profile class is device link.
+ */
+ public static final int CLASS_DEVICELINK = 3;
+
+ /**
+ * Profile class is color space conversion.
+ */
+ public static final int CLASS_COLORSPACECONVERSION = 4;
+
+ /**
+ * Profile class is abstract.
+ */
+ public static final int CLASS_ABSTRACT = 5;
+
+ /**
+ * Profile class is named color.
+ */
+ public static final int CLASS_NAMEDCOLOR = 6;
+
+
+ /**
+ * ICC Profile Color Space Type Signature: 'XYZ '.
+ */
+ public static final int icSigXYZData = 0x58595A20; /* 'XYZ ' */
+
+ /**
+ * ICC Profile Color Space Type Signature: 'Lab '.
+ */
+ public static final int icSigLabData = 0x4C616220; /* 'Lab ' */
+
+ /**
+ * ICC Profile Color Space Type Signature: 'Luv '.
+ */
+ public static final int icSigLuvData = 0x4C757620; /* 'Luv ' */
+
+ /**
+ * ICC Profile Color Space Type Signature: 'YCbr'.
+ */
+ public static final int icSigYCbCrData = 0x59436272; /* 'YCbr' */
+
+ /**
+ * ICC Profile Color Space Type Signature: 'Yxy '.
+ */
+ public static final int icSigYxyData = 0x59787920; /* 'Yxy ' */
+
+ /**
+ * ICC Profile Color Space Type Signature: 'RGB '.
+ */
+ public static final int icSigRgbData = 0x52474220; /* 'RGB ' */
+
+ /**
+ * ICC Profile Color Space Type Signature: 'GRAY'.
+ */
+ public static final int icSigGrayData = 0x47524159; /* 'GRAY' */
+
+ /**
+ * ICC Profile Color Space Type Signature: 'HSV'.
+ */
+ public static final int icSigHsvData = 0x48535620; /* 'HSV ' */
+
+ /**
+ * ICC Profile Color Space Type Signature: 'HLS'.
+ */
+ public static final int icSigHlsData = 0x484C5320; /* 'HLS ' */
+
+ /**
+ * ICC Profile Color Space Type Signature: 'CMYK'.
+ */
+ public static final int icSigCmykData = 0x434D594B; /* 'CMYK' */
+
+ /**
+ * ICC Profile Color Space Type Signature: 'CMY '.
+ */
+ public static final int icSigCmyData = 0x434D5920; /* 'CMY ' */
+
+ /**
+ * ICC Profile Color Space Type Signature: '2CLR'.
+ */
+ public static final int icSigSpace2CLR = 0x32434C52; /* '2CLR' */
+
+ /**
+ * ICC Profile Color Space Type Signature: '3CLR'.
+ */
+ public static final int icSigSpace3CLR = 0x33434C52; /* '3CLR' */
+
+ /**
+ * ICC Profile Color Space Type Signature: '4CLR'.
+ */
+ public static final int icSigSpace4CLR = 0x34434C52; /* '4CLR' */
+
+ /**
+ * ICC Profile Color Space Type Signature: '5CLR'.
+ */
+ public static final int icSigSpace5CLR = 0x35434C52; /* '5CLR' */
+
+ /**
+ * ICC Profile Color Space Type Signature: '6CLR'.
+ */
+ public static final int icSigSpace6CLR = 0x36434C52; /* '6CLR' */
+
+ /**
+ * ICC Profile Color Space Type Signature: '7CLR'.
+ */
+ public static final int icSigSpace7CLR = 0x37434C52; /* '7CLR' */
+
+ /**
+ * ICC Profile Color Space Type Signature: '8CLR'.
+ */
+ public static final int icSigSpace8CLR = 0x38434C52; /* '8CLR' */
+
+ /**
+ * ICC Profile Color Space Type Signature: '9CLR'.
+ */
+ public static final int icSigSpace9CLR = 0x39434C52; /* '9CLR' */
+
+ /**
+ * ICC Profile Color Space Type Signature: 'ACLR'.
+ */
+ public static final int icSigSpaceACLR = 0x41434C52; /* 'ACLR' */
+
+ /**
+ * ICC Profile Color Space Type Signature: 'BCLR'.
+ */
+ public static final int icSigSpaceBCLR = 0x42434C52; /* 'BCLR' */
+
+ /**
+ * ICC Profile Color Space Type Signature: 'CCLR'.
+ */
+ public static final int icSigSpaceCCLR = 0x43434C52; /* 'CCLR' */
+
+ /**
+ * ICC Profile Color Space Type Signature: 'DCLR'.
+ */
+ public static final int icSigSpaceDCLR = 0x44434C52; /* 'DCLR' */
+
+ /**
+ * ICC Profile Color Space Type Signature: 'ECLR'.
+ */
+ public static final int icSigSpaceECLR = 0x45434C52; /* 'ECLR' */
+
+ /**
+ * ICC Profile Color Space Type Signature: 'FCLR'.
+ */
+ public static final int icSigSpaceFCLR = 0x46434C52; /* 'FCLR' */
+
+
+ /**
+ * ICC Profile Class Signature: 'scnr'.
+ */
+ public static final int icSigInputClass = 0x73636E72; /* 'scnr' */
+
+ /**
+ * ICC Profile Class Signature: 'mntr'.
+ */
+ public static final int icSigDisplayClass = 0x6D6E7472; /* 'mntr' */
+
+ /**
+ * ICC Profile Class Signature: 'prtr'.
+ */
+ public static final int icSigOutputClass = 0x70727472; /* 'prtr' */
+
+ /**
+ * ICC Profile Class Signature: 'link'.
+ */
+ public static final int icSigLinkClass = 0x6C696E6B; /* 'link' */
+
+ /**
+ * ICC Profile Class Signature: 'abst'.
+ */
+ public static final int icSigAbstractClass = 0x61627374; /* 'abst' */
+
+ /**
+ * ICC Profile Class Signature: 'spac'.
+ */
+ public static final int icSigColorSpaceClass = 0x73706163; /* 'spac' */
+
+ /**
+ * ICC Profile Class Signature: 'nmcl'.
+ */
+ public static final int icSigNamedColorClass = 0x6e6d636c; /* 'nmcl' */
+
+
+ /**
+ * ICC Profile Rendering Intent: Perceptual.
+ */
+ public static final int icPerceptual = 0;
+
+ /**
+ * ICC Profile Rendering Intent: RelativeColorimetric.
+ */
+ public static final int icRelativeColorimetric = 1;
+
+ /**
+ * ICC Profile Rendering Intent: Media-RelativeColorimetric.
+ * @since 1.5
+ */
+ public static final int icMediaRelativeColorimetric = 1;
+
+ /**
+ * ICC Profile Rendering Intent: Saturation.
+ */
+ public static final int icSaturation = 2;
+
+ /**
+ * ICC Profile Rendering Intent: AbsoluteColorimetric.
+ */
+ public static final int icAbsoluteColorimetric = 3;
+
+ /**
+ * ICC Profile Rendering Intent: ICC-AbsoluteColorimetric.
+ * @since 1.5
+ */
+ public static final int icICCAbsoluteColorimetric = 3;
+
+
+ /**
+ * ICC Profile Tag Signature: 'head' - special.
+ */
+ public static final int icSigHead = 0x68656164; /* 'head' - special */
+
+ /**
+ * ICC Profile Tag Signature: 'A2B0'.
+ */
+ public static final int icSigAToB0Tag = 0x41324230; /* 'A2B0' */
+
+ /**
+ * ICC Profile Tag Signature: 'A2B1'.
+ */
+ public static final int icSigAToB1Tag = 0x41324231; /* 'A2B1' */
+
+ /**
+ * ICC Profile Tag Signature: 'A2B2'.
+ */
+ public static final int icSigAToB2Tag = 0x41324232; /* 'A2B2' */
+
+ /**
+ * ICC Profile Tag Signature: 'bXYZ'.
+ */
+ public static final int icSigBlueColorantTag = 0x6258595A; /* 'bXYZ' */
+
+ /**
+ * ICC Profile Tag Signature: 'bXYZ'.
+ * @since 1.5
+ */
+ public static final int icSigBlueMatrixColumnTag = 0x6258595A; /* 'bXYZ' */
+
+ /**
+ * ICC Profile Tag Signature: 'bTRC'.
+ */
+ public static final int icSigBlueTRCTag = 0x62545243; /* 'bTRC' */
+
+ /**
+ * ICC Profile Tag Signature: 'B2A0'.
+ */
+ public static final int icSigBToA0Tag = 0x42324130; /* 'B2A0' */
+
+ /**
+ * ICC Profile Tag Signature: 'B2A1'.
+ */
+ public static final int icSigBToA1Tag = 0x42324131; /* 'B2A1' */
+
+ /**
+ * ICC Profile Tag Signature: 'B2A2'.
+ */
+ public static final int icSigBToA2Tag = 0x42324132; /* 'B2A2' */
+
+ /**
+ * ICC Profile Tag Signature: 'calt'.
+ */
+ public static final int icSigCalibrationDateTimeTag = 0x63616C74;
+ /* 'calt' */
+
+ /**
+ * ICC Profile Tag Signature: 'targ'.
+ */
+ public static final int icSigCharTargetTag = 0x74617267; /* 'targ' */
+
+ /**
+ * ICC Profile Tag Signature: 'cprt'.
+ */
+ public static final int icSigCopyrightTag = 0x63707274; /* 'cprt' */
+
+ /**
+ * ICC Profile Tag Signature: 'crdi'.
+ */
+ public static final int icSigCrdInfoTag = 0x63726469; /* 'crdi' */
+
+ /**
+ * ICC Profile Tag Signature: 'dmnd'.
+ */
+ public static final int icSigDeviceMfgDescTag = 0x646D6E64; /* 'dmnd' */
+
+ /**
+ * ICC Profile Tag Signature: 'dmdd'.
+ */
+ public static final int icSigDeviceModelDescTag = 0x646D6464; /* 'dmdd' */
+
+ /**
+ * ICC Profile Tag Signature: 'devs'.
+ */
+ public static final int icSigDeviceSettingsTag = 0x64657673; /* 'devs' */
+
+ /**
+ * ICC Profile Tag Signature: 'gamt'.
+ */
+ public static final int icSigGamutTag = 0x67616D74; /* 'gamt' */
+
+ /**
+ * ICC Profile Tag Signature: 'kTRC'.
+ */
+ public static final int icSigGrayTRCTag = 0x6b545243; /* 'kTRC' */
+
+ /**
+ * ICC Profile Tag Signature: 'gXYZ'.
+ */
+ public static final int icSigGreenColorantTag = 0x6758595A; /* 'gXYZ' */
+
+ /**
+ * ICC Profile Tag Signature: 'gXYZ'.
+ * @since 1.5
+ */
+ public static final int icSigGreenMatrixColumnTag = 0x6758595A;/* 'gXYZ' */
+
+ /**
+ * ICC Profile Tag Signature: 'gTRC'.
+ */
+ public static final int icSigGreenTRCTag = 0x67545243; /* 'gTRC' */
+
+ /**
+ * ICC Profile Tag Signature: 'lumi'.
+ */
+ public static final int icSigLuminanceTag = 0x6C756d69; /* 'lumi' */
+
+ /**
+ * ICC Profile Tag Signature: 'meas'.
+ */
+ public static final int icSigMeasurementTag = 0x6D656173; /* 'meas' */
+
+ /**
+ * ICC Profile Tag Signature: 'bkpt'.
+ */
+ public static final int icSigMediaBlackPointTag = 0x626B7074; /* 'bkpt' */
+
+ /**
+ * ICC Profile Tag Signature: 'wtpt'.
+ */
+ public static final int icSigMediaWhitePointTag = 0x77747074; /* 'wtpt' */
+
+ /**
+ * ICC Profile Tag Signature: 'ncl2'.
+ */
+ public static final int icSigNamedColor2Tag = 0x6E636C32; /* 'ncl2' */
+
+ /**
+ * ICC Profile Tag Signature: 'resp'.
+ */
+ public static final int icSigOutputResponseTag = 0x72657370; /* 'resp' */
+
+ /**
+ * ICC Profile Tag Signature: 'pre0'.
+ */
+ public static final int icSigPreview0Tag = 0x70726530; /* 'pre0' */
+
+ /**
+ * ICC Profile Tag Signature: 'pre1'.
+ */
+ public static final int icSigPreview1Tag = 0x70726531; /* 'pre1' */
+
+ /**
+ * ICC Profile Tag Signature: 'pre2'.
+ */
+ public static final int icSigPreview2Tag = 0x70726532; /* 'pre2' */
+
+ /**
+ * ICC Profile Tag Signature: 'desc'.
+ */
+ public static final int icSigProfileDescriptionTag = 0x64657363;
+ /* 'desc' */
+
+ /**
+ * ICC Profile Tag Signature: 'pseq'.
+ */
+ public static final int icSigProfileSequenceDescTag = 0x70736571;
+ /* 'pseq' */
+
+ /**
+ * ICC Profile Tag Signature: 'psd0'.
+ */
+ public static final int icSigPs2CRD0Tag = 0x70736430; /* 'psd0' */
+
+ /**
+ * ICC Profile Tag Signature: 'psd1'.
+ */
+ public static final int icSigPs2CRD1Tag = 0x70736431; /* 'psd1' */
+
+ /**
+ * ICC Profile Tag Signature: 'psd2'.
+ */
+ public static final int icSigPs2CRD2Tag = 0x70736432; /* 'psd2' */
+
+ /**
+ * ICC Profile Tag Signature: 'psd3'.
+ */
+ public static final int icSigPs2CRD3Tag = 0x70736433; /* 'psd3' */
+
+ /**
+ * ICC Profile Tag Signature: 'ps2s'.
+ */
+ public static final int icSigPs2CSATag = 0x70733273; /* 'ps2s' */
+
+ /**
+ * ICC Profile Tag Signature: 'ps2i'.
+ */
+ public static final int icSigPs2RenderingIntentTag = 0x70733269;
+ /* 'ps2i' */
+
+ /**
+ * ICC Profile Tag Signature: 'rXYZ'.
+ */
+ public static final int icSigRedColorantTag = 0x7258595A; /* 'rXYZ' */
+
+ /**
+ * ICC Profile Tag Signature: 'rXYZ'.
+ * @since 1.5
+ */
+ public static final int icSigRedMatrixColumnTag = 0x7258595A; /* 'rXYZ' */
+
+ /**
+ * ICC Profile Tag Signature: 'rTRC'.
+ */
+ public static final int icSigRedTRCTag = 0x72545243; /* 'rTRC' */
+
+ /**
+ * ICC Profile Tag Signature: 'scrd'.
+ */
+ public static final int icSigScreeningDescTag = 0x73637264; /* 'scrd' */
+
+ /**
+ * ICC Profile Tag Signature: 'scrn'.
+ */
+ public static final int icSigScreeningTag = 0x7363726E; /* 'scrn' */
+
+ /**
+ * ICC Profile Tag Signature: 'tech'.
+ */
+ public static final int icSigTechnologyTag = 0x74656368; /* 'tech' */
+
+ /**
+ * ICC Profile Tag Signature: 'bfd '.
+ */
+ public static final int icSigUcrBgTag = 0x62666420; /* 'bfd ' */
+
+ /**
+ * ICC Profile Tag Signature: 'vued'.
+ */
+ public static final int icSigViewingCondDescTag = 0x76756564; /* 'vued' */
+
+ /**
+ * ICC Profile Tag Signature: 'view'.
+ */
+ public static final int icSigViewingConditionsTag = 0x76696577;/* 'view' */
+
+ /**
+ * ICC Profile Tag Signature: 'chrm'.
+ */
+ public static final int icSigChromaticityTag = 0x6368726d; /* 'chrm' */
+
+ /**
+ * ICC Profile Tag Signature: 'chad'.
+ * @since 1.5
+ */
+ public static final int icSigChromaticAdaptationTag = 0x63686164;/* 'chad' */
+
+ /**
+ * ICC Profile Tag Signature: 'clro'.
+ * @since 1.5
+ */
+ public static final int icSigColorantOrderTag = 0x636C726F; /* 'clro' */
+
+ /**
+ * ICC Profile Tag Signature: 'clrt'.
+ * @since 1.5
+ */
+ public static final int icSigColorantTableTag = 0x636C7274; /* 'clrt' */
+
+
+ /**
+ * ICC Profile Header Location: profile size in bytes.
+ */
+ public static final int icHdrSize = 0; /* Profile size in bytes */
+
+ /**
+ * ICC Profile Header Location: CMM for this profile.
+ */
+ public static final int icHdrCmmId = 4; /* CMM for this profile */
+
+ /**
+ * ICC Profile Header Location: format version number.
+ */
+ public static final int icHdrVersion = 8; /* Format version number */
+
+ /**
+ * ICC Profile Header Location: type of profile.
+ */
+ public static final int icHdrDeviceClass = 12; /* Type of profile */
+
+ /**
+ * ICC Profile Header Location: color space of data.
+ */
+ public static final int icHdrColorSpace = 16; /* Color space of data */
+
+ /**
+ * ICC Profile Header Location: PCS - XYZ or Lab only.
+ */
+ public static final int icHdrPcs = 20; /* PCS - XYZ or Lab only */
+
+ /**
+ * ICC Profile Header Location: date profile was created.
+ */
+ public static final int icHdrDate = 24; /* Date profile was created */
+
+ /**
+ * ICC Profile Header Location: icMagicNumber.
+ */
+ public static final int icHdrMagic = 36; /* icMagicNumber */
+
+ /**
+ * ICC Profile Header Location: primary platform.
+ */
+ public static final int icHdrPlatform = 40; /* Primary Platform */
+
+ /**
+ * ICC Profile Header Location: various bit settings.
+ */
+ public static final int icHdrFlags = 44; /* Various bit settings */
+
+ /**
+ * ICC Profile Header Location: device manufacturer.
+ */
+ public static final int icHdrManufacturer = 48; /* Device manufacturer */
+
+ /**
+ * ICC Profile Header Location: device model number.
+ */
+ public static final int icHdrModel = 52; /* Device model number */
+
+ /**
+ * ICC Profile Header Location: device attributes.
+ */
+ public static final int icHdrAttributes = 56; /* Device attributes */
+
+ /**
+ * ICC Profile Header Location: rendering intent.
+ */
+ public static final int icHdrRenderingIntent = 64; /* Rendering intent */
+
+ /**
+ * ICC Profile Header Location: profile illuminant.
+ */
+ public static final int icHdrIlluminant = 68; /* Profile illuminant */
+
+ /**
+ * ICC Profile Header Location: profile creator.
+ */
+ public static final int icHdrCreator = 80; /* Profile creator */
+
+ /**
+ * ICC Profile Header Location: profile's ID.
+ * @since 1.5
+ */
+ public static final int icHdrProfileID = 84; /* Profile's ID */
+
+
+ /**
+ * ICC Profile Constant: tag type signaturE.
+ */
+ public static final int icTagType = 0; /* tag type signature */
+
+ /**
+ * ICC Profile Constant: reserved.
+ */
+ public static final int icTagReserved = 4; /* reserved */
+
+ /**
+ * ICC Profile Constant: curveType count.
+ */
+ public static final int icCurveCount = 8; /* curveType count */
+
+ /**
+ * ICC Profile Constant: curveType data.
+ */
+ public static final int icCurveData = 12; /* curveType data */
+
+ /**
+ * ICC Profile Constant: XYZNumber X.
+ */
+ public static final int icXYZNumberX = 8; /* XYZNumber X */
+
+
+ /**
+ * Constructs an ICC_Profile object with a given ID.
+ */
+ ICC_Profile(long ID) {
+ this.ID = ID;
+ }
+
+
+ /**
+ * Constructs an ICC_Profile object whose loading will be deferred.
+ * The ID will be 0 until the profile is loaded.
+ */
+ ICC_Profile(ProfileDeferralInfo pdi) {
+ this.deferralInfo = pdi;
+ this.profileActivator = new ProfileActivator() {
+ public void activate() {
+ activateDeferredProfile();
+ }
+ };
+ ProfileDeferralMgr.registerDeferral(this.profileActivator);
+ }
+
+
+ /**
+ * Frees the resources associated with an ICC_Profile object.
+ */
+ protected void finalize () {
+ if (ID != 0) {
+ CMSManager.getModule().freeProfile(ID);
+ } else if (profileActivator != null) {
+ ProfileDeferralMgr.unregisterDeferral(profileActivator);
+ }
+ }
+
+
+ /**
+ * Constructs an ICC_Profile object corresponding to the data in
+ * a byte array. Throws an IllegalArgumentException if the data
+ * does not correspond to a valid ICC Profile.
+ * @param data the specified ICC Profile data
+ * @return an <code>ICC_Profile</code> object corresponding to
+ * the data in the specified <code>data</code> array.
+ */
+ public static ICC_Profile getInstance(byte[] data) {
+ ICC_Profile thisProfile;
+
+ long theID;
+
+ if (ProfileDeferralMgr.deferring) {
+ ProfileDeferralMgr.activateProfiles();
+ }
+
+ try {
+ theID = CMSManager.getModule().loadProfile(data);
+ } catch (CMMException c) {
+ throw new IllegalArgumentException("Invalid ICC Profile Data");
+ }
+
+ try {
+ if ((getColorSpaceType (theID) == ColorSpace.TYPE_GRAY) &&
+ (getData (theID, icSigMediaWhitePointTag) != null) &&
+ (getData (theID, icSigGrayTRCTag) != null)) {
+ thisProfile = new ICC_ProfileGray (theID);
+ }
+ else if ((getColorSpaceType (theID) == ColorSpace.TYPE_RGB) &&
+ (getData (theID, icSigMediaWhitePointTag) != null) &&
+ (getData (theID, icSigRedColorantTag) != null) &&
+ (getData (theID, icSigGreenColorantTag) != null) &&
+ (getData (theID, icSigBlueColorantTag) != null) &&
+ (getData (theID, icSigRedTRCTag) != null) &&
+ (getData (theID, icSigGreenTRCTag) != null) &&
+ (getData (theID, icSigBlueTRCTag) != null)) {
+ thisProfile = new ICC_ProfileRGB (theID);
+ }
+ else {
+ thisProfile = new ICC_Profile (theID);
+ }
+ } catch (CMMException c) {
+ thisProfile = new ICC_Profile (theID);
+ }
+ return thisProfile;
+ }
+
+
+
+ /**
+ * Constructs an ICC_Profile corresponding to one of the specific color
+ * spaces defined by the ColorSpace class (for example CS_sRGB).
+ * Throws an IllegalArgumentException if cspace is not one of the
+ * defined color spaces.
+ *
+ * @param cspace the type of color space to create a profile for.
+ * The specified type is one of the color
+ * space constants defined in the <CODE>ColorSpace</CODE> class.
+ *
+ * @return an <code>ICC_Profile</code> object corresponding to
+ * the specified <code>ColorSpace</code> type.
+ * @exception IllegalArgumentException If <CODE>cspace</CODE> is not
+ * one of the predefined color space types.
+ */
+ public static ICC_Profile getInstance (int cspace) {
+ ICC_Profile thisProfile = null;
+ String fileName;
+
+ switch (cspace) {
+ case ColorSpace.CS_sRGB:
+ synchronized(ICC_Profile.class) {
+ if (sRGBprofile == null) {
+ try {
+ /*
+ * Deferral is only used for standard profiles.
+ * Enabling the appropriate access privileges is handled
+ * at a lower level.
+ */
+ sRGBprofile = getDeferredInstance(
+ new ProfileDeferralInfo("sRGB.pf",
+ ColorSpace.TYPE_RGB,
+ 3, CLASS_DISPLAY));
+ } catch (IOException e) {
+ throw new IllegalArgumentException(
+ "Can't load standard profile: sRGB.pf");
+ }
+ }
+ thisProfile = sRGBprofile;
+ }
+
+ break;
+
+ case ColorSpace.CS_CIEXYZ:
+ synchronized(ICC_Profile.class) {
+ if (XYZprofile == null) {
+ XYZprofile = getStandardProfile("CIEXYZ.pf");
+ }
+ thisProfile = XYZprofile;
+ }
+
+ break;
+
+ case ColorSpace.CS_PYCC:
+ synchronized(ICC_Profile.class) {
+ if (PYCCprofile == null) {
+ PYCCprofile = getStandardProfile("PYCC.pf");
+ }
+ thisProfile = PYCCprofile;
+ }
+
+ break;
+
+ case ColorSpace.CS_GRAY:
+ synchronized(ICC_Profile.class) {
+ if (GRAYprofile == null) {
+ GRAYprofile = getStandardProfile("GRAY.pf");
+ }
+ thisProfile = GRAYprofile;
+ }
+
+ break;
+
+ case ColorSpace.CS_LINEAR_RGB:
+ synchronized(ICC_Profile.class) {
+ if (LINEAR_RGBprofile == null) {
+ LINEAR_RGBprofile = getStandardProfile("LINEAR_RGB.pf");
+ }
+ thisProfile = LINEAR_RGBprofile;
+ }
+
+ break;
+
+ default:
+ throw new IllegalArgumentException("Unknown color space");
+ }
+
+ return thisProfile;
+ }
+
+ /* This asserts system privileges, so is used only for the
+ * standard profiles.
+ */
+ private static ICC_Profile getStandardProfile(final String name) {
+
+ return (ICC_Profile) AccessController.doPrivileged(
+ new PrivilegedAction() {
+ public Object run() {
+ ICC_Profile p = null;
+ try {
+ p = getInstance (name);
+ } catch (IOException ex) {
+ throw new IllegalArgumentException(
+ "Can't load standard profile: " + name);
+ }
+ return p;
+ }
+ });
+ }
+
+ /**
+ * Constructs an ICC_Profile corresponding to the data in a file.
+ * fileName may be an absolute or a relative file specification.
+ * Relative file names are looked for in several places: first, relative
+ * to any directories specified by the java.iccprofile.path property;
+ * second, relative to any directories specified by the java.class.path
+ * property; finally, in a directory used to store profiles always
+ * available, such as the profile for sRGB. Built-in profiles use .pf as
+ * the file name extension for profiles, e.g. sRGB.pf.
+ * This method throws an IOException if the specified file cannot be
+ * opened or if an I/O error occurs while reading the file. It throws
+ * an IllegalArgumentException if the file does not contain valid ICC
+ * Profile data.
+ * @param fileName The file that contains the data for the profile.
+ *
+ * @return an <code>ICC_Profile</code> object corresponding to
+ * the data in the specified file.
+ * @exception IOException If the specified file cannot be opened or
+ * an I/O error occurs while reading the file.
+ *
+ * @exception IllegalArgumentException If the file does not
+ * contain valid ICC Profile data.
+ *
+ * @exception SecurityException If a security manager is installed
+ * and it does not permit read access to the given file.
+ */
+ public static ICC_Profile getInstance(String fileName) throws IOException {
+ ICC_Profile thisProfile;
+ FileInputStream fis;
+
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkRead(fileName);
+ }
+
+ if ((fis = openProfile(fileName)) == null) {
+ throw new IOException("Cannot open file " + fileName);
+ }
+
+ thisProfile = getInstance(fis);
+
+ fis.close(); /* close the file */
+
+ return thisProfile;
+ }
+
+
+ /**
+ * Constructs an ICC_Profile corresponding to the data in an InputStream.
+ * This method throws an IllegalArgumentException if the stream does not
+ * contain valid ICC Profile data. It throws an IOException if an I/O
+ * error occurs while reading the stream.
+ * @param s The input stream from which to read the profile data.
+ *
+ * @return an <CODE>ICC_Profile</CODE> object corresponding to the
+ * data in the specified <code>InputStream</code>.
+ *
+ * @exception IOException If an I/O error occurs while reading the stream.
+ *
+ * @exception IllegalArgumentException If the stream does not
+ * contain valid ICC Profile data.
+ */
+ public static ICC_Profile getInstance(InputStream s) throws IOException {
+ byte profileData[];
+
+ if (s instanceof ProfileDeferralInfo) {
+ /* hack to detect profiles whose loading can be deferred */
+ return getDeferredInstance((ProfileDeferralInfo) s);
+ }
+
+ if ((profileData = getProfileDataFromStream(s)) == null) {
+ throw new IllegalArgumentException("Invalid ICC Profile Data");
+ }
+
+ return getInstance(profileData);
+ }
+
+
+ static byte[] getProfileDataFromStream(InputStream s) throws IOException {
+ byte profileData[];
+ int profileSize;
+
+ byte header[] = new byte[128];
+ int bytestoread = 128;
+ int bytesread = 0;
+ int n;
+
+ while (bytestoread != 0) {
+ if ((n = s.read(header, bytesread, bytestoread)) < 0) {
+ return null;
+ }
+ bytesread += n;
+ bytestoread -= n;
+ }
+ if (header[36] != 0x61 || header[37] != 0x63 ||
+ header[38] != 0x73 || header[39] != 0x70) {
+ return null; /* not a valid profile */
+ }
+ profileSize = ((header[0] & 0xff) << 24) |
+ ((header[1] & 0xff) << 16) |
+ ((header[2] & 0xff) << 8) |
+ (header[3] & 0xff);
+ profileData = new byte[profileSize];
+ System.arraycopy(header, 0, profileData, 0, 128);
+ bytestoread = profileSize - 128;
+ bytesread = 128;
+ while (bytestoread != 0) {
+ if ((n = s.read(profileData, bytesread, bytestoread)) < 0) {
+ return null;
+ }
+ bytesread += n;
+ bytestoread -= n;
+ }
+
+ return profileData;
+ }
+
+
+ /**
+ * Constructs an ICC_Profile for which the actual loading of the
+ * profile data from a file and the initialization of the CMM should
+ * be deferred as long as possible.
+ * Deferral is only used for standard profiles.
+ * If deferring is disabled, then getStandardProfile() ensures
+ * that all of the appropriate access privileges are granted
+ * when loading this profile.
+ * If deferring is enabled, then the deferred activation
+ * code will take care of access privileges.
+ * @see activateDeferredProfile()
+ */
+ static ICC_Profile getDeferredInstance(ProfileDeferralInfo pdi)
+ throws IOException {
+
+ if (!ProfileDeferralMgr.deferring) {
+ return getStandardProfile(pdi.filename);
+ }
+ if (pdi.colorSpaceType == ColorSpace.TYPE_RGB) {
+ return new ICC_ProfileRGB(pdi);
+ } else if (pdi.colorSpaceType == ColorSpace.TYPE_GRAY) {
+ return new ICC_ProfileGray(pdi);
+ } else {
+ return new ICC_Profile(pdi);
+ }
+ }
+
+
+ void activateDeferredProfile() {
+ byte profileData[];
+ FileInputStream fis;
+ String fileName = deferralInfo.filename;
+
+ profileActivator = null;
+ deferralInfo = null;
+ if ((fis = openProfile(fileName)) == null) {
+ throw new IllegalArgumentException("Cannot open file " + fileName);
+ }
+ try {
+ profileData = getProfileDataFromStream(fis);
+ fis.close(); /* close the file */
+ }
+ catch (IOException e) {
+ throw new IllegalArgumentException("Invalid ICC Profile Data" +
+ fileName);
+ }
+ if (profileData == null) {
+ throw new IllegalArgumentException("Invalid ICC Profile Data" +
+ fileName);
+ }
+ try {
+ ID = CMSManager.getModule().loadProfile(profileData);
+ } catch (CMMException c) {
+ throw new IllegalArgumentException("Invalid ICC Profile Data" +
+ fileName);
+ }
+ }
+
+
+ /**
+ * Returns profile major version.
+ * @return The major version of the profile.
+ */
+ public int getMajorVersion() {
+ byte[] theHeader;
+
+ theHeader = getData(icSigHead); /* getData will activate deferred
+ profiles if necessary */
+
+ return (int) theHeader[8];
+ }
+
+ /**
+ * Returns profile minor version.
+ * @return The minor version of the profile.
+ */
+ public int getMinorVersion() {
+ byte[] theHeader;
+
+ theHeader = getData(icSigHead); /* getData will activate deferred
+ profiles if necessary */
+
+ return (int) theHeader[9];
+ }
+
+ /**
+ * Returns the profile class.
+ * @return One of the predefined profile class constants.
+ */
+ public int getProfileClass() {
+ byte[] theHeader;
+ int theClassSig, theClass;
+
+ if (deferralInfo != null) {
+ return deferralInfo.profileClass; /* Need to have this info for
+ ICC_ColorSpace without
+ causing a deferred profile
+ to be loaded */
+ }
+
+ theHeader = getData(icSigHead);
+
+ theClassSig = intFromBigEndian (theHeader, icHdrDeviceClass);
+
+ switch (theClassSig) {
+ case icSigInputClass:
+ theClass = CLASS_INPUT;
+ break;
+
+ case icSigDisplayClass:
+ theClass = CLASS_DISPLAY;
+ break;
+
+ case icSigOutputClass:
+ theClass = CLASS_OUTPUT;
+ break;
+
+ case icSigLinkClass:
+ theClass = CLASS_DEVICELINK;
+ break;
+
+ case icSigColorSpaceClass:
+ theClass = CLASS_COLORSPACECONVERSION;
+ break;
+
+ case icSigAbstractClass:
+ theClass = CLASS_ABSTRACT;
+ break;
+
+ case icSigNamedColorClass:
+ theClass = CLASS_NAMEDCOLOR;
+ break;
+
+ default:
+ throw new IllegalArgumentException("Unknown profile class");
+ }
+
+ return theClass;
+ }
+
+ /**
+ * Returns the color space type. Returns one of the color space type
+ * constants defined by the ColorSpace class. This is the
+ * "input" color space of the profile. The type defines the
+ * number of components of the color space and the interpretation,
+ * e.g. TYPE_RGB identifies a color space with three components - red,
+ * green, and blue. It does not define the particular color
+ * characteristics of the space, e.g. the chromaticities of the
+ * primaries.
+ * @return One of the color space type constants defined in the
+ * <CODE>ColorSpace</CODE> class.
+ */
+ public int getColorSpaceType() {
+ if (deferralInfo != null) {
+ return deferralInfo.colorSpaceType; /* Need to have this info for
+ ICC_ColorSpace without
+ causing a deferred profile
+ to be loaded */
+ }
+ return getColorSpaceType(ID);
+ }
+
+ static int getColorSpaceType(long profileID) {
+ byte[] theHeader;
+ int theColorSpaceSig, theColorSpace;
+
+ theHeader = getData(profileID, icSigHead);
+ theColorSpaceSig = intFromBigEndian(theHeader, icHdrColorSpace);
+ theColorSpace = iccCStoJCS (theColorSpaceSig);
+ return theColorSpace;
+ }
+
+ /**
+ * Returns the color space type of the Profile Connection Space (PCS).
+ * Returns one of the color space type constants defined by the
+ * ColorSpace class. This is the "output" color space of the
+ * profile. For an input, display, or output profile useful
+ * for tagging colors or images, this will be either TYPE_XYZ or
+ * TYPE_Lab and should be interpreted as the corresponding specific
+ * color space defined in the ICC specification. For a device
+ * link profile, this could be any of the color space type constants.
+ * @return One of the color space type constants defined in the
+ * <CODE>ColorSpace</CODE> class.
+ */
+ public int getPCSType() {
+ if (ProfileDeferralMgr.deferring) {
+ ProfileDeferralMgr.activateProfiles();
+ }
+ return getPCSType(ID);
+ }
+
+
+ static int getPCSType(long profileID) {
+ byte[] theHeader;
+ int thePCSSig, thePCS;
+
+ theHeader = getData(profileID, icSigHead);
+ thePCSSig = intFromBigEndian(theHeader, icHdrPcs);
+ thePCS = iccCStoJCS(thePCSSig);
+ return thePCS;
+ }
+
+
+ /**
+ * Write this ICC_Profile to a file.
+ *
+ * @param fileName The file to write the profile data to.
+ *
+ * @exception IOException If the file cannot be opened for writing
+ * or an I/O error occurs while writing to the file.
+ */
+ public void write(String fileName) throws IOException {
+ FileOutputStream outputFile;
+ byte profileData[];
+
+ profileData = getData(); /* this will activate deferred
+ profiles if necessary */
+ outputFile = new FileOutputStream(fileName);
+ outputFile.write(profileData);
+ outputFile.close ();
+ }
+
+
+ /**
+ * Write this ICC_Profile to an OutputStream.
+ *
+ * @param s The stream to write the profile data to.
+ *
+ * @exception IOException If an I/O error occurs while writing to the
+ * stream.
+ */
+ public void write(OutputStream s) throws IOException {
+ byte profileData[];
+
+ profileData = getData(); /* this will activate deferred
+ profiles if necessary */
+ s.write(profileData);
+ }
+
+
+ /**
+ * Returns a byte array corresponding to the data of this ICC_Profile.
+ * @return A byte array that contains the profile data.
+ * @see #setData(int, byte[])
+ */
+ public byte[] getData() {
+ int profileSize;
+ byte[] profileData;
+
+ if (ProfileDeferralMgr.deferring) {
+ ProfileDeferralMgr.activateProfiles();
+ }
+
+ PCMM mdl = CMSManager.getModule();
+
+ /* get the number of bytes needed for this profile */
+ profileSize = mdl.getProfileSize(ID);
+
+ profileData = new byte [profileSize];
+
+ /* get the data for the profile */
+ mdl.getProfileData(ID, profileData);
+
+ return profileData;
+ }
+
+
+ /**
+ * Returns a particular tagged data element from the profile as
+ * a byte array. Elements are identified by signatures
+ * as defined in the ICC specification. The signature
+ * icSigHead can be used to get the header. This method is useful
+ * for advanced applets or applications which need to access
+ * profile data directly.
+ *
+ * @param tagSignature The ICC tag signature for the data element you
+ * want to get.
+ *
+ * @return A byte array that contains the tagged data element. Returns
+ * <code>null</code> if the specified tag doesn't exist.
+ * @see #setData(int, byte[])
+ */
+ public byte[] getData(int tagSignature) {
+
+ if (ProfileDeferralMgr.deferring) {
+ ProfileDeferralMgr.activateProfiles();
+ }
+
+ return getData(ID, tagSignature);
+ }
+
+
+ static byte[] getData(long profileID, int tagSignature) {
+ int tagSize;
+ byte[] tagData;
+
+ try {
+ PCMM mdl = CMSManager.getModule();
+
+ /* get the number of bytes needed for this tag */
+ tagSize = mdl.getTagSize(profileID, tagSignature);
+
+ tagData = new byte[tagSize]; /* get an array for the tag */
+
+ /* get the tag's data */
+ mdl.getTagData(profileID, tagSignature, tagData);
+ } catch(CMMException c) {
+ tagData = null;
+ }
+
+ return tagData;
+ }
+
+ /**
+ * Sets a particular tagged data element in the profile from
+ * a byte array. This method is useful
+ * for advanced applets or applications which need to access
+ * profile data directly.
+ *
+ * @param tagSignature The ICC tag signature for the data element
+ * you want to set.
+ * @param tagData the data to set for the specified tag signature
+ * @see #getData
+ */
+ public void setData(int tagSignature, byte[] tagData) {
+
+ if (ProfileDeferralMgr.deferring) {
+ ProfileDeferralMgr.activateProfiles();
+ }
+
+ CMSManager.getModule().setTagData(ID, tagSignature, tagData);
+ }
+
+ /**
+ * Sets the rendering intent of the profile.
+ * This is used to select the proper transform from a profile that
+ * has multiple transforms.
+ */
+ void setRenderingIntent(int renderingIntent) {
+ byte[] theHeader = getData(icSigHead);/* getData will activate deferred
+ profiles if necessary */
+ intToBigEndian (renderingIntent, theHeader, icHdrRenderingIntent);
+ /* set the rendering intent */
+ setData (icSigHead, theHeader);
+ }
+
+
+ /**
+ * Returns the rendering intent of the profile.
+ * This is used to select the proper transform from a profile that
+ * has multiple transforms. It is typically set in a source profile
+ * to select a transform from an output profile.
+ */
+ int getRenderingIntent() {
+ byte[] theHeader = getData(icSigHead);/* getData will activate deferred
+ profiles if necessary */
+
+ int renderingIntent = intFromBigEndian(theHeader, icHdrRenderingIntent);
+ /* set the rendering intent */
+ return renderingIntent;
+ }
+
+
+ /**
+ * Returns the number of color components in the "input" color
+ * space of this profile. For example if the color space type
+ * of this profile is TYPE_RGB, then this method will return 3.
+ *
+ * @return The number of color components in the profile's input
+ * color space.
+ *
+ * @throws ProfileDataException if color space is in the profile
+ * is invalid
+ */
+ public int getNumComponents() {
+ byte[] theHeader;
+ int theColorSpaceSig, theNumComponents;
+
+ if (deferralInfo != null) {
+ return deferralInfo.numComponents; /* Need to have this info for
+ ICC_ColorSpace without
+ causing a deferred profile
+ to be loaded */
+ }
+ theHeader = getData(icSigHead);
+
+ theColorSpaceSig = intFromBigEndian (theHeader, icHdrColorSpace);
+
+ switch (theColorSpaceSig) {
+ case icSigGrayData:
+ theNumComponents = 1;
+ break;
+
+ case icSigSpace2CLR:
+ theNumComponents = 2;
+ break;
+
+ case icSigXYZData:
+ case icSigLabData:
+ case icSigLuvData:
+ case icSigYCbCrData:
+ case icSigYxyData:
+ case icSigRgbData:
+ case icSigHsvData:
+ case icSigHlsData:
+ case icSigCmyData:
+ case icSigSpace3CLR:
+ theNumComponents = 3;
+ break;
+
+ case icSigCmykData:
+ case icSigSpace4CLR:
+ theNumComponents = 4;
+ break;
+
+ case icSigSpace5CLR:
+ theNumComponents = 5;
+ break;
+
+ case icSigSpace6CLR:
+ theNumComponents = 6;
+ break;
+
+ case icSigSpace7CLR:
+ theNumComponents = 7;
+ break;
+
+ case icSigSpace8CLR:
+ theNumComponents = 8;
+ break;
+
+ case icSigSpace9CLR:
+ theNumComponents = 9;
+ break;
+
+ case icSigSpaceACLR:
+ theNumComponents = 10;
+ break;
+
+ case icSigSpaceBCLR:
+ theNumComponents = 11;
+ break;
+
+ case icSigSpaceCCLR:
+ theNumComponents = 12;
+ break;
+
+ case icSigSpaceDCLR:
+ theNumComponents = 13;
+ break;
+
+ case icSigSpaceECLR:
+ theNumComponents = 14;
+ break;
+
+ case icSigSpaceFCLR:
+ theNumComponents = 15;
+ break;
+
+ default:
+ throw new ProfileDataException ("invalid ICC color space");
+ }
+
+ return theNumComponents;
+ }
+
+
+ /**
+ * Returns a float array of length 3 containing the X, Y, and Z
+ * components of the mediaWhitePointTag in the ICC profile.
+ */
+ float[] getMediaWhitePoint() {
+ return getXYZTag(icSigMediaWhitePointTag);
+ /* get the media white point tag */
+ }
+
+
+ /**
+ * Returns a float array of length 3 containing the X, Y, and Z
+ * components encoded in an XYZType tag.
+ */
+ float[] getXYZTag(int theTagSignature) {
+ byte[] theData;
+ float[] theXYZNumber;
+ int i1, i2, theS15Fixed16;
+
+ theData = getData(theTagSignature); /* get the tag data */
+ /* getData will activate deferred
+ profiles if necessary */
+
+ theXYZNumber = new float [3]; /* array to return */
+
+ /* convert s15Fixed16Number to float */
+ for (i1 = 0, i2 = icXYZNumberX; i1 < 3; i1++, i2 += 4) {
+ theS15Fixed16 = intFromBigEndian(theData, i2);
+ theXYZNumber [i1] = ((float) theS15Fixed16) / 65536.0f;
+ }
+ return theXYZNumber;
+ }
+
+
+ /**
+ * Returns a gamma value representing a tone reproduction
+ * curve (TRC). If the profile represents the TRC as a table rather
+ * than a single gamma value, then an exception is thrown. In this
+ * case the actual table can be obtained via getTRC().
+ * theTagSignature should be one of icSigGrayTRCTag, icSigRedTRCTag,
+ * icSigGreenTRCTag, or icSigBlueTRCTag.
+ * @return the gamma value as a float.
+ * @exception ProfileDataException if the profile does not specify
+ * the TRC as a single gamma value.
+ */
+ float getGamma(int theTagSignature) {
+ byte[] theTRCData;
+ float theGamma;
+ int theU8Fixed8;
+
+ theTRCData = getData(theTagSignature); /* get the TRC */
+ /* getData will activate deferred
+ profiles if necessary */
+
+ if (intFromBigEndian (theTRCData, icCurveCount) != 1) {
+ throw new ProfileDataException ("TRC is not a gamma");
+ }
+
+ /* convert u8Fixed8 to float */
+ theU8Fixed8 = (shortFromBigEndian(theTRCData, icCurveData)) & 0xffff;
+
+ theGamma = ((float) theU8Fixed8) / 256.0f;
+
+ return theGamma;
+ }
+
+
+ /**
+ * Returns the TRC as an array of shorts. If the profile has
+ * specified the TRC as linear (gamma = 1.0) or as a simple gamma
+ * value, this method throws an exception, and the getGamma() method
+ * should be used to get the gamma value. Otherwise the short array
+ * returned here represents a lookup table where the input Gray value
+ * is conceptually in the range [0.0, 1.0]. Value 0.0 maps
+ * to array index 0 and value 1.0 maps to array index length-1.
+ * Interpolation may be used to generate output values for
+ * input values which do not map exactly to an index in the
+ * array. Output values also map linearly to the range [0.0, 1.0].
+ * Value 0.0 is represented by an array value of 0x0000 and
+ * value 1.0 by 0xFFFF, i.e. the values are really unsigned
+ * short values, although they are returned in a short array.
+ * theTagSignature should be one of icSigGrayTRCTag, icSigRedTRCTag,
+ * icSigGreenTRCTag, or icSigBlueTRCTag.
+ * @return a short array representing the TRC.
+ * @exception ProfileDataException if the profile does not specify
+ * the TRC as a table.
+ */
+ short[] getTRC(int theTagSignature) {
+ byte[] theTRCData;
+ short[] theTRC;
+ int i1, i2, nElements, theU8Fixed8;
+
+ theTRCData = getData(theTagSignature); /* get the TRC */
+ /* getData will activate deferred
+ profiles if necessary */
+
+ nElements = intFromBigEndian(theTRCData, icCurveCount);
+
+ if (nElements == 1) {
+ throw new ProfileDataException("TRC is not a table");
+ }
+
+ /* make the short array */
+ theTRC = new short [nElements];
+
+ for (i1 = 0, i2 = icCurveData; i1 < nElements; i1++, i2 += 2) {
+ theTRC[i1] = shortFromBigEndian(theTRCData, i2);
+ }
+
+ return theTRC;
+ }
+
+
+ /* convert an ICC color space signature into a Java color space type */
+ static int iccCStoJCS(int theColorSpaceSig) {
+ int theColorSpace;
+
+ switch (theColorSpaceSig) {
+ case icSigXYZData:
+ theColorSpace = ColorSpace.TYPE_XYZ;
+ break;
+
+ case icSigLabData:
+ theColorSpace = ColorSpace.TYPE_Lab;
+ break;
+
+ case icSigLuvData:
+ theColorSpace = ColorSpace.TYPE_Luv;
+ break;
+
+ case icSigYCbCrData:
+ theColorSpace = ColorSpace.TYPE_YCbCr;
+ break;
+
+ case icSigYxyData:
+ theColorSpace = ColorSpace.TYPE_Yxy;
+ break;
+
+ case icSigRgbData:
+ theColorSpace = ColorSpace.TYPE_RGB;
+ break;
+
+ case icSigGrayData:
+ theColorSpace = ColorSpace.TYPE_GRAY;
+ break;
+
+ case icSigHsvData:
+ theColorSpace = ColorSpace.TYPE_HSV;
+ break;
+
+ case icSigHlsData:
+ theColorSpace = ColorSpace.TYPE_HLS;
+ break;
+
+ case icSigCmykData:
+ theColorSpace = ColorSpace.TYPE_CMYK;
+ break;
+
+ case icSigCmyData:
+ theColorSpace = ColorSpace.TYPE_CMY;
+ break;
+
+ case icSigSpace2CLR:
+ theColorSpace = ColorSpace.TYPE_2CLR;
+ break;
+
+ case icSigSpace3CLR:
+ theColorSpace = ColorSpace.TYPE_3CLR;
+ break;
+
+ case icSigSpace4CLR:
+ theColorSpace = ColorSpace.TYPE_4CLR;
+ break;
+
+ case icSigSpace5CLR:
+ theColorSpace = ColorSpace.TYPE_5CLR;
+ break;
+
+ case icSigSpace6CLR:
+ theColorSpace = ColorSpace.TYPE_6CLR;
+ break;
+
+ case icSigSpace7CLR:
+ theColorSpace = ColorSpace.TYPE_7CLR;
+ break;
+
+ case icSigSpace8CLR:
+ theColorSpace = ColorSpace.TYPE_8CLR;
+ break;
+
+ case icSigSpace9CLR:
+ theColorSpace = ColorSpace.TYPE_9CLR;
+ break;
+
+ case icSigSpaceACLR:
+ theColorSpace = ColorSpace.TYPE_ACLR;
+ break;
+
+ case icSigSpaceBCLR:
+ theColorSpace = ColorSpace.TYPE_BCLR;
+ break;
+
+ case icSigSpaceCCLR:
+ theColorSpace = ColorSpace.TYPE_CCLR;
+ break;
+
+ case icSigSpaceDCLR:
+ theColorSpace = ColorSpace.TYPE_DCLR;
+ break;
+
+ case icSigSpaceECLR:
+ theColorSpace = ColorSpace.TYPE_ECLR;
+ break;
+
+ case icSigSpaceFCLR:
+ theColorSpace = ColorSpace.TYPE_FCLR;
+ break;
+
+ default:
+ throw new IllegalArgumentException ("Unknown color space");
+ }
+
+ return theColorSpace;
+ }
+
+
+ static int intFromBigEndian(byte[] array, int index) {
+ return (((array[index] & 0xff) << 24) |
+ ((array[index+1] & 0xff) << 16) |
+ ((array[index+2] & 0xff) << 8) |
+ (array[index+3] & 0xff));
+ }
+
+
+ static void intToBigEndian(int value, byte[] array, int index) {
+ array[index] = (byte) (value >> 24);
+ array[index+1] = (byte) (value >> 16);
+ array[index+2] = (byte) (value >> 8);
+ array[index+3] = (byte) (value);
+ }
+
+
+ static short shortFromBigEndian(byte[] array, int index) {
+ return (short) (((array[index] & 0xff) << 8) |
+ (array[index+1] & 0xff));
+ }
+
+
+ static void shortToBigEndian(short value, byte[] array, int index) {
+ array[index] = (byte) (value >> 8);
+ array[index+1] = (byte) (value);
+ }
+
+
+ /*
+ * fileName may be an absolute or a relative file specification.
+ * Relative file names are looked for in several places: first, relative
+ * to any directories specified by the java.iccprofile.path property;
+ * second, relative to any directories specified by the java.class.path
+ * property; finally, in a directory used to store profiles always
+ * available, such as a profile for sRGB. Built-in profiles use .pf as
+ * the file name extension for profiles, e.g. sRGB.pf.
+ */
+ private static FileInputStream openProfile(final String fileName) {
+ return (FileInputStream)java.security.AccessController.doPrivileged(
+ new java.security.PrivilegedAction() {
+ public Object run() {
+ return privilegedOpenProfile(fileName);
+ }
+ });
+ }
+
+ /*
+ * this version is called from doPrivileged in privilegedOpenProfile.
+ * the whole method is privileged!
+ */
+ private static FileInputStream privilegedOpenProfile(String fileName) {
+ FileInputStream fis = null;
+ String path, dir, fullPath;
+
+ File f = new File(fileName); /* try absolute file name */
+
+ if ((!f.isFile()) &&
+ ((path = System.getProperty("java.iccprofile.path")) != null)){
+ /* try relative to java.iccprofile.path */
+ StringTokenizer st =
+ new StringTokenizer(path, File.pathSeparator);
+ while (st.hasMoreTokens() && (!f.isFile())) {
+ dir = st.nextToken();
+ fullPath = dir + File.separatorChar + fileName;
+ f = new File(fullPath);
+ }
+ }
+
+ if ((!f.isFile()) &&
+ ((path = System.getProperty("java.class.path")) != null)) {
+ /* try relative to java.class.path */
+ StringTokenizer st =
+ new StringTokenizer(path, File.pathSeparator);
+ while (st.hasMoreTokens() && (!f.isFile())) {
+ dir = st.nextToken();
+ fullPath = dir + File.separatorChar + fileName;
+ f = new File(fullPath);
+ }
+ }
+
+ if (!f.isFile()) { /* try the directory of built-in profiles */
+ dir = System.getProperty("java.home") +
+ File.separatorChar + "lib" + File.separatorChar + "cmm";
+ fullPath = dir + File.separatorChar + fileName;
+ f = new File(fullPath);
+ }
+
+ if (f.isFile()) {
+ try {
+ fis = new FileInputStream(f);
+ } catch (FileNotFoundException e) {
+ }
+ }
+ return fis;
+ }
+
+
+ /*
+ * Serialization support.
+ *
+ * Directly deserialized profiles are useless since they are not
+ * registered with CMM. We don't allow constructor to be called
+ * directly and instead have clients to call one of getInstance
+ * factory methods that will register the profile with CMM. For
+ * deserialization we implement readResolve method that will
+ * resolve the bogus deserialized profile object with one obtained
+ * with getInstance as well.
+ *
+ * There're two primary factory methods for construction of ICC
+ * profiles: getInstance(int cspace) and getInstance(byte[] data).
+ * This implementation of ICC_Profile uses the former to return a
+ * cached singleton profile object, other implementations will
+ * likely use this technique too. To preserve the singleton
+ * pattern across serialization we serialize cached singleton
+ * profiles in such a way that deserializing VM could call
+ * getInstance(int cspace) method that will resolve deserialized
+ * object into the corresponding singleton as well.
+ *
+ * Since the singletons are private to ICC_Profile the readResolve
+ * method have to be `protected' instead of `private' so that
+ * singletons that are instances of subclasses of ICC_Profile
+ * could be correctly deserialized.
+ */
+
+
+ /**
+ * Version of the format of additional serialized data in the
+ * stream. Version&nbsp;<code>1</code> corresponds to Java&nbsp;2
+ * Platform,&nbsp;v1.3.
+ * @since 1.3
+ * @serial
+ */
+ private int iccProfileSerializedDataVersion = 1;
+
+
+ /**
+ * Writes default serializable fields to the stream. Writes a
+ * string and an array of bytes to the stream as additional data.
+ *
+ * @param s stream used for serialization.
+ * @throws IOException
+ * thrown by <code>ObjectInputStream</code>.
+ * @serialData
+ * The <code>String</code> is the name of one of
+ * <code>CS_<var>*</var></code> constants defined in the
+ * {@link ColorSpace} class if the profile object is a profile
+ * for a predefined color space (for example
+ * <code>"CS_sRGB"</code>). The string is <code>null</code>
+ * otherwise.
+ * <p>
+ * The <code>byte[]</code> array is the profile data for the
+ * profile. For predefined color spaces <code>null</code> is
+ * written instead of the profile data. If in the future
+ * versions of Java API new predefined color spaces will be
+ * added, future versions of this class may choose to write
+ * for new predefined color spaces not only the color space
+ * name, but the profile data as well so that older versions
+ * could still deserialize the object.
+ */
+ private void writeObject(ObjectOutputStream s)
+ throws IOException
+ {
+ s.defaultWriteObject();
+
+ String csName = null;
+ if (this == sRGBprofile) {
+ csName = "CS_sRGB";
+ } else if (this == XYZprofile) {
+ csName = "CS_CIEXYZ";
+ } else if (this == PYCCprofile) {
+ csName = "CS_PYCC";
+ } else if (this == GRAYprofile) {
+ csName = "CS_GRAY";
+ } else if (this == LINEAR_RGBprofile) {
+ csName = "CS_LINEAR_RGB";
+ }
+
+ // Future versions may choose to write profile data for new
+ // predefined color spaces as well, if any will be introduced,
+ // so that old versions that don't recognize the new CS name
+ // may fall back to constructing profile from the data.
+ byte[] data = null;
+ if (csName == null) {
+ // getData will activate deferred profile if necessary
+ data = getData();
+ }
+
+ s.writeObject(csName);
+ s.writeObject(data);
+ }
+
+ // Temporary storage used by readObject to store resolved profile
+ // (obtained with getInstance) for readResolve to return.
+ private transient ICC_Profile resolvedDeserializedProfile;
+
+ /**
+ * Reads default serializable fields from the stream. Reads from
+ * the stream a string and an array of bytes as additional data.
+ *
+ * @param s stream used for deserialization.
+ * @throws IOException
+ * thrown by <code>ObjectInputStream</code>.
+ * @throws ClassNotFoundException
+ * thrown by <code>ObjectInputStream</code>.
+ * @serialData
+ * The <code>String</code> is the name of one of
+ * <code>CS_<var>*</var></code> constants defined in the
+ * {@link ColorSpace} class if the profile object is a profile
+ * for a predefined color space (for example
+ * <code>"CS_sRGB"</code>). The string is <code>null</code>
+ * otherwise.
+ * <p>
+ * The <code>byte[]</code> array is the profile data for the
+ * profile. It will usually be <code>null</code> for the
+ * predefined profiles.
+ * <p>
+ * If the string is recognized as a constant name for
+ * predefined color space the object will be resolved into
+ * profile obtained with
+ * <code>getInstance(int&nbsp;cspace)</code> and the profile
+ * data are ignored. Otherwise the object will be resolved
+ * into profile obtained with
+ * <code>getInstance(byte[]&nbsp;data)</code>.
+ * @see #readResolve()
+ * @see #getInstance(int)
+ * @see #getInstance(byte[])
+ */
+ private void readObject(ObjectInputStream s)
+ throws IOException, ClassNotFoundException
+ {
+ s.defaultReadObject();
+
+ String csName = (String)s.readObject();
+ byte[] data = (byte[])s.readObject();
+
+ int cspace = 0; // ColorSpace.CS_* constant if known
+ boolean isKnownPredefinedCS = false;
+ if (csName != null) {
+ isKnownPredefinedCS = true;
+ if (csName.equals("CS_sRGB")) {
+ cspace = ColorSpace.CS_sRGB;
+ } else if (csName.equals("CS_CIEXYZ")) {
+ cspace = ColorSpace.CS_CIEXYZ;
+ } else if (csName.equals("CS_PYCC")) {
+ cspace = ColorSpace.CS_PYCC;
+ } else if (csName.equals("CS_GRAY")) {
+ cspace = ColorSpace.CS_GRAY;
+ } else if (csName.equals("CS_LINEAR_RGB")) {
+ cspace = ColorSpace.CS_LINEAR_RGB;
+ } else {
+ isKnownPredefinedCS = false;
+ }
+ }
+
+ if (isKnownPredefinedCS) {
+ resolvedDeserializedProfile = getInstance(cspace);
+ } else {
+ resolvedDeserializedProfile = getInstance(data);
+ }
+ }
+
+ /**
+ * Resolves instances being deserialized into instances registered
+ * with CMM.
+ * @return ICC_Profile object for profile registered with CMM.
+ * @throws ObjectStreamException
+ * never thrown, but mandated by the serialization spec.
+ * @since 1.3
+ */
+ protected Object readResolve() throws ObjectStreamException {
+ return resolvedDeserializedProfile;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/awt/color/ICC_ProfileGray.java Thu Apr 10 16:28:45 2008 -0700
@@ -0,0 +1,150 @@
+/*
+ * Portions Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/**********************************************************************
+ **********************************************************************
+ **********************************************************************
+ *** COPYRIGHT (c) Eastman Kodak Company, 1997 ***
+ *** As an unpublished work pursuant to Title 17 of the United ***
+ *** States Code. All rights reserved. ***
+ **********************************************************************
+ **********************************************************************
+ **********************************************************************/
+
+package java.awt.color;
+
+import java.awt.image.LookupTable;
+import sun.java2d.cmm.ProfileDeferralInfo;
+
+/**
+ *
+ * A subclass of the ICC_Profile class which represents profiles
+ * which meet the following criteria: the color space type of the
+ * profile is TYPE_GRAY and the profile includes the grayTRCTag and
+ * mediaWhitePointTag tags. Examples of this kind of profile are
+ * monochrome input profiles, monochrome display profiles, and
+ * monochrome output profiles. The getInstance methods in the
+ * ICC_Profile class will
+ * return an ICC_ProfileGray object when the above conditions are
+ * met. The advantage of this class is that it provides a lookup
+ * table that Java or native methods may be able to use directly to
+ * optimize color conversion in some cases.
+ * <p>
+ * To transform from a GRAY device profile color space to the CIEXYZ Profile
+ * Connection Space, the device gray component is transformed by
+ * a lookup through the tone reproduction curve (TRC). The result is
+ * treated as the achromatic component of the PCS.
+<pre>
+
+&nbsp; PCSY = grayTRC[deviceGray]
+
+</pre>
+ * The inverse transform is done by converting the PCS Y components to
+ * device Gray via the inverse of the grayTRC.
+ * <p>
+ */
+
+
+
+public class ICC_ProfileGray
+extends ICC_Profile {
+
+ static final long serialVersionUID = -1124721290732002649L;
+
+ /**
+ * Constructs a new ICC_ProfileGray from a CMM ID.
+ */
+ ICC_ProfileGray(long ID) {
+ super(ID);
+ }
+
+ /**
+ * Constructs a new ICC_ProfileGray from a ProfileDeferralInfo object.
+ */
+ ICC_ProfileGray(ProfileDeferralInfo pdi) {
+ super(pdi);
+ }
+
+
+ /**
+ * Returns a float array of length 3 containing the X, Y, and Z
+ * components of the mediaWhitePointTag in the ICC profile.
+ * @return an array containing the components of the
+ * mediaWhitePointTag in the ICC profile.
+ */
+ public float[] getMediaWhitePoint() {
+ return super.getMediaWhitePoint();
+ }
+
+
+ /**
+ * Returns a gamma value representing the tone reproduction
+ * curve (TRC). If the profile represents the TRC as a table rather
+ * than a single gamma value, then an exception is thrown. In this
+ * case the actual table can be obtained via getTRC(). When
+ * using a gamma value, the PCS Y component is computed as follows:
+<pre>
+
+&nbsp; gamma
+&nbsp; PCSY = deviceGray
+
+</pre>
+ * @return the gamma value as a float.
+ * @exception ProfileDataException if the profile does not specify
+ * the TRC as a single gamma value.
+ */
+ public float getGamma() {
+ float theGamma;
+
+ theGamma = super.getGamma(ICC_Profile.icSigGrayTRCTag);
+ return theGamma;
+ }
+
+ /**
+ * Returns the TRC as an array of shorts. If the profile has
+ * specified the TRC as linear (gamma = 1.0) or as a simple gamma
+ * value, this method throws an exception, and the getGamma() method
+ * should be used to get the gamma value. Otherwise the short array
+ * returned here represents a lookup table where the input Gray value
+ * is conceptually in the range [0.0, 1.0]. Value 0.0 maps
+ * to array index 0 and value 1.0 maps to array index length-1.
+ * Interpolation may be used to generate output values for
+ * input values which do not map exactly to an index in the
+ * array. Output values also map linearly to the range [0.0, 1.0].
+ * Value 0.0 is represented by an array value of 0x0000 and
+ * value 1.0 by 0xFFFF, i.e. the values are really unsigned
+ * short values, although they are returned in a short array.
+ * @return a short array representing the TRC.
+ * @exception ProfileDataException if the profile does not specify
+ * the TRC as a table.
+ */
+ public short[] getTRC() {
+ short[] theTRC;
+
+ theTRC = super.getTRC(ICC_Profile.icSigGrayTRCTag);
+ return theTRC;
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/awt/color/ICC_ProfileRGB.java Thu Apr 10 16:28:45 2008 -0700
@@ -0,0 +1,282 @@
+/*
+ * Portions Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/**********************************************************************
+ **********************************************************************
+ **********************************************************************
+ *** COPYRIGHT (c) Eastman Kodak Company, 1997 ***
+ *** As an unpublished work pursuant to Title 17 of the United ***
+ *** States Code. All rights reserved. ***
+ **********************************************************************
+ **********************************************************************
+ **********************************************************************/
+
+package java.awt.color;
+
+import java.awt.image.LookupTable;
+import sun.java2d.cmm.ProfileDeferralInfo;
+
+/**
+ *
+ * The ICC_ProfileRGB class is a subclass of the ICC_Profile class
+ * that represents profiles which meet the following criteria:
+ * <ul>
+ * <li>The profile's color space type is RGB.</li>
+ * <li>The profile includes the <code>redColorantTag</code>,
+ * <code>greenColorantTag</code>, <code>blueColorantTag</code>,
+ * <code>redTRCTag</code>, <code>greenTRCTag</code>,
+ * <code>blueTRCTag</code>, and <code>mediaWhitePointTag</code> tags.</li>
+ * </ul>
+ * The <code>ICC_Profile</code> <code>getInstance</code> method will
+ * return an <code>ICC_ProfileRGB</code> object when these conditions are met.
+ * Three-component, matrix-based input profiles and RGB display profiles are
+ * examples of this type of profile.
+ * <p>
+ * This profile class provides color transform matrices and lookup tables
+ * that Java or native methods can use directly to
+ * optimize color conversion in some cases.
+ * <p>
+ * To transform from a device profile color space to the CIEXYZ Profile
+ * Connection Space, each device color component is first linearized by
+ * a lookup through the corresponding tone reproduction curve (TRC).
+ * The resulting linear RGB components are converted to the CIEXYZ PCS
+ * using a a 3x3 matrix constructed from the RGB colorants.
+ * <pre>
+ *
+ * &nbsp; linearR = redTRC[deviceR]
+ *
+ * &nbsp; linearG = greenTRC[deviceG]
+ *
+ * &nbsp; linearB = blueTRC[deviceB]
+ *
+ * &nbsp; _ _ _ _ _ _
+ * &nbsp;[ PCSX ] [ redColorantX greenColorantX blueColorantX ] [ linearR ]
+ * &nbsp;[ ] [ ] [ ]
+ * &nbsp;[ PCSY ] = [ redColorantY greenColorantY blueColorantY ] [ linearG ]
+ * &nbsp;[ ] [ ] [ ]
+ * &nbsp;[_ PCSZ _] [_ redColorantZ greenColorantZ blueColorantZ _] [_ linearB _]
+ *
+ * </pre>
+ * The inverse transform is performed by converting PCS XYZ components to linear
+ * RGB components through the inverse of the above 3x3 matrix, and then converting
+ * linear RGB to device RGB through inverses of the TRCs.
+ * <p>
+ */
+
+
+
+public class ICC_ProfileRGB
+extends ICC_Profile {
+
+ static final long serialVersionUID = 8505067385152579334L;
+
+ /**
+ * Used to get a gamma value or TRC for the red component.
+ */
+ public static final int REDCOMPONENT = 0;
+
+ /**
+ * Used to get a gamma value or TRC for the green component.
+ */
+ public static final int GREENCOMPONENT = 1;
+
+ /**
+ * Used to get a gamma value or TRC for the blue component.
+ */
+ public static final int BLUECOMPONENT = 2;
+
+
+ /**
+ * Constructs an new <code>ICC_ProfileRGB</code> from a CMM ID.
+ *
+ * @param ID The CMM ID for the profile.
+ *
+ */
+ ICC_ProfileRGB(long ID) {
+ super(ID);
+ }
+
+ /**
+ * Constructs a new <code>ICC_ProfileRGB</code> from a
+ * ProfileDeferralInfo object.
+ *
+ * @param pdi
+ */
+ ICC_ProfileRGB(ProfileDeferralInfo pdi) {
+ super(pdi);
+ }
+
+
+ /**
+ * Returns an array that contains the components of the profile's
+ * <CODE>mediaWhitePointTag</CODE>.
+ *
+ * @return A 3-element <CODE>float</CODE> array containing the x, y,
+ * and z components of the profile's <CODE>mediaWhitePointTag</CODE>.
+ */
+ public float[] getMediaWhitePoint() {
+ return super.getMediaWhitePoint();
+ }
+
+
+ /**
+ * Returns a 3x3 <CODE>float</CODE> matrix constructed from the
+ * X, Y, and Z components of the profile's <CODE>redColorantTag</CODE>,
+ * <CODE>greenColorantTag</CODE>, and <CODE>blueColorantTag</CODE>.
+ * <p>
+ * This matrix can be used for color transforms in the forward
+ * direction of the profile--from the profile color space
+ * to the CIEXYZ PCS.
+ *
+ * @return A 3x3 <CODE>float</CODE> array that contains the x, y, and z
+ * components of the profile's <CODE>redColorantTag</CODE>,
+ * <CODE>greenColorantTag</CODE>, and <CODE>blueColorantTag</CODE>.
+ */
+ public float[][] getMatrix() {
+ float[][] theMatrix = new float[3][3];
+ float[] tmpMatrix;
+
+ tmpMatrix = getXYZTag(ICC_Profile.icSigRedColorantTag);
+ theMatrix[0][0] = tmpMatrix[0];
+ theMatrix[1][0] = tmpMatrix[1];
+ theMatrix[2][0] = tmpMatrix[2];
+ tmpMatrix = getXYZTag(ICC_Profile.icSigGreenColorantTag);
+ theMatrix[0][1] = tmpMatrix[0];
+ theMatrix[1][1] = tmpMatrix[1];
+ theMatrix[2][1] = tmpMatrix[2];
+ tmpMatrix = getXYZTag(ICC_Profile.icSigBlueColorantTag);
+ theMatrix[0][2] = tmpMatrix[0];
+ theMatrix[1][2] = tmpMatrix[1];
+ theMatrix[2][2] = tmpMatrix[2];
+ return theMatrix;
+ }
+
+ /**
+ * Returns a gamma value representing the tone reproduction curve
+ * (TRC) for a particular component. The component parameter
+ * must be one of REDCOMPONENT, GREENCOMPONENT, or BLUECOMPONENT.
+ * <p>
+ * If the profile
+ * represents the TRC for the corresponding component
+ * as a table rather than a single gamma value, an
+ * exception is thrown. In this case the actual table
+ * can be obtained through the {@link #getTRC(int)} method.
+ * When using a gamma value,
+ * the linear component (R, G, or B) is computed as follows:
+ * <pre>
+ *
+ * &nbsp; gamma
+ * &nbsp; linearComponent = deviceComponent
+ *
+ *</pre>
+ * @param component The <CODE>ICC_ProfileRGB</CODE> constant that
+ * represents the component whose TRC you want to retrieve
+ * @return the gamma value as a float.
+ * @exception ProfileDataException if the profile does not specify
+ * the corresponding TRC as a single gamma value.
+ */
+ public float getGamma(int component) {
+ float theGamma;
+ int theSignature;
+
+ switch (component) {
+ case REDCOMPONENT:
+ theSignature = ICC_Profile.icSigRedTRCTag;
+ break;
+
+ case GREENCOMPONENT:
+ theSignature = ICC_Profile.icSigGreenTRCTag;
+ break;
+
+ case BLUECOMPONENT:
+ theSignature = ICC_Profile.icSigBlueTRCTag;
+ break;
+
+ default:
+ throw new IllegalArgumentException("Must be Red, Green, or Blue");
+ }
+
+ theGamma = super.getGamma(theSignature);
+
+ return theGamma;
+ }
+
+ /**
+ * Returns the TRC for a particular component as an array.
+ * Component must be <code>REDCOMPONENT</code>,
+ * <code>GREENCOMPONENT</code>, or <code>BLUECOMPONENT</code>.
+ * Otherwise the returned array
+ * represents a lookup table where the input component value
+ * is conceptually in the range [0.0, 1.0]. Value 0.0 maps
+ * to array index 0 and value 1.0 maps to array index length-1.
+ * Interpolation might be used to generate output values for
+ * input values that do not map exactly to an index in the
+ * array. Output values also map linearly to the range [0.0, 1.0].
+ * Value 0.0 is represented by an array value of 0x0000 and
+ * value 1.0 by 0xFFFF. In other words, the values are really unsigned
+ * <code>short</code> values even though they are returned in a
+ * <code>short</code> array.
+ *
+ * If the profile has specified the corresponding TRC
+ * as linear (gamma = 1.0) or as a simple gamma value, this method
+ * throws an exception. In this case, the {@link #getGamma(int)}
+ * method should be used to get the gamma value.
+ *
+ * @param component The <CODE>ICC_ProfileRGB</CODE> constant that
+ * represents the component whose TRC you want to retrieve:
+ * <CODE>REDCOMPONENT</CODE>, <CODE>GREENCOMPONENT</CODE>, or
+ * <CODE>BLUECOMPONENT</CODE>.
+ *
+ * @return a short array representing the TRC.
+ * @exception ProfileDataException if the profile does not specify
+ * the corresponding TRC as a table.
+ */
+ public short[] getTRC(int component) {
+ short[] theTRC;
+ int theSignature;
+
+ switch (component) {
+ case REDCOMPONENT:
+ theSignature = ICC_Profile.icSigRedTRCTag;
+ break;
+
+ case GREENCOMPONENT:
+ theSignature = ICC_Profile.icSigGreenTRCTag;
+ break;
+
+ case BLUECOMPONENT:
+ theSignature = ICC_Profile.icSigBlueTRCTag;
+ break;
+
+ default:
+ throw new IllegalArgumentException("Must be Red, Green, or Blue");
+ }
+
+ theTRC = super.getTRC(theSignature);
+
+ return theTRC;
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/awt/image/BandedSampleModel.java Thu Apr 10 16:28:45 2008 -0700
@@ -0,0 +1,839 @@
+/*
+ * Portions Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* ****************************************************************
+ ******************************************************************
+ ******************************************************************
+ *** COPYRIGHT (c) Eastman Kodak Company, 1997
+ *** As an unpublished work pursuant to Title 17 of the United
+ *** States Code. All rights reserved.
+ ******************************************************************
+ ******************************************************************
+ ******************************************************************/
+
+package java.awt.image;
+
+/**
+ * This class represents image data which is stored in a band interleaved
+ * fashion and for
+ * which each sample of a pixel occupies one data element of the DataBuffer.
+ * It subclasses ComponentSampleModel but provides a more efficent
+ * implementation for accessing band interleaved image data than is provided
+ * by ComponentSampleModel. This class should typically be used when working
+ * with images which store sample data for each band in a different bank of the
+ * DataBuffer. Accessor methods are provided so that image data can be
+ * manipulated directly. Pixel stride is the number of
+ * data array elements between two samples for the same band on the same
+ * scanline. The pixel stride for a BandedSampleModel is one.
+ * Scanline stride is the number of data array elements between
+ * a given sample and the corresponding sample in the same column of the next
+ * scanline. Band offsets denote the number
+ * of data array elements from the first data array element of the bank
+ * of the DataBuffer holding each band to the first sample of the band.
+ * The bands are numbered from 0 to N-1.
+ * Bank indices denote the correspondence between a bank of the data buffer
+ * and a band of image data. This class supports
+ * {@link DataBuffer#TYPE_BYTE TYPE_BYTE},
+ * {@link DataBuffer#TYPE_USHORT TYPE_USHORT},
+ * {@link DataBuffer#TYPE_SHORT TYPE_SHORT},
+ * {@link DataBuffer#TYPE_INT TYPE_INT},
+ * {@link DataBuffer#TYPE_FLOAT TYPE_FLOAT}, and
+ * {@link DataBuffer#TYPE_DOUBLE TYPE_DOUBLE} datatypes
+ */
+
+
+public final class BandedSampleModel extends ComponentSampleModel
+{
+
+ /**
+ * Constructs a BandedSampleModel with the specified parameters.
+ * The pixel stride will be one data element. The scanline stride
+ * will be the same as the width. Each band will be stored in
+ * a separate bank and all band offsets will be zero.
+ * @param dataType The data type for storing samples.
+ * @param w The width (in pixels) of the region of
+ * image data described.
+ * @param h The height (in pixels) of the region of image
+ * data described.
+ * @param numBands The number of bands for the image data.
+ * @throws IllegalArgumentException if <code>dataType</code> is not
+ * one of the supported data types
+ */
+ public BandedSampleModel(int dataType, int w, int h, int numBands) {
+ super(dataType, w, h, 1, w,
+ BandedSampleModel.createIndicesArray(numBands),
+ BandedSampleModel.createOffsetArray(numBands));
+ }
+
+ /**
+ * Constructs a BandedSampleModel with the specified parameters.
+ * The number of bands will be inferred from the lengths of the
+ * bandOffsets bankIndices arrays, which must be equal. The pixel
+ * stride will be one data element.
+ * @param dataType The data type for storing samples.
+ * @param w The width (in pixels) of the region of
+ * image data described.
+ * @param h The height (in pixels) of the region of
+ * image data described.
+ * @param scanlineStride The line stride of the of the image data.
+ * @param bankIndices The bank index for each band.
+ * @param bandOffsets The band offset for each band.
+ * @throws IllegalArgumentException if <code>dataType</code> is not
+ * one of the supported data types
+ */
+ public BandedSampleModel(int dataType,
+ int w, int h,
+ int scanlineStride,
+ int bankIndices[],
+ int bandOffsets[]) {
+
+ super(dataType, w, h, 1,scanlineStride, bankIndices, bandOffsets);
+ }
+
+ /**
+ * Creates a new BandedSampleModel with the specified
+ * width and height. The new BandedSampleModel will have the same
+ * number of bands, storage data type, and bank indices
+ * as this BandedSampleModel. The band offsets will be compressed
+ * such that the offset between bands will be w*pixelStride and
+ * the minimum of all of the band offsets is zero.
+ * @param w the width of the resulting <code>BandedSampleModel</code>
+ * @param h the height of the resulting <code>BandedSampleModel</code>
+ * @return a new <code>BandedSampleModel</code> with the specified
+ * width and height.
+ * @throws IllegalArgumentException if <code>w</code> or
+ * <code>h</code> equals either
+ * <code>Integer.MAX_VALUE</code> or
+ * <code>Integer.MIN_VALUE</code>
+ * @throws IllegalArgumentException if <code>dataType</code> is not
+ * one of the supported data types
+ */
+ public SampleModel createCompatibleSampleModel(int w, int h) {
+ int[] bandOffs;
+
+ if (numBanks == 1) {
+ bandOffs = orderBands(bandOffsets, w*h);
+ }
+ else {
+ bandOffs = new int[bandOffsets.length];
+ }
+
+ SampleModel sampleModel =
+ new BandedSampleModel(dataType, w, h, w, bankIndices, bandOffs);
+ return sampleModel;
+ }
+
+ /**
+ * Creates a new BandedSampleModel with a subset of the bands of this
+ * BandedSampleModel. The new BandedSampleModel can be
+ * used with any DataBuffer that the existing BandedSampleModel
+ * can be used with. The new BandedSampleModel/DataBuffer
+ * combination will represent an image with a subset of the bands
+ * of the original BandedSampleModel/DataBuffer combination.
+ * @throws RasterFormatException if the number of bands is greater than
+ * the number of banks in this sample model.
+ * @throws IllegalArgumentException if <code>dataType</code> is not
+ * one of the supported data types
+ */
+ public SampleModel createSubsetSampleModel(int bands[]) {
+ if (bands.length > bankIndices.length)
+ throw new RasterFormatException("There are only " +
+ bankIndices.length +
+ " bands");
+ int newBankIndices[] = new int[bands.length];
+ int newBandOffsets[] = new int[bands.length];
+
+ for (int i=0; i<bands.length; i++) {
+ newBankIndices[i] = bankIndices[bands[i]];
+ newBandOffsets[i] = bandOffsets[bands[i]];
+ }
+
+ return new BandedSampleModel(this.dataType, width, height,
+ this.scanlineStride,
+ newBankIndices, newBandOffsets);
+ }
+
+ /**
+ * Creates a DataBuffer that corresponds to this BandedSampleModel,
+ * The DataBuffer's data type, number of banks, and size
+ * will be consistent with this BandedSampleModel.
+ * @throws IllegalArgumentException if <code>dataType</code> is not
+ * one of the supported types.
+ */
+ public DataBuffer createDataBuffer() {
+ DataBuffer dataBuffer = null;
+
+ int size = scanlineStride * height;
+ switch (dataType) {
+ case DataBuffer.TYPE_BYTE:
+ dataBuffer = new DataBufferByte(size, numBanks);
+ break;
+ case DataBuffer.TYPE_USHORT:
+ dataBuffer = new DataBufferUShort(size, numBanks);
+ break;
+ case DataBuffer.TYPE_SHORT:
+ dataBuffer = new DataBufferShort(size, numBanks);
+ break;
+ case DataBuffer.TYPE_INT:
+ dataBuffer = new DataBufferInt(size, numBanks);
+ break;
+ case DataBuffer.TYPE_FLOAT:
+ dataBuffer = new DataBufferFloat(size, numBanks);
+ break;
+ case DataBuffer.TYPE_DOUBLE:
+ dataBuffer = new DataBufferDouble(size, numBanks);
+ break;
+ default:
+ throw new IllegalArgumentException("dataType is not one " +
+ "of the supported types.");
+ }
+
+ return dataBuffer;
+ }
+
+
+ /**
+ * Returns data for a single pixel in a primitive array of type
+ * TransferType. For a BandedSampleModel, this will be the same
+ * as the data type, and samples will be returned one per array
+ * element. Generally, obj
+ * should be passed in as null, so that the Object will be created
+ * automatically and will be of the right primitive data type.
+ * <p>
+ * The following code illustrates transferring data for one pixel from
+ * DataBuffer <code>db1</code>, whose storage layout is described by
+ * BandedSampleModel <code>bsm1</code>, to DataBuffer <code>db2</code>,
+ * whose storage layout is described by
+ * BandedSampleModel <code>bsm2</code>.
+ * The transfer will generally be more efficient than using
+ * getPixel/setPixel.
+ * <pre>
+ * BandedSampleModel bsm1, bsm2;
+ * DataBufferInt db1, db2;
+ * bsm2.setDataElements(x, y, bsm1.getDataElements(x, y, null, db1),
+ * db2);
+ * </pre>
+ * Using getDataElements/setDataElements to transfer between two
+ * DataBuffer/SampleModel pairs is legitimate if the SampleModels have
+ * the same number of bands, corresponding bands have the same number of
+ * bits per sample, and the TransferTypes are the same.
+ * <p>
+ * If obj is non-null, it should be a primitive array of type TransferType.
+ * Otherwise, a ClassCastException is thrown. An
+ * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+ * not in bounds, or if obj is non-null and is not large enough to hold
+ * the pixel data.
+ * @param x The X coordinate of the pixel location
+ * @param y The Y coordinate of the pixel location
+ * @param obj If non-null, a primitive array in which to return
+ * the pixel data.
+ * @param data The DataBuffer containing the image data.
+ * @return the data for the specified pixel.
+ * @see #setDataElements(int, int, Object, DataBuffer)
+ */
+ public Object getDataElements(int x, int y, Object obj, DataBuffer data) {
+ if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
+ throw new ArrayIndexOutOfBoundsException
+ ("Coordinate out of bounds!");
+ }
+ int type = getTransferType();
+ int numDataElems = getNumDataElements();
+ int pixelOffset = y*scanlineStride + x;
+
+ switch(type) {
+
+ case DataBuffer.TYPE_BYTE:
+
+ byte[] bdata;
+
+ if (obj == null) {
+ bdata = new byte[numDataElems];
+ } else {
+ bdata = (byte[])obj;
+ }
+
+ for (int i=0; i<numDataElems; i++) {
+ bdata[i] = (byte)data.getElem(bankIndices[i],
+ pixelOffset + bandOffsets[i]);
+ }
+
+ obj = (Object)bdata;
+ break;
+
+ case DataBuffer.TYPE_USHORT:
+ case DataBuffer.TYPE_SHORT:
+
+ short[] sdata;
+
+ if (obj == null) {
+ sdata = new short[numDataElems];
+ } else {
+ sdata = (short[])obj;
+ }
+
+ for (int i=0; i<numDataElems; i++) {
+ sdata[i] = (short)data.getElem(bankIndices[i],
+ pixelOffset + bandOffsets[i]);
+ }
+
+ obj = (Object)sdata;
+ break;
+
+ case DataBuffer.TYPE_INT:
+
+ int[] idata;
+
+ if (obj == null) {
+ idata = new int[numDataElems];
+ } else {
+ idata = (int[])obj;
+ }
+
+ for (int i=0; i<numDataElems; i++) {
+ idata[i] = data.getElem(bankIndices[i],
+ pixelOffset + bandOffsets[i]);
+ }
+
+ obj = (Object)idata;
+ break;
+
+ case DataBuffer.TYPE_FLOAT:
+
+ float[] fdata;
+
+ if (obj == null) {
+ fdata = new float[numDataElems];
+ } else {
+ fdata = (float[])obj;
+ }
+
+ for (int i=0; i<numDataElems; i++) {
+ fdata[i] = data.getElemFloat(bankIndices[i],
+ pixelOffset + bandOffsets[i]);
+ }
+
+ obj = (Object)fdata;
+ break;
+
+ case DataBuffer.TYPE_DOUBLE:
+
+ double[] ddata;
+
+ if (obj == null) {
+ ddata = new double[numDataElems];
+ } else {
+ ddata = (double[])obj;
+ }
+
+ for (int i=0; i<numDataElems; i++) {
+ ddata[i] = data.getElemDouble(bankIndices[i],
+ pixelOffset + bandOffsets[i]);
+ }
+
+ obj = (Object)ddata;
+ break;
+ }
+
+ return obj;
+ }
+
+ /**
+ * Returns all samples for the specified pixel in an int array.
+ * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+ * not in bounds.
+ * @param x The X coordinate of the pixel location
+ * @param y The Y coordinate of the pixel location
+ * @param iArray If non-null, returns the samples in this array
+ * @param data The DataBuffer containing the image data
+ * @return the samples for the specified pixel.
+ * @see #setPixel(int, int, int[], DataBuffer)
+ */
+ public int[] getPixel(int x, int y, int iArray[], DataBuffer data) {
+ if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
+ throw new ArrayIndexOutOfBoundsException
+ ("Coordinate out of bounds!");
+ }
+
+ int[] pixels;
+
+ if (iArray != null) {
+ pixels = iArray;
+ } else {
+ pixels = new int [numBands];
+ }
+
+ int pixelOffset = y*scanlineStride + x;
+ for (int i=0; i<numBands; i++) {
+ pixels[i] = data.getElem(bankIndices[i],
+ pixelOffset + bandOffsets[i]);
+ }
+ return pixels;
+ }
+
+ /**
+ * Returns all samples for the specified rectangle of pixels in
+ * an int array, one sample per data array element.
+ * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+ * not in bounds.
+ * @param x The X coordinate of the upper left pixel location
+ * @param y The Y coordinate of the upper left pixel location
+ * @param w The width of the pixel rectangle
+ * @param h The height of the pixel rectangle
+ * @param iArray If non-null, returns the samples in this array
+ * @param data The DataBuffer containing the image data
+ * @return the samples for the pixels within the specified region.
+ * @see #setPixels(int, int, int, int, int[], DataBuffer)
+ */
+ public int[] getPixels(int x, int y, int w, int h,
+ int iArray[], DataBuffer data) {
+ if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) {
+ throw new ArrayIndexOutOfBoundsException
+ ("Coordinate out of bounds!");
+ }
+ int[] pixels;
+
+ if (iArray != null) {
+ pixels = iArray;
+ } else {
+ pixels = new int[w*h*numBands];
+ }
+
+ for (int k = 0; k < numBands; k++) {
+ int lineOffset = y*scanlineStride + x + bandOffsets[k];
+ int srcOffset = k;
+ int bank = bankIndices[k];
+
+ for (int i = 0; i < h; i++) {
+ int pixelOffset = lineOffset;
+ for (int j = 0; j < w; j++) {
+ pixels[srcOffset] = data.getElem(bank, pixelOffset++);
+ srcOffset += numBands;
+ }
+ lineOffset += scanlineStride;
+ }
+ }
+ return pixels;
+ }
+
+ /**
+ * Returns as int the sample in a specified band for the pixel
+ * located at (x,y).
+ * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+ * not in bounds.
+ * @param x The X coordinate of the pixel location
+ * @param y The Y coordinate of the pixel location
+ * @param b The band to return
+ * @param data The DataBuffer containing the image data
+ * @return the sample in the specified band for the specified pixel.
+ * @see #setSample(int, int, int, int, DataBuffer)
+ */
+ public int getSample(int x, int y, int b, DataBuffer data) {
+ // Bounds check for 'b' will be performed automatically
+ if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
+ throw new ArrayIndexOutOfBoundsException
+ ("Coordinate out of bounds!");
+ }
+ int sample =
+ data.getElem(bankIndices[b],
+ y*scanlineStride + x + bandOffsets[b]);
+ return sample;
+ }
+
+ /**
+ * Returns the sample in a specified band
+ * for the pixel located at (x,y) as a float.
+ * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+ * not in bounds.
+ * @param x The X coordinate of the pixel location
+ * @param y The Y coordinate of the pixel location
+ * @param b The band to return
+ * @param data The DataBuffer containing the image data
+ * @return a float value that represents the sample in the specified
+ * band for the specified pixel.
+ */
+ public float getSampleFloat(int x, int y, int b, DataBuffer data) {
+ // Bounds check for 'b' will be performed automatically
+ if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
+ throw new ArrayIndexOutOfBoundsException
+ ("Coordinate out of bounds!");
+ }
+
+ float sample = data.getElemFloat(bankIndices[b],
+ y*scanlineStride + x + bandOffsets[b]);
+ return sample;
+ }
+
+ /**
+ * Returns the sample in a specified band
+ * for a pixel located at (x,y) as a double.
+ * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+ * not in bounds.
+ * @param x The X coordinate of the pixel location
+ * @param y The Y coordinate of the pixel location
+ * @param b The band to return
+ * @param data The DataBuffer containing the image data
+ * @return a double value that represents the sample in the specified
+ * band for the specified pixel.
+ */
+ public double getSampleDouble(int x, int y, int b, DataBuffer data) {
+ // Bounds check for 'b' will be performed automatically
+ if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
+ throw new ArrayIndexOutOfBoundsException
+ ("Coordinate out of bounds!");
+ }
+
+ double sample = data.getElemDouble(bankIndices[b],
+ y*scanlineStride + x + bandOffsets[b]);
+ return sample;
+ }
+
+ /**
+ * Returns the samples in a specified band for the specified rectangle
+ * of pixels in an int array, one sample per data array element.
+ * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+ * not in bounds.
+ * @param x The X coordinate of the upper left pixel location
+ * @param y The Y coordinate of the upper left pixel location
+ * @param w The width of the pixel rectangle
+ * @param h The height of the pixel rectangle
+ * @param b The band to return
+ * @param iArray If non-null, returns the samples in this array
+ * @param data The DataBuffer containing the image data
+ * @return the samples in the specified band for the pixels within
+ * the specified region.
+ * @see #setSamples(int, int, int, int, int, int[], DataBuffer)
+ */
+ public int[] getSamples(int x, int y, int w, int h, int b,
+ int iArray[], DataBuffer data) {
+ // Bounds check for 'b' will be performed automatically
+ if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) {
+ throw new ArrayIndexOutOfBoundsException
+ ("Coordinate out of bounds!");
+ }
+ int samples[];
+ if (iArray != null) {
+ samples = iArray;
+ } else {
+ samples = new int [w*h];
+ }
+
+ int lineOffset = y*scanlineStride + x + bandOffsets[b];
+ int srcOffset = 0;
+ int bank = bankIndices[b];
+
+ for (int i = 0; i < h; i++) {
+ int sampleOffset = lineOffset;
+ for (int j = 0; j < w; j++) {
+ samples[srcOffset++] = data.getElem(bank, sampleOffset++);
+ }
+ lineOffset += scanlineStride;
+ }
+ return samples;
+ }
+
+ /**
+ * Sets the data for a single pixel in the specified DataBuffer from a
+ * primitive array of type TransferType. For a BandedSampleModel,
+ * this will be the same as the data type, and samples are transferred
+ * one per array element.
+ * <p>
+ * The following code illustrates transferring data for one pixel from
+ * DataBuffer <code>db1</code>, whose storage layout is described by
+ * BandedSampleModel <code>bsm1</code>, to DataBuffer <code>db2</code>,
+ * whose storage layout is described by
+ * BandedSampleModel <code>bsm2</code>.
+ * The transfer will generally be more efficient than using
+ * getPixel/setPixel.
+ * <pre>
+ * BandedSampleModel bsm1, bsm2;
+ * DataBufferInt db1, db2;
+ * bsm2.setDataElements(x, y, bsm1.getDataElements(x, y, null, db1),
+ * db2);
+ * </pre>
+ * Using getDataElements/setDataElements to transfer between two
+ * DataBuffer/SampleModel pairs is legitimate if the SampleModels have
+ * the same number of bands, corresponding bands have the same number of
+ * bits per sample, and the TransferTypes are the same.
+ * <p>
+ * obj must be a primitive array of type TransferType. Otherwise,
+ * a ClassCastException is thrown. An
+ * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+ * not in bounds, or if obj is not large enough to hold the pixel data.
+ * @param x The X coordinate of the pixel location
+ * @param y The Y coordinate of the pixel location
+ * @param obj If non-null, returns the primitive array in this
+ * object
+ * @param data The DataBuffer containing the image data
+ * @see #getDataElements(int, int, Object, DataBuffer)
+ */
+ public void setDataElements(int x, int y, Object obj, DataBuffer data) {
+ if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
+ throw new ArrayIndexOutOfBoundsException
+ ("Coordinate out of bounds!");
+ }
+ int type = getTransferType();
+ int numDataElems = getNumDataElements();
+ int pixelOffset = y*scanlineStride + x;
+
+ switch(type) {
+
+ case DataBuffer.TYPE_BYTE:
+
+ byte[] barray = (byte[])obj;
+
+ for (int i=0; i<numDataElems; i++) {
+ data.setElem(bankIndices[i], pixelOffset + bandOffsets[i],
+ barray[i] & 0xff);
+ }
+ break;
+
+ case DataBuffer.TYPE_USHORT:
+ case DataBuffer.TYPE_SHORT:
+
+ short[] sarray = (short[])obj;
+
+ for (int i=0; i<numDataElems; i++) {
+ data.setElem(bankIndices[i], pixelOffset + bandOffsets[i],
+ sarray[i] & 0xffff);
+ }
+ break;
+
+ case DataBuffer.TYPE_INT:
+
+ int[] iarray = (int[])obj;
+
+ for (int i=0; i<numDataElems; i++) {
+ data.setElem(bankIndices[i], pixelOffset + bandOffsets[i],
+ iarray[i]);
+ }
+ break;
+
+ case DataBuffer.TYPE_FLOAT:
+
+ float[] farray = (float[])obj;
+
+ for (int i=0; i<numDataElems; i++) {
+ data.setElemFloat(bankIndices[i], pixelOffset + bandOffsets[i],
+ farray[i]);
+ }
+ break;
+
+ case DataBuffer.TYPE_DOUBLE:
+
+ double[] darray = (double[])obj;
+
+ for (int i=0; i<numDataElems; i++) {
+ data.setElemDouble(bankIndices[i], pixelOffset + bandOffsets[i],
+ darray[i]);
+ }
+ break;
+
+ }
+ }
+
+ /**
+ * Sets a pixel in the DataBuffer using an int array of samples for input.
+ * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+ * not in bounds.
+ * @param x The X coordinate of the pixel location
+ * @param y The Y coordinate of the pixel location
+ * @param iArray The input samples in an int array
+ * @param data The DataBuffer containing the image data
+ * @see #getPixel(int, int, int[], DataBuffer)
+ */
+ public void setPixel(int x, int y, int iArray[], DataBuffer data) {
+ if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
+ throw new ArrayIndexOutOfBoundsException
+ ("Coordinate out of bounds!");
+ }
+ int pixelOffset = y*scanlineStride + x;
+ for (int i=0; i<numBands; i++) {
+ data.setElem(bankIndices[i], pixelOffset + bandOffsets[i],
+ iArray[i]);
+ }
+ }
+
+ /**
+ * Sets all samples for a rectangle of pixels from an int array containing
+ * one sample per array element.
+ * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+ * not in bounds.
+ * @param x The X coordinate of the upper left pixel location
+ * @param y The Y coordinate of the upper left pixel location
+ * @param w The width of the pixel rectangle
+ * @param h The height of the pixel rectangle
+ * @param iArray The input samples in an int array
+ * @param data The DataBuffer containing the image data
+ * @see #getPixels(int, int, int, int, int[], DataBuffer)
+ */
+ public void setPixels(int x, int y, int w, int h,
+ int iArray[], DataBuffer data) {
+ if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) {
+ throw new ArrayIndexOutOfBoundsException
+ ("Coordinate out of bounds!");
+ }
+
+ for (int k = 0; k < numBands; k++) {
+ int lineOffset = y*scanlineStride + x + bandOffsets[k];
+ int srcOffset = k;
+ int bank = bankIndices[k];
+
+ for (int i = 0; i < h; i++) {
+ int pixelOffset = lineOffset;
+ for (int j = 0; j < w; j++) {
+ data.setElem(bank, pixelOffset++, iArray[srcOffset]);
+ srcOffset += numBands;
+ }
+ lineOffset += scanlineStride;
+ }
+ }
+ }
+
+ /**
+ * Sets a sample in the specified band for the pixel located at (x,y)
+ * in the DataBuffer using an int for input.
+ * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+ * not in bounds.
+ * @param x The X coordinate of the pixel location
+ * @param y The Y coordinate of the pixel location
+ * @param b The band to set
+ * @param s The input sample as an int
+ * @param data The DataBuffer containing the image data
+ * @see #getSample(int, int, int, DataBuffer)
+ */
+ public void setSample(int x, int y, int b, int s,
+ DataBuffer data) {
+ // Bounds check for 'b' will be performed automatically
+ if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
+ throw new ArrayIndexOutOfBoundsException
+ ("Coordinate out of bounds!");
+ }
+ data.setElem(bankIndices[b],
+ y*scanlineStride + x + bandOffsets[b], s);
+ }
+
+ /**
+ * Sets a sample in the specified band for the pixel located at (x,y)
+ * in the DataBuffer using a float for input.
+ * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+ * not in bounds.
+ * @param x The X coordinate of the pixel location
+ * @param y The Y coordinate of the pixel location
+ * @param b The band to set
+ * @param s The input sample as a float
+ * @param data The DataBuffer containing the image data
+ * @see #getSample(int, int, int, DataBuffer)
+ */
+ public void setSample(int x, int y, int b,
+ float s ,
+ DataBuffer data) {
+ // Bounds check for 'b' will be performed automatically
+ if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
+ throw new ArrayIndexOutOfBoundsException
+ ("Coordinate out of bounds!");
+ }
+ data.setElemFloat(bankIndices[b],
+ y*scanlineStride + x + bandOffsets[b], s);
+ }
+
+ /**
+ * Sets a sample in the specified band for the pixel located at (x,y)
+ * in the DataBuffer using a double for input.
+ * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+ * not in bounds.
+ * @param x The X coordinate of the pixel location
+ * @param y The Y coordinate of the pixel location
+ * @param b The band to set
+ * @param s The input sample as a double
+ * @param data The DataBuffer containing the image data
+ * @see #getSample(int, int, int, DataBuffer)
+ */
+ public void setSample(int x, int y, int b,
+ double s,
+ DataBuffer data) {
+ // Bounds check for 'b' will be performed automatically
+ if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
+ throw new ArrayIndexOutOfBoundsException
+ ("Coordinate out of bounds!");
+ }
+ data.setElemDouble(bankIndices[b],
+ y*scanlineStride + x + bandOffsets[b], s);
+ }
+
+ /**
+ * Sets the samples in the specified band for the specified rectangle
+ * of pixels from an int array containing one sample per data array element.
+ * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
+ * not in bounds.
+ * @param x The X coordinate of the upper left pixel location
+ * @param y The Y coordinate of the upper left pixel location
+ * @param w The width of the pixel rectangle
+ * @param h The height of the pixel rectangle
+ * @param b The band to set
+ * @param iArray The input sample array
+ * @param data The DataBuffer containing the image data
+ * @see #getSamples(int, int, int, int, int, int[], DataBuffer)
+ */
+ public void setSamples(int x, int y, int w, int h, int b,
+ int iArray[], DataBuffer data) {
+ // Bounds check for 'b' will be performed automatically
+ if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) {
+ throw new ArrayIndexOutOfBoundsException
+ ("Coordinate out of bounds!");
+ }
+ int lineOffset = y*scanlineStride + x + bandOffsets[b];
+ int srcOffset = 0;
+ int bank = bankIndices[b];
+
+ for (int i = 0; i < h; i++) {
+ int sampleOffset = lineOffset;
+ for (int j = 0; j < w; j++) {
+ data.setElem(bank, sampleOffset++, iArray[srcOffset++]);
+ }
+ lineOffset += scanlineStride;
+ }
+ }
+
+ private static int[] createOffsetArray(int numBands) {
+ int[] bandOffsets = new int[numBands];
+ for (int i=0; i < numBands; i++) {
+ bandOffsets[i] = 0;
+ }
+ return bandOffsets;
+ }
+
+ private static int[] createIndicesArray(int numBands) {
+ int[] bankIndices = new int[numBands];
+ for (int i=0; i < numBands; i++) {
+ bankIndices[i] = i;
+ }
+ return bankIndices;
+ }
+
+ // Differentiate hash code from other ComponentSampleModel subclasses
+ public int hashCode() {
+ return super.hashCode() ^ 0x2;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/awt/image/ColorConvertOp.java Thu Apr 10 16:28:45 2008 -0700
@@ -0,0 +1,1109 @@
+/*
+ * Portions Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/**********************************************************************
+ **********************************************************************
+ **********************************************************************
+ *** COPYRIGHT (c) Eastman Kodak Company, 1997 ***
+ *** As an unpublished work pursuant to Title 17 of the United ***
+ *** States Code. All rights reserved. ***
+ **********************************************************************
+ **********************************************************************
+ **********************************************************************/
+
+package java.awt.image;
+
+import java.awt.Point;
+import java.awt.Graphics2D;
+import java.awt.color.*;
+import sun.java2d.cmm.ColorTransform;
+import sun.java2d.cmm.CMSManager;
+import sun.java2d.cmm.ProfileDeferralMgr;
+import sun.java2d.cmm.PCMM;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.Point2D;
+import java.awt.RenderingHints;
+
+/**
+ * This class performs a pixel-by-pixel color conversion of the data in
+ * the source image. The resulting color values are scaled to the precision
+ * of the destination image. Color conversion can be specified
+ * via an array of ColorSpace objects or an array of ICC_Profile objects.
+ * <p>
+ * If the source is a BufferedImage with premultiplied alpha, the
+ * color components are divided by the alpha component before color conversion.
+ * If the destination is a BufferedImage with premultiplied alpha, the
+ * color components are multiplied by the alpha component after conversion.
+ * Rasters are treated as having no alpha channel, i.e. all bands are
+ * color bands.
+ * <p>
+ * If a RenderingHints object is specified in the constructor, the
+ * color rendering hint and the dithering hint may be used to control
+ * color conversion.
+ * <p>
+ * Note that Source and Destination may be the same object.
+ * <p>
+ * @see java.awt.RenderingHints#KEY_COLOR_RENDERING
+ * @see java.awt.RenderingHints#KEY_DITHERING
+ */
+public class ColorConvertOp implements BufferedImageOp, RasterOp {
+ ICC_Profile[] profileList;
+ ColorSpace[] CSList;
+ ColorTransform thisTransform, thisRasterTransform;
+ ICC_Profile thisSrcProfile, thisDestProfile;
+ RenderingHints hints;
+ boolean gotProfiles;
+ float[] srcMinVals, srcMaxVals, dstMinVals, dstMaxVals;
+
+ /* the class initializer */
+ static {
+ if (ProfileDeferralMgr.deferring) {
+ ProfileDeferralMgr.activateProfiles();
+ }
+ }
+
+ /**
+ * Constructs a new ColorConvertOp which will convert
+ * from a source color space to a destination color space.
+ * The RenderingHints argument may be null.
+ * This Op can be used only with BufferedImages, and will convert
+ * directly from the ColorSpace of the source image to that of the
+ * destination. The destination argument of the filter method
+ * cannot be specified as null.
+ * @param hints the <code>RenderingHints</code> object used to control
+ * the color conversion, or <code>null</code>
+ */
+ public ColorConvertOp (RenderingHints hints)
+ {
+ profileList = new ICC_Profile [0]; /* 0 length list */
+ this.hints = hints;
+ }
+
+ /**
+ * Constructs a new ColorConvertOp from a ColorSpace object.
+ * The RenderingHints argument may be null. This
+ * Op can be used only with BufferedImages, and is primarily useful
+ * when the {@link #filter(BufferedImage, BufferedImage) filter}
+ * method is invoked with a destination argument of null.
+ * In that case, the ColorSpace defines the destination color space
+ * for the destination created by the filter method. Otherwise, the
+ * ColorSpace defines an intermediate space to which the source is
+ * converted before being converted to the destination space.
+ * @param cspace defines the destination <code>ColorSpace</code> or an
+ * intermediate <code>ColorSpace</code>
+ * @param hints the <code>RenderingHints</code> object used to control
+ * the color conversion, or <code>null</code>
+ * @throws NullPointerException if cspace is null
+ */
+ public ColorConvertOp (ColorSpace cspace, RenderingHints hints)
+ {
+ if (cspace == null) {
+ throw new NullPointerException("ColorSpace cannot be null");
+ }
+ if (cspace instanceof ICC_ColorSpace) {
+ profileList = new ICC_Profile [1]; /* 1 profile in the list */
+
+ profileList [0] = ((ICC_ColorSpace) cspace).getProfile();
+ }
+ else {
+ CSList = new ColorSpace[1]; /* non-ICC case: 1 ColorSpace in list */
+ CSList[0] = cspace;
+ }
+ this.hints = hints;
+ }
+
+
+ /**
+ * Constructs a new ColorConvertOp from two ColorSpace objects.
+ * The RenderingHints argument may be null.
+ * This Op is primarily useful for calling the filter method on
+ * Rasters, in which case the two ColorSpaces define the operation
+ * to be performed on the Rasters. In that case, the number of bands
+ * in the source Raster must match the number of components in
+ * srcCspace, and the number of bands in the destination Raster
+ * must match the number of components in dstCspace. For BufferedImages,
+ * the two ColorSpaces define intermediate spaces through which the
+ * source is converted before being converted to the destination space.
+ * @param srcCspace the source <code>ColorSpace</code>
+ * @param dstCspace the destination <code>ColorSpace</code>
+ * @param hints the <code>RenderingHints</code> object used to control
+ * the color conversion, or <code>null</code>
+ * @throws NullPointerException if either srcCspace or dstCspace is null
+ */
+ public ColorConvertOp(ColorSpace srcCspace, ColorSpace dstCspace,
+ RenderingHints hints)
+ {
+ if ((srcCspace == null) || (dstCspace == null)) {
+ throw new NullPointerException("ColorSpaces cannot be null");
+ }
+ if ((srcCspace instanceof ICC_ColorSpace) &&
+ (dstCspace instanceof ICC_ColorSpace)) {
+ profileList = new ICC_Profile [2]; /* 2 profiles in the list */
+
+ profileList [0] = ((ICC_ColorSpace) srcCspace).getProfile();
+ profileList [1] = ((ICC_ColorSpace) dstCspace).getProfile();
+
+ getMinMaxValsFromColorSpaces(srcCspace, dstCspace);
+ } else {
+ /* non-ICC case: 2 ColorSpaces in list */
+ CSList = new ColorSpace[2];
+ CSList[0] = srcCspace;
+ CSList[1] = dstCspace;
+ }
+ this.hints = hints;
+ }
+
+
+ /**
+ * Constructs a new ColorConvertOp from an array of ICC_Profiles.
+ * The RenderingHints argument may be null.
+ * The sequence of profiles may include profiles that represent color
+ * spaces, profiles that represent effects, etc. If the whole sequence
+ * does not represent a well-defined color conversion, an exception is
+ * thrown.
+ * <p>For BufferedImages, if the ColorSpace
+ * of the source BufferedImage does not match the requirements of the
+ * first profile in the array,
+ * the first conversion is to an appropriate ColorSpace.
+ * If the requirements of the last profile in the array are not met
+ * by the ColorSpace of the destination BufferedImage,
+ * the last conversion is to the destination's ColorSpace.
+ * <p>For Rasters, the number of bands in the source Raster must match
+ * the requirements of the first profile in the array, and the
+ * number of bands in the destination Raster must match the requirements
+ * of the last profile in the array. The array must have at least two
+ * elements or calling the filter method for Rasters will throw an
+ * IllegalArgumentException.
+ * @param profiles the array of <code>ICC_Profile</code> objects
+ * @param hints the <code>RenderingHints</code> object used to control
+ * the color conversion, or <code>null</code>
+ * @exception IllegalArgumentException when the profile sequence does not
+ * specify a well-defined color conversion
+ * @exception NullPointerException if profiles is null
+ */
+ public ColorConvertOp (ICC_Profile[] profiles, RenderingHints hints)
+ {
+ if (profiles == null) {
+ throw new NullPointerException("Profiles cannot be null");
+ }
+ gotProfiles = true;
+ profileList = new ICC_Profile[profiles.length];
+ for (int i1 = 0; i1 < profiles.length; i1++) {
+ profileList[i1] = profiles[i1];
+ }
+ this.hints = hints;
+ }
+
+
+ /**
+ * Returns the array of ICC_Profiles used to construct this ColorConvertOp.
+ * Returns null if the ColorConvertOp was not constructed from such an
+ * array.
+ * @return the array of <code>ICC_Profile</code> objects of this
+ * <code>ColorConvertOp</code>, or <code>null</code> if this
+ * <code>ColorConvertOp</code> was not constructed with an
+ * array of <code>ICC_Profile</code> objects.
+ */
+ public final ICC_Profile[] getICC_Profiles() {
+ if (gotProfiles) {
+ ICC_Profile[] profiles = new ICC_Profile[profileList.length];
+ for (int i1 = 0; i1 < profileList.length; i1++) {
+ profiles[i1] = profileList[i1];
+ }
+ return profiles;
+ }
+ return null;
+ }
+
+ /**
+ * ColorConverts the source BufferedImage.
+ * If the destination image is null,
+ * a BufferedImage will be created with an appropriate ColorModel.
+ * @param src the source <code>BufferedImage</code> to be converted
+ * @param dest the destination <code>BufferedImage</code>,
+ * or <code>null</code>
+ * @return <code>dest</code> color converted from <code>src</code>
+ * or a new, converted <code>BufferedImage</code>
+ * if <code>dest</code> is <code>null</code>
+ * @exception IllegalArgumentException if dest is null and this op was
+ * constructed using the constructor which takes only a
+ * RenderingHints argument, since the operation is ill defined.
+ */
+ public final BufferedImage filter(BufferedImage src, BufferedImage dest) {
+ ColorSpace srcColorSpace, destColorSpace;
+ BufferedImage savdest = null;
+
+ if (src.getColorModel() instanceof IndexColorModel) {
+ IndexColorModel icm = (IndexColorModel) src.getColorModel();
+ src = icm.convertToIntDiscrete(src.getRaster(), true);
+ }
+ srcColorSpace = src.getColorModel().getColorSpace();
+ if (dest != null) {
+ if (dest.getColorModel() instanceof IndexColorModel) {
+ savdest = dest;
+ dest = null;
+ destColorSpace = null;
+ } else {
+ destColorSpace = dest.getColorModel().getColorSpace();
+ }
+ } else {
+ destColorSpace = null;
+ }
+
+ if ((CSList != null) ||
+ (!(srcColorSpace instanceof ICC_ColorSpace)) ||
+ ((dest != null) &&
+ (!(destColorSpace instanceof ICC_ColorSpace)))) {
+ /* non-ICC case */
+ dest = nonICCBIFilter(src, srcColorSpace, dest, destColorSpace);
+ } else {
+ dest = ICCBIFilter(src, srcColorSpace, dest, destColorSpace);
+ }
+
+ if (savdest != null) {
+ Graphics2D big = savdest.createGraphics();
+ try {
+ big.drawImage(dest, 0, 0, null);
+ } finally {
+ big.dispose();
+ }
+ return savdest;
+ } else {
+ return dest;
+ }
+ }
+
+ private final BufferedImage ICCBIFilter(BufferedImage src,
+ ColorSpace srcColorSpace,
+ BufferedImage dest,
+ ColorSpace destColorSpace) {
+ int nProfiles = profileList.length;
+ ICC_Profile srcProfile = null, destProfile = null;
+
+ srcProfile = ((ICC_ColorSpace) srcColorSpace).getProfile();
+
+ if (dest == null) { /* last profile in the list defines
+ the output color space */
+ if (nProfiles == 0) {
+ throw new IllegalArgumentException(
+ "Destination ColorSpace is undefined");
+ }
+ destProfile = profileList [nProfiles - 1];
+ dest = createCompatibleDestImage(src, null);
+ }
+ else {
+ if (src.getHeight() != dest.getHeight() ||
+ src.getWidth() != dest.getWidth()) {
+ throw new IllegalArgumentException(
+ "Width or height of BufferedImages do not match");
+ }
+ destProfile = ((ICC_ColorSpace) destColorSpace).getProfile();
+ }
+
+ /* Checking if all profiles in the transform sequence are the same.
+ * If so, performing just copying the data.
+ */
+ if (srcProfile == destProfile) {
+ boolean noTrans = true;
+ for (int i = 0; i < nProfiles; i++) {
+ if (srcProfile != profileList[i]) {
+ noTrans = false;
+ break;
+ }
+ }
+ if (noTrans) {
+ Graphics2D g = dest.createGraphics();
+ try {
+ g.drawImage(src, 0, 0, null);
+ } finally {
+ g.dispose();
+ }
+
+ return dest;
+ }
+ }
+
+ /* make a new transform if needed */
+ if ((thisTransform == null) || (thisSrcProfile != srcProfile) ||
+ (thisDestProfile != destProfile) ) {
+ updateBITransform(srcProfile, destProfile);
+ }
+
+ /* color convert the image */
+ thisTransform.colorConvert(src, dest);
+
+ return dest;
+ }
+
+ private void updateBITransform(ICC_Profile srcProfile,
+ ICC_Profile destProfile) {
+ ICC_Profile[] theProfiles;
+ int i1, nProfiles, nTransforms, whichTrans, renderState;
+ ColorTransform[] theTransforms;
+ boolean useSrc = false, useDest = false;
+
+ nProfiles = profileList.length;
+ nTransforms = nProfiles;
+ if ((nProfiles == 0) || (srcProfile != profileList[0])) {
+ nTransforms += 1;
+ useSrc = true;
+ }
+ if ((nProfiles == 0) || (destProfile != profileList[nProfiles - 1]) ||
+ (nTransforms < 2)) {
+ nTransforms += 1;
+ useDest = true;
+ }
+
+ /* make the profile list */
+ theProfiles = new ICC_Profile[nTransforms]; /* the list of profiles
+ for this Op */
+
+ int idx = 0;
+ if (useSrc) {
+ /* insert source as first profile */
+ theProfiles[idx++] = srcProfile;
+ }
+
+ for (i1 = 0; i1 < nProfiles; i1++) {
+ /* insert profiles defined in this Op */
+ theProfiles[idx++] = profileList [i1];
+ }
+
+ if (useDest) {
+ /* insert dest as last profile */
+ theProfiles[idx] = destProfile;
+ }
+
+ /* make the transform list */
+ theTransforms = new ColorTransform [nTransforms];
+
+ /* initialize transform get loop */
+ if (theProfiles[0].getProfileClass() == ICC_Profile.CLASS_OUTPUT) {
+ /* if first profile is a printer
+ render as colorimetric */
+ renderState = ICC_Profile.icRelativeColorimetric;
+ }
+ else {
+ renderState = ICC_Profile.icPerceptual; /* render any other
+ class perceptually */
+ }
+
+ whichTrans = ColorTransform.In;
+
+ PCMM mdl = CMSManager.getModule();
+
+ /* get the transforms from each profile */
+ for (i1 = 0; i1 < nTransforms; i1++) {
+ if (i1 == nTransforms -1) { /* last profile? */
+ whichTrans = ColorTransform.Out; /* get output transform */
+ }
+ else { /* check for abstract profile */
+ if ((whichTrans == ColorTransform.Simulation) &&
+ (theProfiles[i1].getProfileClass () ==
+ ICC_Profile.CLASS_ABSTRACT)) {
+ renderState = ICC_Profile.icPerceptual;
+ whichTrans = ColorTransform.In;
+ }
+ }
+
+ theTransforms[i1] = mdl.createTransform (
+ theProfiles[i1], renderState, whichTrans);
+
+ /* get this profile's rendering intent to select transform
+ from next profile */
+ renderState = getRenderingIntent(theProfiles[i1]);
+
+ /* "middle" profiles use simulation transform */
+ whichTrans = ColorTransform.Simulation;
+ }
+
+ /* make the net transform */
+ thisTransform = mdl.createTransform(theTransforms);
+
+ /* update corresponding source and dest profiles */
+ thisSrcProfile = srcProfile;
+ thisDestProfile = destProfile;
+ }
+
+ /**
+ * ColorConverts the image data in the source Raster.
+ * If the destination Raster is null, a new Raster will be created.
+ * The number of bands in the source and destination Rasters must
+ * meet the requirements explained above. The constructor used to
+ * create this ColorConvertOp must have provided enough information
+ * to define both source and destination color spaces. See above.
+ * Otherwise, an exception is thrown.
+ * @param src the source <code>Raster</code> to be converted
+ * @param dest the destination <code>WritableRaster</code>,
+ * or <code>null</code>
+ * @return <code>dest</code> color converted from <code>src</code>
+ * or a new, converted <code>WritableRaster</code>
+ * if <code>dest</code> is <code>null</code>
+ * @exception IllegalArgumentException if the number of source or
+ * destination bands is incorrect, the source or destination
+ * color spaces are undefined, or this op was constructed
+ * with one of the constructors that applies only to
+ * operations on BufferedImages.
+ */
+ public final WritableRaster filter (Raster src, WritableRaster dest) {
+
+ if (CSList != null) {
+ /* non-ICC case */
+ return nonICCRasterFilter(src, dest);
+ }
+ int nProfiles = profileList.length;
+ if (nProfiles < 2) {
+ throw new IllegalArgumentException(
+ "Source or Destination ColorSpace is undefined");
+ }
+ if (src.getNumBands() != profileList[0].getNumComponents()) {
+ throw new IllegalArgumentException(
+ "Numbers of source Raster bands and source color space " +
+ "components do not match");
+ }
+ if (dest == null) {
+ dest = createCompatibleDestRaster(src);
+ }
+ else {
+ if (src.getHeight() != dest.getHeight() ||
+ src.getWidth() != dest.getWidth()) {
+ throw new IllegalArgumentException(
+ "Width or height of Rasters do not match");
+ }
+ if (dest.getNumBands() !=
+ profileList[nProfiles-1].getNumComponents()) {
+ throw new IllegalArgumentException(
+ "Numbers of destination Raster bands and destination " +
+ "color space components do not match");
+ }
+ }
+
+ /* make a new transform if needed */
+ if (thisRasterTransform == null) {
+ int i1, whichTrans, renderState;
+ ColorTransform[] theTransforms;
+
+ /* make the transform list */
+ theTransforms = new ColorTransform [nProfiles];
+
+ /* initialize transform get loop */
+ if (profileList[0].getProfileClass() == ICC_Profile.CLASS_OUTPUT) {
+ /* if first profile is a printer
+ render as colorimetric */
+ renderState = ICC_Profile.icRelativeColorimetric;
+ }
+ else {
+ renderState = ICC_Profile.icPerceptual; /* render any other
+ class perceptually */
+ }
+
+ whichTrans = ColorTransform.In;
+
+ PCMM mdl = CMSManager.getModule();
+
+ /* get the transforms from each profile */
+ for (i1 = 0; i1 < nProfiles; i1++) {
+ if (i1 == nProfiles -1) { /* last profile? */
+ whichTrans = ColorTransform.Out; /* get output transform */
+ }
+ else { /* check for abstract profile */
+ if ((whichTrans == ColorTransform.Simulation) &&
+ (profileList[i1].getProfileClass () ==
+ ICC_Profile.CLASS_ABSTRACT)) {
+ renderState = ICC_Profile.icPerceptual;
+ whichTrans = ColorTransform.In;
+ }
+ }
+
+ theTransforms[i1] = mdl.createTransform (
+ profileList[i1], renderState, whichTrans);
+
+ /* get this profile's rendering intent to select transform
+ from next profile */
+ renderState = getRenderingIntent(profileList[i1]);
+
+ /* "middle" profiles use simulation transform */
+ whichTrans = ColorTransform.Simulation;
+ }
+
+ /* make the net transform */
+ thisRasterTransform = mdl.createTransform(theTransforms);
+ }
+
+ int srcTransferType = src.getTransferType();
+ int dstTransferType = dest.getTransferType();
+ if ((srcTransferType == DataBuffer.TYPE_FLOAT) ||
+ (srcTransferType == DataBuffer.TYPE_DOUBLE) ||
+ (dstTransferType == DataBuffer.TYPE_FLOAT) ||
+ (dstTransferType == DataBuffer.TYPE_DOUBLE)) {
+ if (srcMinVals == null) {
+ getMinMaxValsFromProfiles(profileList[0],
+ profileList[nProfiles-1]);
+ }
+ /* color convert the raster */
+ thisRasterTransform.colorConvert(src, dest,
+ srcMinVals, srcMaxVals,
+ dstMinVals, dstMaxVals);
+ } else {
+ /* color convert the raster */
+ thisRasterTransform.colorConvert(src, dest);
+ }
+
+
+ return dest;
+ }
+
+ /**
+ * Returns the bounding box of the destination, given this source.
+ * Note that this will be the same as the the bounding box of the
+ * source.
+ * @param src the source <code>BufferedImage</code>
+ * @return a <code>Rectangle2D</code> that is the bounding box
+ * of the destination, given the specified <code>src</code>
+ */
+ public final Rectangle2D getBounds2D (BufferedImage src) {
+ return getBounds2D(src.getRaster());
+ }
+
+ /**
+ * Returns the bounding box of the destination, given this source.
+ * Note that this will be the same as the the bounding box of the
+ * source.
+ * @param src the source <code>Raster</code>
+ * @return a <code>Rectangle2D</code> that is the bounding box
+ * of the destination, given the specified <code>src</code>
+ */
+ public final Rectangle2D getBounds2D (Raster src) {
+ /* return new Rectangle (src.getXOffset(),
+ src.getYOffset(),
+ src.getWidth(), src.getHeight()); */
+ return src.getBounds();
+ }
+
+ /**
+ * Creates a zeroed destination image with the correct size and number of
+ * bands, given this source.
+ * @param src Source image for the filter operation.
+ * @param destCM ColorModel of the destination. If null, an
+ * appropriate ColorModel will be used.
+ * @return a <code>BufferedImage</code> with the correct size and
+ * number of bands from the specified <code>src</code>.
+ * @throws IllegalArgumentException if <code>destCM</code> is
+ * <code>null</code> and this <code>ColorConvertOp</code> was
+ * created without any <code>ICC_Profile</code> or
+ * <code>ColorSpace</code> defined for the destination
+ */
+ public BufferedImage createCompatibleDestImage (BufferedImage src,
+ ColorModel destCM) {
+ ColorSpace cs = null;;
+ if (destCM == null) {
+ if (CSList == null) {
+ /* ICC case */
+ int nProfiles = profileList.length;
+ if (nProfiles == 0) {
+ throw new IllegalArgumentException(
+ "Destination ColorSpace is undefined");
+ }
+ ICC_Profile destProfile = profileList[nProfiles - 1];
+ cs = new ICC_ColorSpace(destProfile);
+ } else {
+ /* non-ICC case */
+ int nSpaces = CSList.length;
+ cs = CSList[nSpaces - 1];
+ }
+ }
+ return createCompatibleDestImage(src, destCM, cs);
+ }
+
+ private BufferedImage createCompatibleDestImage(BufferedImage src,
+ ColorModel destCM,
+ ColorSpace destCS) {
+ BufferedImage image;
+ if (destCM == null) {
+ ColorModel srcCM = src.getColorModel();
+ int nbands = destCS.getNumComponents();
+ boolean hasAlpha = srcCM.hasAlpha();
+ if (hasAlpha) {
+ nbands += 1;
+ }
+ int[] nbits = new int[nbands];
+ for (int i = 0; i < nbands; i++) {
+ nbits[i] = 8;
+ }
+ destCM = new ComponentColorModel(destCS, nbits, hasAlpha,
+ srcCM.isAlphaPremultiplied(),
+ srcCM.getTransparency(),
+ DataBuffer.TYPE_BYTE);
+ }
+ int w = src.getWidth();
+ int h = src.getHeight();
+ image = new BufferedImage(destCM,
+ destCM.createCompatibleWritableRaster(w, h),
+ destCM.isAlphaPremultiplied(), null);
+ return image;
+ }
+
+
+ /**
+ * Creates a zeroed destination Raster with the correct size and number of
+ * bands, given this source.
+ * @param src the specified <code>Raster</code>
+ * @return a <code>WritableRaster</code> with the correct size and number
+ * of bands from the specified <code>src</code>
+ * @throws IllegalArgumentException if this <code>ColorConvertOp</code>
+ * was created without sufficient information to define the
+ * <code>dst</code> and <code>src</code> color spaces
+ */
+ public WritableRaster createCompatibleDestRaster (Raster src) {
+ int ncomponents;
+
+ if (CSList != null) {
+ /* non-ICC case */
+ if (CSList.length != 2) {
+ throw new IllegalArgumentException(
+ "Destination ColorSpace is undefined");
+ }
+ ncomponents = CSList[1].getNumComponents();
+ } else {
+ /* ICC case */
+ int nProfiles = profileList.length;
+ if (nProfiles < 2) {
+ throw new IllegalArgumentException(
+ "Destination ColorSpace is undefined");
+ }
+ ncomponents = profileList[nProfiles-1].getNumComponents();
+ }
+
+ WritableRaster dest =
+ Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
+ src.getWidth(),
+ src.getHeight(),
+ ncomponents,
+ new Point(src.getMinX(), src.getMinY()));
+ return dest;
+ }
+
+ /**
+ * Returns the location of the destination point given a
+ * point in the source. If <code>dstPt</code> is non-null,
+ * it will be used to hold the return value. Note that
+ * for this class, the destination point will be the same
+ * as the source point.
+ * @param srcPt the specified source <code>Point2D</code>
+ * @param dstPt the destination <code>Point2D</code>
+ * @return <code>dstPt</code> after setting its location to be
+ * the same as <code>srcPt</code>
+ */
+ public final Point2D getPoint2D (Point2D srcPt, Point2D dstPt) {
+ if (dstPt == null) {
+ dstPt = new Point2D.Float();
+ }
+ dstPt.setLocation(srcPt.getX(), srcPt.getY());
+
+ return dstPt;
+ }
+
+
+ /**
+ * Returns the RenderingIntent from the specified ICC Profile.
+ */
+ private int getRenderingIntent (ICC_Profile profile) {
+ byte[] header = profile.getData(ICC_Profile.icSigHead);
+ int index = ICC_Profile.icHdrRenderingIntent;
+ return (((header[index] & 0xff) << 24) |
+ ((header[index+1] & 0xff) << 16) |
+ ((header[index+2] & 0xff) << 8) |
+ (header[index+3] & 0xff));
+ }
+
+ /**
+ * Returns the rendering hints used by this op.
+ * @return the <code>RenderingHints</code> object of this
+ * <code>ColorConvertOp</code>
+ */
+ public final RenderingHints getRenderingHints() {
+ return hints;
+ }
+
+ private final BufferedImage nonICCBIFilter(BufferedImage src,
+ ColorSpace srcColorSpace,
+ BufferedImage dst,
+ ColorSpace dstColorSpace) {
+
+ int w = src.getWidth();
+ int h = src.getHeight();
+ ICC_ColorSpace ciespace =
+ (ICC_ColorSpace) ColorSpace.getInstance(ColorSpace.CS_CIEXYZ);
+ if (dst == null) {
+ dst = createCompatibleDestImage(src, null);
+ dstColorSpace = dst.getColorModel().getColorSpace();
+ } else {
+ if ((h != dst.getHeight()) || (w != dst.getWidth())) {
+ throw new IllegalArgumentException(
+ "Width or height of BufferedImages do not match");
+ }
+ }
+ Raster srcRas = src.getRaster();
+ WritableRaster dstRas = dst.getRaster();
+ ColorModel srcCM = src.getColorModel();
+ ColorModel dstCM = dst.getColorModel();
+ int srcNumComp = srcCM.getNumColorComponents();
+ int dstNumComp = dstCM.getNumColorComponents();
+ boolean dstHasAlpha = dstCM.hasAlpha();
+ boolean needSrcAlpha = srcCM.hasAlpha() && dstHasAlpha;
+ ColorSpace[] list;
+ if ((CSList == null) && (profileList.length != 0)) {
+ /* possible non-ICC src, some profiles, possible non-ICC dst */
+ boolean nonICCSrc, nonICCDst;
+ ICC_Profile srcProfile, dstProfile;
+ if (!(srcColorSpace instanceof ICC_ColorSpace)) {
+ nonICCSrc = true;
+ srcProfile = ciespace.getProfile();
+ } else {
+ nonICCSrc = false;
+ srcProfile = ((ICC_ColorSpace) srcColorSpace).getProfile();
+ }
+ if (!(dstColorSpace instanceof ICC_ColorSpace)) {
+ nonICCDst = true;
+ dstProfile = ciespace.getProfile();
+ } else {
+ nonICCDst = false;
+ dstProfile = ((ICC_ColorSpace) dstColorSpace).getProfile();
+ }
+ /* make a new transform if needed */
+ if ((thisTransform == null) || (thisSrcProfile != srcProfile) ||
+ (thisDestProfile != dstProfile) ) {
+ updateBITransform(srcProfile, dstProfile);
+ }
+ // process per scanline
+ float maxNum = 65535.0f; // use 16-bit precision in CMM
+ ColorSpace cs;
+ int iccSrcNumComp;
+ if (nonICCSrc) {
+ cs = ciespace;
+ iccSrcNumComp = 3;
+ } else {
+ cs = srcColorSpace;
+ iccSrcNumComp = srcNumComp;
+ }
+ float[] srcMinVal = new float[iccSrcNumComp];
+ float[] srcInvDiffMinMax = new float[iccSrcNumComp];
+ for (int i = 0; i < srcNumComp; i++) {
+ srcMinVal[i] = cs.getMinValue(i);
+ srcInvDiffMinMax[i] = maxNum / (cs.getMaxValue(i) - srcMinVal[i]);
+ }
+ int iccDstNumComp;
+ if (nonICCDst) {
+ cs = ciespace;
+ iccDstNumComp = 3;
+ } else {
+ cs = dstColorSpace;
+ iccDstNumComp = dstNumComp;
+ }
+ float[] dstMinVal = new float[iccDstNumComp];
+ float[] dstDiffMinMax = new float[iccDstNumComp];
+ for (int i = 0; i < dstNumComp; i++) {
+ dstMinVal[i] = cs.getMinValue(i);
+ dstDiffMinMax[i] = (cs.getMaxValue(i) - dstMinVal[i]) / maxNum;
+ }
+ float[] dstColor;
+ if (dstHasAlpha) {
+ int size = ((dstNumComp + 1) > 3) ? (dstNumComp + 1) : 3;
+ dstColor = new float[size];
+ } else {
+ int size = (dstNumComp > 3) ? dstNumComp : 3;
+ dstColor = new float[size];
+ }
+ short[] srcLine = new short[w * iccSrcNumComp];
+ short[] dstLine = new short[w * iccDstNumComp];
+ Object pixel;
+ float[] color;
+ float[] alpha = null;
+ if (needSrcAlpha) {
+ alpha = new float[w];
+ }
+ int idx;
+ // process each scanline
+ for (int y = 0; y < h; y++) {
+ // convert src scanline
+ pixel = null;
+ color = null;
+ idx = 0;
+ for (int x = 0; x < w; x++) {
+ pixel = srcRas.getDataElements(x, y, pixel);
+ color = srcCM.getNormalizedComponents(pixel, color, 0);
+ if (needSrcAlpha) {
+ alpha[x] = color[srcNumComp];
+ }
+ if (nonICCSrc) {
+ color = srcColorSpace.toCIEXYZ(color);
+ }
+ for (int i = 0; i < iccSrcNumComp; i++) {
+ srcLine[idx++] = (short)
+ ((color[i] - srcMinVal[i]) * srcInvDiffMinMax[i] +
+ 0.5f);
+ }
+ }
+ // color convert srcLine to dstLine
+ thisTransform.colorConvert(srcLine, dstLine);
+ // convert dst scanline
+ pixel = null;
+ idx = 0;
+ for (int x = 0; x < w; x++) {
+ for (int i = 0; i < iccDstNumComp; i++) {
+ dstColor[i] = ((float) (dstLine[idx++] & 0xffff)) *
+ dstDiffMinMax[i] + dstMinVal[i];
+ }
+ if (nonICCDst) {
+ color = srcColorSpace.fromCIEXYZ(dstColor);
+ for (int i = 0; i < dstNumComp; i++) {
+ dstColor[i] = color[i];
+ }
+ }
+ if (needSrcAlpha) {
+ dstColor[dstNumComp] = alpha[x];
+ } else if (dstHasAlpha) {
+ dstColor[dstNumComp] = 1.0f;
+ }
+ pixel = dstCM.getDataElements(dstColor, 0, pixel);
+ dstRas.setDataElements(x, y, pixel);
+ }
+ }
+ } else {
+ /* possible non-ICC src, possible CSList, possible non-ICC dst */
+ // process per pixel
+ int numCS;
+ if (CSList == null) {
+ numCS = 0;
+ } else {
+ numCS = CSList.length;
+ }
+ float[] dstColor;
+ if (dstHasAlpha) {
+ dstColor = new float[dstNumComp + 1];
+ } else {
+ dstColor = new float[dstNumComp];
+ }
+ Object spixel = null;
+ Object dpixel = null;
+ float[] color = null;
+ float[] tmpColor;
+ // process each pixel
+ for (int y = 0; y < h; y++) {
+ for (int x = 0; x < w; x++) {
+ spixel = srcRas.getDataElements(x, y, spixel);
+ color = srcCM.getNormalizedComponents(spixel, color, 0);
+ tmpColor = srcColorSpace.toCIEXYZ(color);
+ for (int i = 0; i < numCS; i++) {
+ tmpColor = CSList[i].fromCIEXYZ(tmpColor);
+ tmpColor = CSList[i].toCIEXYZ(tmpColor);
+ }
+ tmpColor = dstColorSpace.fromCIEXYZ(tmpColor);
+ for (int i = 0; i < dstNumComp; i++) {
+ dstColor[i] = tmpColor[i];
+ }
+ if (needSrcAlpha) {
+ dstColor[dstNumComp] = color[srcNumComp];
+ } else if (dstHasAlpha) {
+ dstColor[dstNumComp] = 1.0f;
+ }
+ dpixel = dstCM.getDataElements(dstColor, 0, dpixel);
+ dstRas.setDataElements(x, y, dpixel);
+
+ }
+ }
+ }
+
+ return dst;
+ }
+
+ /* color convert a Raster - handles byte, ushort, int, short, float,
+ or double transferTypes */
+ private final WritableRaster nonICCRasterFilter(Raster src,
+ WritableRaster dst) {
+
+ if (CSList.length != 2) {
+ throw new IllegalArgumentException(
+ "Destination ColorSpace is undefined");
+ }
+ if (src.getNumBands() != CSList[0].getNumComponents()) {
+ throw new IllegalArgumentException(
+ "Numbers of source Raster bands and source color space " +
+ "components do not match");
+ }
+ if (dst == null) {
+ dst = createCompatibleDestRaster(src);
+ } else {
+ if (src.getHeight() != dst.getHeight() ||
+ src.getWidth() != dst.getWidth()) {
+ throw new IllegalArgumentException(
+ "Width or height of Rasters do not match");
+ }
+ if (dst.getNumBands() != CSList[1].getNumComponents()) {
+ throw new IllegalArgumentException(
+ "Numbers of destination Raster bands and destination " +
+ "color space components do not match");
+ }
+ }
+
+ if (srcMinVals == null) {
+ getMinMaxValsFromColorSpaces(CSList[0], CSList[1]);
+ }
+
+ SampleModel srcSM = src.getSampleModel();
+ SampleModel dstSM = dst.getSampleModel();
+ boolean srcIsFloat, dstIsFloat;
+ int srcTransferType = src.getTransferType();
+ int dstTransferType = dst.getTransferType();
+ if ((srcTransferType == DataBuffer.TYPE_FLOAT) ||
+ (srcTransferType == DataBuffer.TYPE_DOUBLE)) {
+ srcIsFloat = true;
+ } else {
+ srcIsFloat = false;
+ }
+ if ((dstTransferType == DataBuffer.TYPE_FLOAT) ||
+ (dstTransferType == DataBuffer.TYPE_DOUBLE)) {
+ dstIsFloat = true;
+ } else {
+ dstIsFloat = false;
+ }
+ int w = src.getWidth();
+ int h = src.getHeight();
+ int srcNumBands = src.getNumBands();
+ int dstNumBands = dst.getNumBands();
+ float[] srcScaleFactor = null;
+ float[] dstScaleFactor = null;
+ if (!srcIsFloat) {
+ srcScaleFactor = new float[srcNumBands];
+ for (int i = 0; i < srcNumBands; i++) {
+ if (srcTransferType == DataBuffer.TYPE_SHORT) {
+ srcScaleFactor[i] = (srcMaxVals[i] - srcMinVals[i]) /
+ 32767.0f;
+ } else {
+ srcScaleFactor[i] = (srcMaxVals[i] - srcMinVals[i]) /
+ ((float) ((1 << srcSM.getSampleSize(i)) - 1));
+ }
+ }
+ }
+ if (!dstIsFloat) {
+ dstScaleFactor = new float[dstNumBands];
+ for (int i = 0; i < dstNumBands; i++) {
+ if (dstTransferType == DataBuffer.TYPE_SHORT) {
+ dstScaleFactor[i] = 32767.0f /
+ (dstMaxVals[i] - dstMinVals[i]);
+ } else {
+ dstScaleFactor[i] =
+ ((float) ((1 << dstSM.getSampleSize(i)) - 1)) /
+ (dstMaxVals[i] - dstMinVals[i]);
+ }
+ }
+ }
+ int ys = src.getMinY();
+ int yd = dst.getMinY();
+ int xs, xd;
+ float sample;
+ float[] color = new float[srcNumBands];
+ float[] tmpColor;
+ ColorSpace srcColorSpace = CSList[0];
+ ColorSpace dstColorSpace = CSList[1];
+ // process each pixel
+ for (int y = 0; y < h; y++, ys++, yd++) {
+ // get src scanline
+ xs = src.getMinX();
+ xd = dst.getMinX();
+ for (int x = 0; x < w; x++, xs++, xd++) {
+ for (int i = 0; i < srcNumBands; i++) {
+ sample = src.getSampleFloat(xs, ys, i);
+ if (!srcIsFloat) {
+ sample = sample * srcScaleFactor[i] + srcMinVals[i];
+ }
+ color[i] = sample;
+ }
+ tmpColor = srcColorSpace.toCIEXYZ(color);
+ tmpColor = dstColorSpace.fromCIEXYZ(tmpColor);
+ for (int i = 0; i < dstNumBands; i++) {
+ sample = tmpColor[i];
+ if (!dstIsFloat) {
+ sample = (sample - dstMinVals[i]) * dstScaleFactor[i];
+ }
+ dst.setSample(xd, yd, i, sample);
+ }
+ }
+ }
+ return dst;
+ }
+
+ private void getMinMaxValsFromProfiles(ICC_Profile srcProfile,
+ ICC_Profile dstProfile) {
+ int type = srcProfile.getColorSpaceType();
+ int nc = srcProfile.getNumComponents();
+ srcMinVals = new float[nc];
+ srcMaxVals = new float[nc];
+ setMinMax(type, nc, srcMinVals, srcMaxVals);
+ type = dstProfile.getColorSpaceType();
+ nc = dstProfile.getNumComponents();
+ dstMinVals = new float[nc];
+ dstMaxVals = new float[nc];
+ setMinMax(type, nc, dstMinVals, dstMaxVals);
+ }
+
+ private void setMinMax(int type, int nc, float[] minVals, float[] maxVals) {
+ if (type == ColorSpace.TYPE_Lab) {
+ minVals[0] = 0.0f; // L
+ maxVals[0] = 100.0f;
+ minVals[1] = -128.0f; // a
+ maxVals[1] = 127.0f;
+ minVals[2] = -128.0f; // b
+ maxVals[2] = 127.0f;
+ } else if (type == ColorSpace.TYPE_XYZ) {
+ minVals[0] = minVals[1] = minVals[2] = 0.0f; // X, Y, Z
+ maxVals[0] = maxVals[1] = maxVals[2] = 1.0f + (32767.0f/ 32768.0f);
+ } else {
+ for (int i = 0; i < nc; i++) {
+ minVals[i] = 0.0f;
+ maxVals[i] = 1.0f;
+ }
+ }
+ }
+
+ private void getMinMaxValsFromColorSpaces(ColorSpace srcCspace,
+ ColorSpace dstCspace) {
+ int nc = srcCspace.getNumComponents();
+ srcMinVals = new float[nc];
+ srcMaxVals = new float[nc];
+ for (int i = 0; i < nc; i++) {
+ srcMinVals[i] = srcCspace.getMinValue(i);
+ srcMaxVals[i] = srcCspace.getMaxValue(i);
+ }
+ nc = dstCspace.getNumComponents();
+ dstMinVals = new float[nc];
+ dstMaxVals = new float[nc];
+ for (int i = 0; i < nc; i++) {
+ dstMinVals[i] = dstCspace.getMinValue(i);
+ dstMaxVals[i] = dstCspace.getMaxValue(i);
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/awt/image/ComponentSampleModel.java Thu Apr 10 16:28:45 2008 -0700
@@ -0,0 +1,1202 @@
+/*
+ * Portions Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* ****************************************************************
+ ******************************************************************
+ ******************************************************************
+ *** COPYRIGHT (c) Eastman Kodak Company, 1997
+ *** As an unpublished work pursuant to Title 17 of the United
+ *** States Code. All rights reserved.
+ ******************************************************************
+ ******************************************************************