/* JAI-Ext - OpenSource Java Advanced Image Extensions Library
* http://www.geo-solutions.it/
* Copyright 2014 GeoSolutions
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package it.geosolutions.jaiext.iterators.nl;
import java.awt.Rectangle;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.awt.image.SampleModel;
import javax.media.jai.PlanarImage;
import javax.media.jai.iterator.RandomIter;
/**
* Modified version of JAI {@link RandomIterFallbackNoCacheNoArray} that uses a ThreadLocal object for storing the current tile used in iterations.
*/
public class RandomIterFallbackLocal implements RandomIter {
private final RenderedImage im;
private final Rectangle boundsRect;
private final SampleModel sampleModel;
private final int boundsX;
private final int boundsY;
private final int tileWidth;
private final int tileHeight;
private final int tileGridXOffset;
private final int tileGridYOffset;
private static final ThreadLocal<CurrentTile> iterator = new ThreadLocal<CurrentTile>() {
// Creation of an initial empty bean
@Override
protected CurrentTile initialValue() {
CurrentTile beanIt = new CurrentTile();
// The first raster is set to null
beanIt.tile = null;
// The tile coordinates are set to (0,0);
beanIt.tileX = 0;
beanIt.tileY = 0;
return beanIt;
}
};
public RandomIterFallbackLocal(RenderedImage im, Rectangle bounds) {
this.im = im;
Rectangle imBounds = new Rectangle(im.getMinX(), im.getMinY(), im.getWidth(),
im.getHeight());
this.boundsRect = imBounds.intersection(bounds);
this.sampleModel = im.getSampleModel();
this.boundsX = boundsRect.x;
this.boundsY = boundsRect.y;
this.tileWidth = im.getTileWidth();
this.tileHeight = im.getTileHeight();
this.tileGridXOffset = im.getTileGridXOffset();
this.tileGridYOffset = im.getTileGridYOffset();
}
/**
* Sets dataBuffer to the correct buffer for the pixel (x, y) = (xLocal + boundsRect.x, yLocal + boundsRect.y).
*
* @param xLocal the X coordinate in the local coordinate system.
* @param yLocal the Y coordinate in the local coordinate system.
*/
private Raster makeCurrent(int xLocal, int yLocal) {
// get the tile coordinates
final int tileXNew = PlanarImage.XToTileX(xLocal, tileGridXOffset, tileWidth);
final int tileYNew = PlanarImage.YToTileY(yLocal, tileGridYOffset, tileHeight);
// get the threadLocal object
final CurrentTile beanOld = iterator.get();
// get the bean objects
final Raster tileOld = beanOld.tile;
final int tileXOld = beanOld.tileX;
final int tileYOld = beanOld.tileY;
// if the raster is not defined or the tile coordinates are changed a new tile
// with new coordinates is calculated
if (tileOld == null || (tileXNew != tileXOld || tileYNew != tileYOld)) {
Raster tileNew = im.getTile(tileXNew, tileYNew);
CurrentTile beanNew = new CurrentTile();
beanNew.tile = tileNew;
beanNew.tileX = tileXNew;
beanNew.tileY = tileYNew;
// The new tile is returned
return tileNew;
// Else the old tile is returned
} else {
return tileOld;
}
}
public int getSample(int x, int y, int b) {
// get tile
final Raster tile = makeCurrent(x - boundsX, y - boundsY);
// get value
final int sampleModelTranslateX = tile.getSampleModelTranslateX();
final int sampleModelTranslateY = tile.getSampleModelTranslateY();
return sampleModel.getSample(x - sampleModelTranslateX, y - sampleModelTranslateY, b,
tile.getDataBuffer());
}
public float getSampleFloat(int x, int y, int b) {
// get tile
final Raster tile = makeCurrent(x - boundsX, y - boundsY);
// get value
final int sampleModelTranslateX = tile.getSampleModelTranslateX();
final int sampleModelTranslateY = tile.getSampleModelTranslateY();
return sampleModel.getSampleFloat(x - sampleModelTranslateX, y - sampleModelTranslateY, b,
tile.getDataBuffer());
}
public double getSampleDouble(int x, int y, int b) {
// get tile
final Raster tile = makeCurrent(x - boundsX, y - boundsY);
// get value
final int sampleModelTranslateX = tile.getSampleModelTranslateX();
final int sampleModelTranslateY = tile.getSampleModelTranslateY();
return sampleModel.getSampleDouble(x - sampleModelTranslateX, y - sampleModelTranslateY, b,
tile.getDataBuffer());
}
public int[] getPixel(int x, int y, int[] iArray) {
// get tile
final Raster tile = makeCurrent(x - boundsX, y - boundsY);
// get value
final int sampleModelTranslateX = tile.getSampleModelTranslateX();
final int sampleModelTranslateY = tile.getSampleModelTranslateY();
return sampleModel.getPixel(x - sampleModelTranslateX, y - sampleModelTranslateY, iArray,
tile.getDataBuffer());
}
public float[] getPixel(int x, int y, float[] fArray) {
// get tile
final Raster tile = makeCurrent(x - boundsX, y - boundsY);
// get value
final int sampleModelTranslateX = tile.getSampleModelTranslateX();
final int sampleModelTranslateY = tile.getSampleModelTranslateY();
return sampleModel.getPixel(x - sampleModelTranslateX, y - sampleModelTranslateY, fArray,
tile.getDataBuffer());
}
public double[] getPixel(int x, int y, double[] dArray) {
// get tile
final Raster tile = makeCurrent(x - boundsX, y - boundsY);
// get value
final int sampleModelTranslateX = tile.getSampleModelTranslateX();
final int sampleModelTranslateY = tile.getSampleModelTranslateY();
return sampleModel.getPixel(x - sampleModelTranslateX, y - sampleModelTranslateY, dArray,
tile.getDataBuffer());
}
public void done() {
iterator.remove();
}
/**
* This class is used only by the threadLocal to store the value of the current tile used and its coordinates. By using getters and setters all
* the inner parameters can be retrieved or changed
*/
private static class CurrentTile {
/** Data tile */
private Raster tile;
/** Tile X coordinate */
private int tileX;
/** Tile Y coordinate */
private int tileY;
private CurrentTile() {
}
}
}