001: /*
002: * $RCSfile: BorderExtenderWrap.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 copies of the whole image. 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>E</td><td>F</td><td>D</td><td>E</td><td>F</td><td>D</td><td>E</td> </tr>
037: * <td>H</td><td>I</td><td>G</td><td>H</td><td>I</td><td>G</td><td>H</td> </tr>
038: * <td>B</td><td>C</td><td>A</td><td>B</td><td>C</td><td>A</td><td>B</td> </tr>
039: * <td>E</td><td>F</td><td>D</td><td>E</td><td>F</td><td>D</td><td>E</td> </tr>
040: * <td>H</td><td>I</td><td>G</td><td>H</td><td>I</td><td>G</td><td>H</td> </tr>
041: * <td>B</td><td>C</td><td>A</td><td>B</td><td>C</td><td>A</td><td>B</td> </tr>
042: * <td>E</td><td>F</td><td>D</td><td>E</td><td>F</td><td>D</td><td>E</td> </tr>
043: * </table></center>
044: *
045: * <p> This form of extension is appropriate for data that is inherently
046: * periodic, such as the Fourier transform of an image, or a wallpaper
047: * pattern.
048: *
049: * @see BorderExtender
050: */
051: public class BorderExtenderWrap extends BorderExtender {
052:
053: BorderExtenderWrap() {
054: }
055:
056: /**
057: * Fills in the portions of a given <code>Raster</code> that lie
058: * outside the bounds of a given <code>PlanarImage</code> with
059: * copies of the entire image.
060: *
061: * <p> The portion of <code>raster</code> that lies within
062: * <code>im.getBounds()</code> is not altered.
063: *
064: * @param raster The <code>WritableRaster</code> the border area of
065: * which is to be filled with copies of the given image.
066: * @param im The <code>PlanarImage</code> which will be copied
067: * to fill the border area of the
068: * <code>WritableRaster</code>.
069: *
070: * @throws <code>IllegalArgumentException</code> if either parameter is
071: * <code>null</code>.
072: */
073: public final void extend(WritableRaster raster, PlanarImage im) {
074:
075: if (raster == null || im == null) {
076: throw new IllegalArgumentException(JaiI18N
077: .getString("Generic0"));
078: }
079:
080: int width = raster.getWidth();
081: int height = raster.getHeight();
082:
083: int minX = raster.getMinX();
084: int maxX = minX + width;
085: int minY = raster.getMinY();
086: int maxY = minY + height;
087:
088: int imMinX = im.getMinX();
089: int imMinY = im.getMinY();
090: int imWidth = im.getWidth();
091: int imHeight = im.getHeight();
092:
093: Rectangle rect = new Rectangle();
094:
095: // Notionally extend the source image by treating it as a single
096: // tile of an infinite tiled image.
097:
098: // Compute the min and max X and Y tile indices of the area
099: // intersected by the output raster.
100: int minTileX = PlanarImage.XToTileX(minX, imMinX, imWidth);
101: int maxTileX = PlanarImage.XToTileX(maxX - 1, imMinX, imWidth);
102: int minTileY = PlanarImage.YToTileY(minY, imMinY, imHeight);
103: int maxTileY = PlanarImage.YToTileY(maxY - 1, imMinY, imHeight);
104:
105: // Loop over the tiles
106: for (int tileY = minTileY; tileY <= maxTileY; tileY++) {
107: int ty = tileY * imHeight + imMinY;
108: for (int tileX = minTileX; tileX <= maxTileX; tileX++) {
109: int tx = tileX * imWidth + imMinX;
110:
111: // Don't touch the central "tile" (actual image)
112: if (tileX == 0 && tileY == 0) {
113: continue;
114: }
115:
116: // Clip the tile bounds against the bounds of the Raster.
117: // Keep track of the (x, y) offset of the start of the tile.
118: rect.x = tx;
119: rect.y = ty;
120: rect.width = imWidth;
121: rect.height = imHeight;
122:
123: int xOffset = 0;
124: if (rect.x < minX) {
125: xOffset = minX - rect.x;
126: rect.x = minX;
127: rect.width -= xOffset;
128: }
129: int yOffset = 0;
130: if (rect.y < minY) {
131: yOffset = minY - rect.y;
132: rect.y = minY;
133: rect.height -= yOffset;
134: }
135: if (rect.x + rect.width > maxX) {
136: rect.width = maxX - rect.x;
137: }
138: if (rect.y + rect.height > maxY) {
139: rect.height = maxY - rect.y;
140: }
141:
142: // Create a child raster with coordinates within the
143: // actual image.
144: WritableRaster child = RasterFactory
145: .createWritableChild(raster, rect.x, rect.y,
146: rect.width, rect.height, imMinX
147: + xOffset, imMinY + yOffset,
148: null);
149:
150: // Copy the data into the Raster
151: im.copyData(child);
152: }
153: }
154: }
155: }
|