001: /*
002: * $RCSfile: ColormapOpImage.java,v $
003: *
004: * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
005: *
006: * Use is subject to license terms.
007: *
008: * $Revision: 1.1 $
009: * $Date: 2005/02/11 04:57:06 $
010: * $State: Exp $
011: */
012: package javax.media.jai;
013:
014: import java.awt.image.ColorModel;
015: import java.awt.image.IndexColorModel;
016: import java.awt.image.RenderedImage;
017: import java.util.Map;
018: import javax.media.jai.ImageLayout;
019: import javax.media.jai.PointOpImage;
020: import javax.media.jai.TileCache;
021: import javax.media.jai.util.CaselessStringKey;
022:
023: /**
024: * A class to be used to implement an operation which may conditionally
025: * be accelerated by transforming the colormap of the source image instead
026: * of its data. An instance of this class will represent the destination
027: * of a single-source point operation which may be effected by a simple
028: * transformation of the source image colormap if the <code>ColorModel</code>s
029: * of the source and destination images are both instances of
030: * <code>IndexColorModel</code>. A subclass may take advantage of this
031: * capability merely by implementing <code>transformColormap()</code> and
032: * invoking <code>initializeColormapOperation()</code> as the last
033: * statement of its constructor. If the <code>ColorModel</code>s are not
034: * <code>IndexColorModel</code>s, the behavior is the same as if the
035: * superclass <code>PointOpImage</code> had been extended directly.
036: *
037: * <p> The default behavior for a <code>ColormapOpImage</code> is to
038: * do the transform only on the color map in order to accelerate processing
039: * when the source and destination images are all color-indexed.
040: * However, in some situations it may be desirable to transform the
041: * pixel (index) data directly instead of transforming the colormap.
042: * To suppress the acceleration, a mapping of the key
043: * <code>JAI.KEY_TRANSFORM_ON_COLORMAP</code> with value
044: * <code>Boolean.FALSE</code> should be added to the configuration
045: * map (or the <code>RenderingHints</code> provided to the
046: * <code>create</code> methods in the class <code>JAI</code>) supplied to
047: * the corresponding operation when it is created.
048: *
049: * <p> Transforming on the pixel (index) data is only meaningful
050: * when the transform maps all the possible index values of the source image
051: * into the index value set of the destination image. Otherwise,
052: * it may generate pixel (index) values without color definitions, and
053: * cause problems when computing the color components from pixel values.
054: * In addition, the colormaps should be ordered in a useful way
055: * for the transform in question, e.g. a smooth grayscale.</p>
056: *
057: * @see java.awt.image.IndexColorModel
058: * @see PointOpImage
059: *
060: * @since JAI 1.1
061: */
062: public abstract class ColormapOpImage extends PointOpImage {
063:
064: /** Whether the colormap acceleration flag has been initialized. */
065: private boolean isInitialized = false;
066:
067: /** Whether the operation is effected via colormap transformation. */
068: private boolean isColormapAccelerated;
069:
070: /**
071: * Constructs a <code>ColormapOpImage</code> with one source image.
072: * The parameters are forwarded unmodified to the equivalent
073: * superclass constructor.
074: *
075: * @param layout The layout parameters of the destination image.
076: * @param source The source image.
077: * @param configuration Configurable attributes of the image including
078: * configuration variables indexed by
079: * <code>RenderingHints.Key</code>s and image properties indexed
080: * by <code>String</code>s or <code>CaselessStringKey</code>s.
081: * This is simply forwarded to the superclass constructor.
082: * @param cobbleSources Indicates whether <code>computeRect()</code>
083: * expects contiguous sources.
084: *
085: * @throws IllegalArgumentException if <code>source</code>
086: * is <code>null</code>.
087: */
088: public ColormapOpImage(RenderedImage source, ImageLayout layout,
089: Map configuration, boolean cobbleSources) {
090: super (source, // tested for null in superclass
091: layout, configuration, cobbleSources);
092:
093: // If the source has an IndexColorModel, override the default setting
094: // in OpImage. The dest shall have exactly the same SampleModel and
095: // ColorModel as the source.
096: // Note, in this case, the source should have an integral data type.
097:
098: // Fix 4706651: ColormapOpImage should not force destination to
099: // have an IndexColorModel
100: /*
101: ColorModel srcColorModel = source.getColorModel();
102: if (srcColorModel instanceof IndexColorModel) {
103: sampleModel = source.getSampleModel().createCompatibleSampleModel(
104: tileWidth, tileHeight);
105: colorModel = srcColorModel;
106: }
107: */
108: isColormapAccelerated = true;
109: Boolean value = configuration == null ? Boolean.TRUE
110: : (Boolean) configuration
111: .get(JAI.KEY_TRANSFORM_ON_COLORMAP);
112: if (value != null)
113: isColormapAccelerated = value.booleanValue();
114: }
115:
116: /**
117: * Whether the operation is performed on the colormap directly.
118: */
119: protected final boolean isColormapOperation() {
120: return isColormapAccelerated;
121: }
122:
123: /**
124: * Method to be invoked as the last statement of a subclass constructor.
125: * The colormap acceleration flag is set appropriately and if
126: * <code>true</code> a new <code>ColorModel</code> is calculated by
127: * transforming the source colormap. This method must be invoked in
128: * the subclass constructor as it calls <code>transformColormap()</code>
129: * which is abstract and therefore requires that the implementing class be
130: * constructed before it may be invoked.
131: */
132: protected final void initializeColormapOperation() {
133: // Retrieve the ColorModels
134: ColorModel srcCM = getSource(0).getColorModel();
135: ColorModel dstCM = super .getColorModel();
136:
137: // Set the acceleration flag.
138: isColormapAccelerated &= srcCM != null && dstCM != null
139: && srcCM instanceof IndexColorModel
140: && dstCM instanceof IndexColorModel;
141:
142: // Set the initialization flag.
143: isInitialized = true;
144:
145: // Transform the colormap if the operation is accelerated.
146: if (isColormapAccelerated) {
147: // Cast the target ColorModel.
148: IndexColorModel icm = (IndexColorModel) dstCM;
149:
150: // Get the size and allocate the array.
151: int mapSize = icm.getMapSize();
152: byte[][] colormap = new byte[3][mapSize];
153:
154: // Load the colormap.
155: icm.getReds(colormap[0]);
156: icm.getGreens(colormap[1]);
157: icm.getBlues(colormap[2]);
158:
159: // Transform the colormap.
160: transformColormap(colormap);
161:
162: // Clamp the colormap if necessary. In the Sun implementation
163: // of IndexColorModel, getComponentSize() always returns 8 so
164: // no clamping will be performed.
165: for (int b = 0; b < 3; b++) {
166: int maxComponent = 0xFF >> (8 - icm.getComponentSize(b));
167: if (maxComponent < 255) {
168: byte[] map = colormap[b];
169: for (int i = 0; i < mapSize; i++) {
170: if ((map[i] & 0xFF) > maxComponent) {
171: map[i] = (byte) maxComponent;
172: }
173: }
174: }
175: }
176:
177: // Cache references to individual color component arrays.
178: byte[] reds = colormap[0];
179: byte[] greens = colormap[1];
180: byte[] blues = colormap[2];
181:
182: // Create the RGB array.
183: int[] rgb = new int[mapSize];
184:
185: // Copy the colormap into the RGB array.
186: if (icm.hasAlpha()) {
187: byte[] alphas = new byte[mapSize];
188: icm.getAlphas(alphas);
189: for (int i = 0; i < mapSize; i++) {
190: rgb[i] = ((alphas[i] & 0xFF) << 24)
191: | ((reds[i] & 0xFF) << 16)
192: | ((greens[i] & 0xFF) << 8)
193: | (blues[i] & 0xFF);
194: }
195: } else {
196: for (int i = 0; i < mapSize; i++) {
197: rgb[i] = ((reds[i] & 0xFF) << 16)
198: | ((greens[i] & 0xFF) << 8)
199: | (blues[i] & 0xFF);
200: }
201: }
202:
203: // Create the new ColorModel.
204: colorModel = new IndexColorModel(icm.getPixelSize(),
205: mapSize, rgb, 0, icm.hasAlpha(), icm
206: .getTransparentPixel(), sampleModel
207: .getTransferType());
208: }
209: }
210:
211: /**
212: * Transform the colormap according to the specific operation.
213: * The modification is done in place so that the parameter array
214: * will be modified. The format of the parameter array is
215: * <code>byte[3][]</code> wherein <code>colormap[0]</code>,
216: * <code>colormap[1]</code>, and <code>colormap[2]</code>
217: * represent the red, green, and blue colormaps, respectively.
218: */
219: protected abstract void transformColormap(byte[][] colormap);
220: }
|