001: /*
002: * $RCSfile: PeriodicShiftOpImage.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:40 $
010: * $State: Exp $
011: */
012: package com.sun.media.jai.opimage;
013:
014: import java.awt.Point;
015: import java.awt.Rectangle;
016: import java.awt.image.Raster;
017: import java.awt.image.RenderedImage;
018: import java.awt.image.WritableRaster;
019: import javax.media.jai.ImageLayout;
020: import javax.media.jai.OpImage;
021: import javax.media.jai.RasterFactory;
022: import java.util.Map;
023: import com.sun.media.jai.util.JDKWorkarounds;
024:
025: /**
026: * The OpImage implementation of the "PeriodicShift" operation as described in
027: * javax.media.jai.operator.PeriodicShiftDescriptor.
028: *
029: * <p> The layout the extended shifted image is copied from its source if
030: * the layout parameter is null.
031: *
032: * @see javax.media.jai.operator.PeriodicShiftDescriptor
033: * @see javax.media.jai.ImageLayout
034: * @see javax.media.jai.OpImage
035: *
036: * @since EA4
037: */
038: final class PeriodicShiftOpImage extends OpImage {
039:
040: /** The horizontal translation in pixels for each translated image. */
041: private int[] xTrans;
042:
043: /** The vertical translation in pixels for each translated image. */
044: private int[] yTrans;
045:
046: /** The source image translated in four different directions. */
047: private TranslateIntOpImage[] images;
048:
049: /** The bounds of each of the four translated images. */
050: private Rectangle[] bounds;
051:
052: /**
053: * Creates a OpImage to return the tiles of a periodic extension.
054: *
055: * @param source a RenderedImage.
056: * @param layout an ImageLayout optionally containing the tile grid
057: * layout, SampleModel, and ColorModel, or null.
058: * @param shiftX the number of pixels of horizontal translation.
059: * @param shiftY the number of pixels of vertical translation.
060: */
061: public PeriodicShiftOpImage(RenderedImage source, Map config,
062: ImageLayout layout, int shiftX, int shiftY) {
063: super (vectorize(source), layout == null ? new ImageLayout()
064: : (ImageLayout) layout.clone(), config, false);
065:
066: // Calculate the four translation factors.
067: xTrans = new int[] { -shiftX, -shiftX, width - shiftX,
068: width - shiftX };
069: yTrans = new int[] { -shiftY, height - shiftY, -shiftY,
070: height - shiftY };
071:
072: // Translate the source image in four separate directions.
073: images = new TranslateIntOpImage[4];
074: for (int i = 0; i < 4; i++) {
075: images[i] = new TranslateIntOpImage(source, null,
076: xTrans[i], yTrans[i]);
077: }
078:
079: // Compute the intersection of the translated sources with the
080: // destination bounds.
081: Rectangle destBounds = getBounds();
082: bounds = new Rectangle[4];
083: for (int i = 0; i < 4; i++) {
084: bounds[i] = destBounds.intersection(images[i].getBounds());
085: }
086: }
087:
088: /**
089: * Computes a tile of the destination by copying the data which
090: * overlaps the tile in the four translated source images.
091: *
092: * @param tileX the X index of the tile.
093: * @param tileY the Y index of the tile.
094: */
095: public Raster computeTile(int tileX, int tileY) {
096: // Create a new WritableRaster to represent this tile.
097: Point org = new Point(tileXToX(tileX), tileYToY(tileY));
098: WritableRaster dest = createWritableRaster(sampleModel, org);
099:
100: // Clip output rectangle to image bounds.
101: Rectangle rect = new Rectangle(org.x, org.y, sampleModel
102: .getWidth(), sampleModel.getHeight());
103: Rectangle destRect = rect.intersection(getBounds());
104:
105: // Fill the destination raster.
106: for (int i = 0; i < 4; i++) {
107: // Calculate the overlap with the current translated source.
108: Rectangle overlap = destRect.intersection(bounds[i]);
109:
110: // If the overlap is non-empty, copy the data within it.
111: if (!overlap.isEmpty()) {
112: //dest.setRect(images[i].getData(overlap));
113: JDKWorkarounds
114: .setRect(dest, images[i].getData(overlap));
115: }
116: }
117:
118: return dest;
119: }
120:
121: /**
122: * Returns a conservative estimate of the destination region that
123: * can potentially be affected by the pixels of a rectangle of a
124: * given source.
125: *
126: * @param sourceRect the Rectangle in source coordinates.
127: * @param sourceIndex the index of the source image.
128: * @return a Rectangle indicating the potentially affected
129: * destination region. or null if the region is unknown.
130: * @throws IllegalArgumentException if the source index is
131: * negative or greater than that of the last source.
132: * @throws IllegalArgumentException if sourceRect is null.
133: */
134: public Rectangle mapSourceRect(Rectangle sourceRect, int sourceIndex) {
135:
136: if (sourceRect == null) {
137: throw new IllegalArgumentException(JaiI18N
138: .getString("Generic0"));
139: }
140:
141: if (sourceIndex < 0 || sourceIndex >= getNumSources()) {
142: throw new IllegalArgumentException(JaiI18N
143: .getString("PeriodicShiftOpImage0"));
144: }
145:
146: Rectangle destRect = null;
147: for (int i = 0; i < 4; i++) {
148: Rectangle srcRect = sourceRect;
149: srcRect.translate(xTrans[i], yTrans[i]);
150: Rectangle overlap = srcRect.intersection(getBounds());
151: if (!overlap.isEmpty()) {
152: destRect = destRect == null ? overlap : destRect
153: .union(overlap);
154: }
155: }
156:
157: return destRect;
158: }
159:
160: /**
161: * Returns a conservative estimate of the region of a specified
162: * source that is required in order to compute the pixels of a
163: * given destination rectangle.
164: *
165: * @param destRect the Rectangle in destination coordinates.
166: * @param sourceIndex the index of the source image.
167: * @return a Rectangle indicating the required source region.
168: * @throws IllegalArgumentException if the source index is
169: * negative or greater than that of the last source.
170: * @throws IllegalArgumentException if destRect is null.
171: */
172: public Rectangle mapDestRect(Rectangle destRect, int sourceIndex) {
173:
174: if (destRect == null) {
175: throw new IllegalArgumentException(JaiI18N
176: .getString("Generic0"));
177: }
178:
179: if (sourceIndex < 0 || sourceIndex >= getNumSources()) {
180: throw new IllegalArgumentException(JaiI18N
181: .getString("PeriodicShiftOpImage0"));
182: }
183:
184: Rectangle sourceRect = null;
185: for (int i = 0; i < 4; i++) {
186: Rectangle overlap = destRect.intersection(bounds[i]);
187: if (!overlap.isEmpty()) {
188: overlap.translate(-xTrans[i], -yTrans[i]);
189: sourceRect = sourceRect == null ? overlap : sourceRect
190: .union(overlap);
191: }
192: }
193:
194: return sourceRect;
195: }
196: }
|