001: /*
002: * $RCSfile: BorderExtenderConstant.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:04 $
010: * $State: Exp $
011: */
012: package javax.media.jai;
013:
014: import java.awt.Rectangle;
015: import java.awt.image.DataBuffer;
016: import java.awt.image.WritableRaster;
017:
018: /**
019: * A subclass of <code>BorderExtender</code> that implements
020: * border extension by filling all pixels outside of the image
021: * bounds with constant values. For example, the image:
022: *
023: * <p><center>
024: * <table border=1>
025: * <tr align=center><td>A</td><td>B</td><td>C</td> </tr>
026: * <tr align=center><td>D</td><td>E</td><td>F</td> </tr>
027: * <tr align=center><td>G</td><td>H</td><td>I</td> </tr>
028: * </table></center>
029: *
030: * <br>if extended by adding two extra rows to the top and bottom and
031: * two extra columns on the left and right sides, would become:
032: *
033: * <p><center>
034: * <table border=1>
035: * <tr align=center>
036: * <td>X</td><td>X</td><td>X</td><td>X</td><td>X</td><td>X</td><td>X</td> </tr>
037: * <td>X</td><td>X</td><td>X</td><td>X</td><td>X</td><td>X</td><td>X</td> </tr>
038: * <td>X</td><td>X</td><td>A</td><td>B</td><td>C</td><td>X</td><td>X</td> </tr>
039: * <td>X</td><td>X</td><td>D</td><td>E</td><td>F</td><td>X</td><td>X</td> </tr>
040: * <td>X</td><td>X</td><td>G</td><td>H</td><td>I</td><td>X</td><td>X</td> </tr>
041: * <td>X</td><td>X</td><td>X</td><td>X</td><td>X</td><td>X</td><td>X</td> </tr>
042: * <td>X</td><td>X</td><td>X</td><td>X</td><td>X</td><td>X</td><td>X</td> </tr>
043: * </table></center>
044: *
045: * where X is the constant fill value. The set of constants is clamped to
046: * the range and precision of the data type of the <code>WritableRaster</code>
047: * being filled. The number of constants used is given by the number of bands
048: * of the <code>WritableRaster</code>. If the <code>WritableRaster</code> has
049: * <code>b</code> bands, and there are <code>c</code> constants, constants
050: * <code>0</code> through <code>b - 1</code> are used when
051: * <code>b <= c</code>. If there is only a single constant, then it is used
052: * for all bands. If <code>b > c</code>, an
053: * <code>UnsupportedOperationException</code> is thrown.
054: *
055: * @see BorderExtender
056: */
057: public final class BorderExtenderConstant extends BorderExtender {
058:
059: private double[] constants;
060:
061: /**
062: * Constructs an instance of <code>BorderExtenderConstant</code>
063: * with a given set of constants. The constants are specified
064: * as an array of <code>double</code>s.
065: */
066: public BorderExtenderConstant(double[] constants) {
067: this .constants = constants;
068: }
069:
070: private int clamp(int band, int min, int max) {
071: int length = constants.length;
072: double c;
073: if (length == 1) {
074: c = constants[0];
075: } else if (band < length) {
076: c = constants[band];
077: } else {
078: throw new UnsupportedOperationException(JaiI18N
079: .getString("BorderExtenderConstant0"));
080: }
081:
082: return (c > min) ? ((c > max) ? max : (int) c) : min;
083: }
084:
085: /**
086: * Returns a clone of the <code>constants</code> array originally
087: * supplied to the constructor.
088: *
089: * @since JAI 1.1.2
090: */
091: public final double[] getConstants() {
092: return (double[]) constants;
093: }
094:
095: /**
096: * Fills in the portions of a given <code>Raster</code> that lie
097: * outside the bounds of a given <code>PlanarImage</code> with
098: * constant values.
099: *
100: * <p> The portion of <code>raster</code> that lies within
101: * <code>im.getBounds()</code> is not altered.
102: *
103: * @param raster The <code>WritableRaster</code> the border area of
104: * which is to be filled with constants.
105: * @param im The <code>PlanarImage</code> which determines the
106: * portion of the <code>WritableRaster</code> <i>not</i>
107: * to be filled.
108: *
109: * @throws <code>IllegalArgumentException</code> if either parameter is
110: * <code>null</code>.
111: * @throws <code>UnsupportedOperationException</code> if the number
112: * of image bands exceeds the number of constants and the
113: * latter is not unity.
114: */
115: public final void extend(WritableRaster raster, PlanarImage im) {
116:
117: if (raster == null || im == null) {
118: throw new IllegalArgumentException(JaiI18N
119: .getString("Generic0"));
120: }
121:
122: int width = raster.getWidth();
123: int height = raster.getHeight();
124: int numBands = raster.getNumBands();
125:
126: int minX = raster.getMinX();
127: int maxX = minX + width;
128: int minY = raster.getMinY();
129: int maxY = minY + height;
130:
131: int validMinX = Math.max(im.getMinX(), minX);
132: int validMaxX = Math.min(im.getMaxX(), maxX);
133: int validMinY = Math.max(im.getMinY(), minY);
134: int validMaxY = Math.min(im.getMaxY(), maxY);
135:
136: int row, index;
137:
138: int dataType = raster.getSampleModel().getDataType();
139: if (dataType == DataBuffer.TYPE_FLOAT) {
140: float[] fBandData = new float[numBands];
141: for (int b = 0; b < numBands; b++) {
142: fBandData[b] = (b < constants.length) ? (float) constants[b]
143: : 0.0F;
144: }
145: float[] fData = new float[width * numBands];
146: index = 0;
147: for (int i = 0; i < width; i++) {
148: for (int b = 0; b < numBands; b++) {
149: fData[index++] = fBandData[b];
150: }
151: }
152:
153: if (validMinX > validMaxX || validMinY > validMaxY) {
154: // Raster does not intersect image.
155: for (row = minY; row < maxY; row++) {
156: raster.setPixels(minX, row, width, 1, fData);
157: }
158: } else {
159: for (row = minY; row < validMinY; row++) {
160: raster.setPixels(minX, row, width, 1, fData);
161: }
162: for (row = validMinY; row < validMaxY; row++) {
163: if (minX < validMinX) {
164: raster.setPixels(minX, row, validMinX - minX,
165: 1, fData);
166: }
167: if (validMaxX < maxX) {
168: raster.setPixels(validMaxX, row, maxX
169: - validMaxX, 1, fData);
170: }
171: }
172: for (row = validMaxY; row < maxY; row++) {
173: raster.setPixels(minX, row, width, 1, fData);
174: }
175: }
176: } else if (dataType == DataBuffer.TYPE_DOUBLE) {
177: double[] dBandData = new double[numBands];
178: for (int b = 0; b < numBands; b++) {
179: dBandData[b] = (b < constants.length) ? constants[b]
180: : 0.0;
181: }
182: double[] dData = new double[width * numBands];
183: index = 0;
184: for (int i = 0; i < width; i++) {
185: for (int b = 0; b < numBands; b++) {
186: dData[index++] = dBandData[b];
187: }
188: }
189:
190: if (validMinX > validMaxX || validMinY > validMaxY) {
191: // Raster does not intersect image.
192: for (row = minY; row < maxY; row++) {
193: raster.setPixels(minX, row, width, 1, dData);
194: }
195: } else {
196: for (row = minY; row < validMinY; row++) {
197: raster.setPixels(minX, row, width, 1, dData);
198: }
199: for (row = validMinY; row < validMaxY; row++) {
200: if (minX < validMinX) {
201: raster.setPixels(minX, row, validMinX - minX,
202: 1, dData);
203: }
204: if (validMaxX < maxX) {
205: raster.setPixels(validMaxX, row, maxX
206: - validMaxX, 1, dData);
207: }
208: }
209: for (row = validMaxY; row < maxY; row++) {
210: raster.setPixels(minX, row, width, 1, dData);
211: }
212: }
213: } else {
214: int[] iBandData = new int[numBands];
215: switch (dataType) {
216: case DataBuffer.TYPE_BYTE:
217: for (int b = 0; b < numBands; b++) {
218: iBandData[b] = clamp(b, 0, 255);
219: }
220: break;
221: case DataBuffer.TYPE_SHORT:
222: for (int b = 0; b < numBands; b++) {
223: iBandData[b] = clamp(b, Short.MIN_VALUE,
224: Short.MAX_VALUE);
225: }
226: break;
227: case DataBuffer.TYPE_USHORT:
228: for (int b = 0; b < numBands; b++) {
229: iBandData[b] = clamp(b, 0, 65535);
230: }
231: break;
232: case DataBuffer.TYPE_INT:
233: for (int b = 0; b < numBands; b++) {
234: iBandData[b] = clamp(b, Integer.MIN_VALUE,
235: Integer.MAX_VALUE);
236: }
237: break;
238: default:
239: throw new IllegalArgumentException(JaiI18N
240: .getString("Generic3"));
241: }
242:
243: int[] iData = new int[width * numBands];
244: index = 0;
245: for (int i = 0; i < width; i++) {
246: for (int b = 0; b < numBands; b++) {
247: iData[index++] = iBandData[b];
248: }
249: }
250:
251: if (validMinX > validMaxX || validMinY > validMaxY) {
252: // Raster does not intersect image.
253: for (row = minY; row < maxY; row++) {
254: raster.setPixels(minX, row, width, 1, iData);
255: }
256: } else {
257: for (row = minY; row < validMinY; row++) {
258: raster.setPixels(minX, row, width, 1, iData);
259: }
260: for (row = validMinY; row < validMaxY; row++) {
261: if (minX < validMinX) {
262: raster.setPixels(minX, row, validMinX - minX,
263: 1, iData);
264: }
265: if (validMaxX < maxX) {
266: raster.setPixels(validMaxX, row, maxX
267: - validMaxX, 1, iData);
268: }
269: }
270: for (row = validMaxY; row < maxY; row++) {
271: raster.setPixels(minX, row, width, 1, iData);
272: }
273: }
274: }
275: }
276: }
|