001: /*
002: * $RCSfile: OverlayOpImage.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:39 $
010: * $State: Exp $
011: */
012: package com.sun.media.jai.opimage;
013:
014: import com.sun.media.jai.util.ImageUtil;
015: import com.sun.media.jai.util.JDKWorkarounds;
016: import java.awt.Point;
017: import java.awt.Rectangle;
018: import java.awt.image.DataBuffer;
019: import java.awt.image.Raster;
020: import java.awt.image.RenderedImage;
021: import java.awt.image.SampleModel;
022: import java.awt.image.WritableRaster;
023: import java.util.Map;
024: import java.util.Vector;
025: import javax.media.jai.ImageLayout;
026: import javax.media.jai.PlanarImage;
027: import javax.media.jai.PointOpImage;
028: import javax.media.jai.RasterAccessor;
029: import javax.media.jai.RasterFactory;
030: import javax.media.jai.RasterFormatTag;
031:
032: /**
033: * An <code>OpImage</code> implementing the "Overlay" operation.
034: *
035: * <p>This <code>OpImage</code> overlays one rendered image (source2)
036: * on top of another (source1). The two sources are required to have
037: * the same data type and number of bands.
038: *
039: * @see javax.media.jai.operator.OverlayDescriptor
040: * @see OverlayCRIF
041: *
042: */
043: final class OverlayOpImage extends PointOpImage {
044:
045: /**
046: * OverlayOpImage always has the bounds of the sourceUnder image.
047: * The image bounds specified in the "layout" are always ignored.
048: * Hence unset the image bounds so that PointImage.layoutHelper checks
049: * dont fail.
050: */
051: private static ImageLayout layoutHelper(ImageLayout layout,
052: Vector sources, Map config) {
053:
054: if (layout != null) {
055: layout = (ImageLayout) layout.clone();
056: layout.unsetImageBounds();
057: }
058:
059: return layout;
060: }
061:
062: /**
063: * Construct an <code>OverlayOpImage</code>.
064: *
065: * @param sourceUnder The source image on the bottom.
066: * @param sourceOver The source image to be overlayed on top of
067: * <code>sourceUnder</code>.
068: * @param layout The image layout for the destination image.
069: */
070: public OverlayOpImage(RenderedImage sourceUnder,
071: RenderedImage sourceOver, Map config, ImageLayout layout) {
072: super (sourceUnder, sourceOver, layoutHelper(layout, vectorize(
073: sourceUnder, sourceOver), config), config, true);
074:
075: /* Validate destination sampleModel. */
076: SampleModel srcSM = sourceUnder.getSampleModel();
077: if (sampleModel.getTransferType() != srcSM.getTransferType()
078: || sampleModel.getNumBands() != srcSM.getNumBands()) {
079: sampleModel = srcSM.createCompatibleSampleModel(tileWidth,
080: tileHeight);
081:
082: if (colorModel != null
083: && !JDKWorkarounds.areCompatibleDataModels(
084: sampleModel, colorModel)) {
085: colorModel = ImageUtil.getCompatibleColorModel(
086: sampleModel, config);
087: }
088: }
089:
090: /*
091: * Unlike other multi-source OpImages, the image dimension in this
092: * case is set to the same values as that of the source image on
093: * the bottom.
094: */
095: minX = sourceUnder.getMinX();
096: minY = sourceUnder.getMinY();
097: width = sourceUnder.getWidth();
098: height = sourceUnder.getHeight();
099: }
100:
101: /**
102: * Computes a tile. This method overrides PointOpImage.computeTile()
103: *
104: * @param tileX The X index of the tile.
105: * @param tileY The Y index of the tile.
106: */
107: public Raster computeTile(int tileX, int tileY) {
108: /* Create a new WritableRaster to represent this tile. */
109: WritableRaster dest = createTile(tileX, tileY);
110:
111: /* Clip the raster bound to image bounds. */
112: Rectangle destRect = dest.getBounds().intersection(getBounds());
113:
114: PlanarImage srcUnder = getSource(0);
115: PlanarImage srcOver = getSource(1);
116:
117: Rectangle srcUnderBounds = srcUnder.getBounds();
118: Rectangle srcOverBounds = srcOver.getBounds();
119:
120: /* In case of PointOpImage, mapDestRect(destRect, i) = destRect). */
121:
122: Raster[] sources = new Raster[1];
123: if (srcOverBounds.contains(destRect)) {
124: /* Tile is entirely inside sourceOver. */
125: sources[0] = srcOver.getData(destRect);
126: computeRect(sources, dest, destRect);
127:
128: // Recycle the source tile
129: if (srcOver.overlapsMultipleTiles(destRect)) {
130: recycleTile(sources[0]);
131: }
132:
133: return dest;
134:
135: } else if (srcUnderBounds.contains(destRect)
136: && !srcOverBounds.intersects(destRect)) {
137: /* Tile is entirely inside sourceUnder. */
138: sources[0] = srcUnder.getData(destRect);
139: computeRect(sources, dest, destRect);
140:
141: // Recycle the source tile
142: if (srcUnder.overlapsMultipleTiles(destRect)) {
143: recycleTile(sources[0]);
144: }
145:
146: return dest;
147:
148: } else {
149: /* Tile is inside both sources. */
150: Rectangle isectUnder = destRect
151: .intersection(srcUnderBounds);
152: sources[0] = srcUnder.getData(isectUnder);
153: computeRect(sources, dest, isectUnder);
154:
155: // Recycle the source tile
156: if (srcUnder.overlapsMultipleTiles(isectUnder)) {
157: recycleTile(sources[0]);
158: }
159:
160: if (srcOverBounds.intersects(destRect)) {
161: Rectangle isectOver = destRect
162: .intersection(srcOverBounds);
163: sources[0] = srcOver.getData(isectOver);
164: computeRect(sources, dest, isectOver);
165:
166: // Recycle the source tile
167: if (srcOver.overlapsMultipleTiles(isectOver)) {
168: recycleTile(sources[0]);
169: }
170: }
171:
172: return dest;
173: }
174: }
175:
176: /**
177: * Copies the pixel values of a source image within a specified
178: * rectangle.
179: *
180: * @param sources Cobbled sources, guaranteed to provide all the
181: * source data necessary for computing the rectangle.
182: * @param dest The tile containing the rectangle to be computed.
183: * @param destRect The rectangle within the tile to be computed.
184: */
185: protected void computeRect(Raster[] sources, WritableRaster dest,
186: Rectangle destRect) {
187: // Retrieve format tags.
188: RasterFormatTag[] formatTags = getFormatTags();
189:
190: RasterAccessor src = new RasterAccessor(sources[0], destRect,
191: formatTags[0], getSource(0).getColorModel());
192: RasterAccessor dst = new RasterAccessor(dest, destRect,
193: formatTags[1], getColorModel());
194:
195: switch (dst.getDataType()) {
196: case DataBuffer.TYPE_BYTE:
197: computeRectByte(src, dst);
198: break;
199: case DataBuffer.TYPE_USHORT:
200: case DataBuffer.TYPE_SHORT:
201: computeRectShort(src, dst);
202: break;
203: case DataBuffer.TYPE_INT:
204: computeRectInt(src, dst);
205: break;
206: case DataBuffer.TYPE_FLOAT:
207: computeRectFloat(src, dst);
208: break;
209: case DataBuffer.TYPE_DOUBLE:
210: computeRectDouble(src, dst);
211: break;
212: }
213:
214: dst.copyDataToRaster();
215: }
216:
217: private void computeRectByte(RasterAccessor src, RasterAccessor dst) {
218: int dstWidth = dst.getWidth();
219: int dstHeight = dst.getHeight();
220: int dstBands = dst.getNumBands();
221:
222: int dstLineStride = dst.getScanlineStride();
223: int dstPixelStride = dst.getPixelStride();
224: int[] dstBandOffsets = dst.getBandOffsets();
225: byte[][] dstData = dst.getByteDataArrays();
226:
227: int srcLineStride = src.getScanlineStride();
228: int srcPixelStride = src.getPixelStride();
229: int[] srcBandOffsets = src.getBandOffsets();
230: byte[][] srcData = src.getByteDataArrays();
231:
232: for (int b = 0; b < dstBands; b++) {
233: byte[] d = dstData[b];
234: byte[] s = srcData[b];
235:
236: int dstLineOffset = dstBandOffsets[b];
237: int srcLineOffset = srcBandOffsets[b];
238:
239: for (int h = 0; h < dstHeight; h++) {
240: int dstPixelOffset = dstLineOffset;
241: int srcPixelOffset = srcLineOffset;
242:
243: dstLineOffset += dstLineStride;
244: srcLineOffset += srcLineStride;
245:
246: for (int w = 0; w < dstWidth; w++) {
247: d[dstPixelOffset] = s[srcPixelOffset];
248:
249: dstPixelOffset += dstPixelStride;
250: srcPixelOffset += srcPixelStride;
251: }
252: }
253: }
254: }
255:
256: private void computeRectShort(RasterAccessor src, RasterAccessor dst) {
257: int dstWidth = dst.getWidth();
258: int dstHeight = dst.getHeight();
259: int dstBands = dst.getNumBands();
260:
261: int dstLineStride = dst.getScanlineStride();
262: int dstPixelStride = dst.getPixelStride();
263: int[] dstBandOffsets = dst.getBandOffsets();
264: short[][] dstData = dst.getShortDataArrays();
265:
266: int srcLineStride = src.getScanlineStride();
267: int srcPixelStride = src.getPixelStride();
268: int[] srcBandOffsets = src.getBandOffsets();
269: short[][] srcData = src.getShortDataArrays();
270:
271: for (int b = 0; b < dstBands; b++) {
272: short[] d = dstData[b];
273: short[] s = srcData[b];
274:
275: int dstLineOffset = dstBandOffsets[b];
276: int srcLineOffset = srcBandOffsets[b];
277:
278: for (int h = 0; h < dstHeight; h++) {
279: int dstPixelOffset = dstLineOffset;
280: int srcPixelOffset = srcLineOffset;
281:
282: dstLineOffset += dstLineStride;
283: srcLineOffset += srcLineStride;
284:
285: for (int w = 0; w < dstWidth; w++) {
286: d[dstPixelOffset] = s[srcPixelOffset];
287:
288: dstPixelOffset += dstPixelStride;
289: srcPixelOffset += srcPixelStride;
290: }
291: }
292: }
293: }
294:
295: private void computeRectInt(RasterAccessor src, RasterAccessor dst) {
296: int dstWidth = dst.getWidth();
297: int dstHeight = dst.getHeight();
298: int dstBands = dst.getNumBands();
299:
300: int dstLineStride = dst.getScanlineStride();
301: int dstPixelStride = dst.getPixelStride();
302: int[] dstBandOffsets = dst.getBandOffsets();
303: int[][] dstData = dst.getIntDataArrays();
304:
305: int srcLineStride = src.getScanlineStride();
306: int srcPixelStride = src.getPixelStride();
307: int[] srcBandOffsets = src.getBandOffsets();
308: int[][] srcData = src.getIntDataArrays();
309:
310: for (int b = 0; b < dstBands; b++) {
311: int[] d = dstData[b];
312: int[] s = srcData[b];
313:
314: int dstLineOffset = dstBandOffsets[b];
315: int srcLineOffset = srcBandOffsets[b];
316:
317: for (int h = 0; h < dstHeight; h++) {
318: int dstPixelOffset = dstLineOffset;
319: int srcPixelOffset = srcLineOffset;
320:
321: dstLineOffset += dstLineStride;
322: srcLineOffset += srcLineStride;
323:
324: for (int w = 0; w < dstWidth; w++) {
325: d[dstPixelOffset] = s[srcPixelOffset];
326:
327: dstPixelOffset += dstPixelStride;
328: srcPixelOffset += srcPixelStride;
329: }
330: }
331: }
332: }
333:
334: private void computeRectFloat(RasterAccessor src, RasterAccessor dst) {
335: int dstWidth = dst.getWidth();
336: int dstHeight = dst.getHeight();
337: int dstBands = dst.getNumBands();
338:
339: int dstLineStride = dst.getScanlineStride();
340: int dstPixelStride = dst.getPixelStride();
341: int[] dstBandOffsets = dst.getBandOffsets();
342: float[][] dstData = dst.getFloatDataArrays();
343:
344: int srcLineStride = src.getScanlineStride();
345: int srcPixelStride = src.getPixelStride();
346: int[] srcBandOffsets = src.getBandOffsets();
347: float[][] srcData = src.getFloatDataArrays();
348:
349: for (int b = 0; b < dstBands; b++) {
350: float[] d = dstData[b];
351: float[] s = srcData[b];
352:
353: int dstLineOffset = dstBandOffsets[b];
354: int srcLineOffset = srcBandOffsets[b];
355:
356: for (int h = 0; h < dstHeight; h++) {
357: int dstPixelOffset = dstLineOffset;
358: int srcPixelOffset = srcLineOffset;
359:
360: dstLineOffset += dstLineStride;
361: srcLineOffset += srcLineStride;
362:
363: for (int w = 0; w < dstWidth; w++) {
364: d[dstPixelOffset] = s[srcPixelOffset];
365:
366: dstPixelOffset += dstPixelStride;
367: srcPixelOffset += srcPixelStride;
368: }
369: }
370: }
371: }
372:
373: private void computeRectDouble(RasterAccessor src,
374: RasterAccessor dst) {
375: int dstWidth = dst.getWidth();
376: int dstHeight = dst.getHeight();
377: int dstBands = dst.getNumBands();
378:
379: int dstLineStride = dst.getScanlineStride();
380: int dstPixelStride = dst.getPixelStride();
381: int[] dstBandOffsets = dst.getBandOffsets();
382: double[][] dstData = dst.getDoubleDataArrays();
383:
384: int srcLineStride = src.getScanlineStride();
385: int srcPixelStride = src.getPixelStride();
386: int[] srcBandOffsets = src.getBandOffsets();
387: double[][] srcData = src.getDoubleDataArrays();
388:
389: for (int b = 0; b < dstBands; b++) {
390: double[] d = dstData[b];
391: double[] s = srcData[b];
392:
393: int dstLineOffset = dstBandOffsets[b];
394: int srcLineOffset = srcBandOffsets[b];
395:
396: for (int h = 0; h < dstHeight; h++) {
397: int dstPixelOffset = dstLineOffset;
398: int srcPixelOffset = srcLineOffset;
399:
400: dstLineOffset += dstLineStride;
401: srcLineOffset += srcLineStride;
402:
403: for (int w = 0; w < dstWidth; w++) {
404: d[dstPixelOffset] = s[srcPixelOffset];
405:
406: dstPixelOffset += dstPixelStride;
407: srcPixelOffset += srcPixelStride;
408: }
409: }
410: }
411: }
412: }
|