001: /*
002: * $RCSfile: LookupOpImage.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:56:31 $
010: * $State: Exp $
011: */
012: package com.sun.media.jai.opimage;
013:
014: import java.awt.Rectangle;
015: import java.awt.image.Raster;
016: import java.awt.image.RenderedImage;
017: import java.awt.image.SampleModel;
018: import java.awt.image.WritableRaster;
019: import java.util.Map;
020: import javax.media.jai.ColormapOpImage;
021: import javax.media.jai.ImageLayout;
022: import javax.media.jai.LookupTableJAI;
023: import javax.media.jai.PlanarImage;
024: import javax.media.jai.PointOpImage;
025: import com.sun.media.jai.util.ImageUtil;
026: import com.sun.media.jai.util.JDKWorkarounds;
027:
028: /**
029: * An <code>OpImage</code> implementing the "Lookup" operation.
030: *
031: * <p>This <code>OpImage</code> performs the general table lookup on
032: * a source image by passing it through a lookup table. The source
033: * image may be single- or multi-banded and of any integral data types.
034: * The lookup table may be single- or multi-banded of any JAI supported
035: * data types. The destination image must have the same data type as
036: * the lookup table, and its number of bands is determined based on
037: * the number of bands of the source and the table.
038: *
039: * <p>If both the source and the lookup table are multi-banded, they
040: * should have the same number of bands. In case their band numbers
041: * are different, if the source's number of bands is less than the
042: * table's number of bands, the first <code>n</code> bands of the table
043: * data is used, where <code>n</code> is the source's number of bands;
044: * otherwise, the first band (band 0) of the table data is applied to
045: * all the bands of the source.
046: *
047: * <p>The application programs may specify the layout of the
048: * destination image via the <code>ImageLayout</code> parameter. If
049: * a <code>SampleModel</code> is supplied, it should be created in
050: * accordance with the source image and the actual lookup table
051: * used in a specific case. It is strongly recommended that a
052: * <code>ComponentSampleModel</code> is be used whenever possible
053: * for better performance.
054: *
055: * <p>If the supplied <code>SampleModel</code> is unsuitable for
056: * the source image and the lookup table type, or if no
057: * <code>SampleModel</code> is specified, a default suitable
058: * <code>SampleModel</code> is chosen for this operation based on
059: * the type of source image and lookup table. In this case, a new
060: * <code>ColorModel</code> is chosen based on the <code>SampleModel</code>.
061: *
062: * <p>Special case lookup operators should extend this class.
063: *
064: * <p>The destination pixel values are determined as:
065: * <pre>
066: * if (srcNumBands == 1) {
067: * // dst[y][x] has the same number of bands as the lookup table.
068: * for (b = 0; b < dstNumBands; b++) {
069: * dst[y][x][b] = tableData[b][src[y][x][0] + offsets[b]];
070: * }
071: * } else {
072: * // src[y][x] is multi-banded, dst[y][x] has the same
073: * // number of bands as src[y][x].
074: * if (tableNumBands == 1) {
075: * for (b = 0; b < dstNumBands; b++) {
076: * dst[y][x][b] = tableData[0][src[y][x][b] + offsets[0]];
077: * }
078: * } else {
079: * for (b = 0; b < dstNumBands; b++) {
080: * dst[y][x][b] = tableData[b][src[y][x][b] + offsets[b]];
081: * }
082: * }
083: * }
084: * </pre>
085: *
086: * @see javax.media.jai.operator.LookupDescriptor
087: * @see javax.media.jai.LookupTableJAI
088: * @see LookupCRIF
089: *
090: */
091: final class LookupOpImage extends ColormapOpImage {
092:
093: /**
094: * The lookup table associated with this operation.
095: * The source image is passed through this table.
096: */
097: protected LookupTableJAI table;
098:
099: /**
100: * Constructor.
101: *
102: * <p>If a <code>SampleModel</code> is supplied in the <code>layout</code>
103: * parameter, it may be ignored in case it's unsuitable for this
104: * operation. In this case the default <code>SampleModel</code>
105: * and <code>ColorModel</code> are used.
106: *
107: * @param source The source image.
108: * @param layout The destination image layout.
109: * @param table The table used to perform the lookup operation,
110: * stored by reference.
111: */
112: public LookupOpImage(RenderedImage source, Map config,
113: ImageLayout layout, LookupTableJAI table) {
114: super (source, layout, config, true);
115:
116: this .table = table;
117:
118: SampleModel sm = source.getSampleModel(); // source sample model
119:
120: if (sampleModel.getTransferType() != table.getDataType()
121: || sampleModel.getNumBands() != table
122: .getDestNumBands(sm.getNumBands())) {
123: /*
124: * The current SampleModel is not suitable for the supplied
125: * source and lookup table. Create a suitable SampleModel
126: * and ColorModel for the destination image.
127: */
128: sampleModel = table.getDestSampleModel(sm, tileWidth,
129: tileHeight);
130: if (colorModel != null
131: && !JDKWorkarounds.areCompatibleDataModels(
132: sampleModel, colorModel)) {
133: colorModel = ImageUtil.getCompatibleColorModel(
134: sampleModel, config);
135: }
136: }
137:
138: // Set flag to permit in-place operation.
139: permitInPlaceOperation();
140:
141: // Initialize the colormap if necessary.
142: initializeColormapOperation();
143: }
144:
145: /**
146: * Transform the colormap via the lookup table.
147: */
148: protected void transformColormap(byte[][] colormap) {
149: for (int b = 0; b < 3; b++) {
150: byte[] map = colormap[b];
151: int mapSize = map.length;
152:
153: int band = table.getNumBands() < 3 ? 0 : b;
154:
155: for (int i = 0; i < mapSize; i++) {
156: int result = table.lookup(band, map[i] & 0xFF);
157: map[i] = ImageUtil.clampByte(result);
158: }
159: }
160: }
161:
162: /**
163: * Performs the table lookup operation within a specified rectangle.
164: *
165: * @param sources Cobbled source, guaranteed to provide all the
166: * source data necessary for computing the rectangle.
167: * @param dest The tile containing the rectangle to be computed.
168: * @param destRect The rectangle within the tile to be computed.
169: */
170: protected void computeRect(Raster[] sources, WritableRaster dest,
171: Rectangle destRect) {
172: table.lookup(sources[0], dest, destRect);
173: }
174: }
|