/* 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; import java.awt.Rectangle; import java.awt.image.DataBuffer; import java.awt.image.Raster; import java.awt.image.RenderedImage; import java.awt.image.SampleModel; import java.util.Arrays; import javax.media.jai.PlanarImage; import javax.media.jai.iterator.RandomIter; /** * Slight modified version of JAI {@link RandomIterFallbackNoCacheNoArray} that uses byte vectors to handle indexes rather than int vector. This way we use 4x4 * times less memory in the iterator * * @author Simone Giannecchini, GeoSolutions SAS */ public class RandomIterFallbackLarge implements RandomIter { protected RenderedImage im; protected Rectangle boundsRect; protected SampleModel sampleModel; protected int xID = Integer.MIN_VALUE; protected int yID = Integer.MIN_VALUE; protected int sampleModelTranslateX; protected int sampleModelTranslateY; protected DataBuffer dataBuffer = null; protected int boundsX; protected int boundsY; protected int[] xTiles; protected int[] yTiles; private int minTileX; private int minTileY; private int tileGridXOffset; private int tileHeight; private int tileGridYOffset; private int tileWidth; private int currentMaxXInclusive = Integer.MIN_VALUE; private int currentMaxYInclusive = Integer.MIN_VALUE; private int minx; private int miny; private int currentMinXInclusive = Integer.MAX_VALUE; private int currentMinYInclusive = Integer.MAX_VALUE; public RandomIterFallbackLarge(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; tileWidth = im.getTileWidth(); tileGridXOffset = im.getTileGridXOffset(); tileHeight = im.getTileHeight(); tileGridYOffset = im.getTileGridYOffset(); minTileX = im.getMinTileX(); final int maxTileXExcluded = minTileX + im.getNumXTiles(); minTileY = im.getMinTileY(); final int maxTileYExcluded = minTileY + im.getNumYTiles(); this.xTiles = new int[im.getNumXTiles()]; this.yTiles = new int[im.getNumYTiles()]; minx = im.getMinX(); miny = im.getMinY(); final int maxx = minx + im.getWidth() - 1; final int maxy = miny + im.getHeight() - 1; for (int xT = minTileX; xT < maxTileXExcluded; xT++) { xTiles[xT - minTileX] = PlanarImage.tileXToX(xT, tileGridXOffset, tileWidth) + tileWidth - 1; xTiles[xT - minTileX] = Math.min(xTiles[xT], maxx); } for (int yT = minTileY; yT < maxTileYExcluded; yT++) { yTiles[yT - minTileY] = PlanarImage.tileYToY(yT, tileGridYOffset, tileHeight) + tileHeight - 1; yTiles[yT - minTileY] = Math.min(yTiles[yT], maxy); } } /** * 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 void makeCurrent(int xLocal, int yLocal) { if ((xLocal <= currentMaxXInclusive) && (xLocal >= currentMinXInclusive) && (yLocal <= currentMaxYInclusive) && (yLocal >= currentMinYInclusive)) { return; } int xIDNew = Arrays.binarySearch(xTiles, xLocal); if (xIDNew < 0) { xIDNew += 1; xIDNew *= -1; } xIDNew += minTileX; int yIDNew = Arrays.binarySearch(yTiles, yLocal); if (yIDNew < 0) { yIDNew += 1; yIDNew *= -1; } yIDNew += minTileY; if ((xIDNew != xID) || (yIDNew != yID) || (dataBuffer == null)) { xID = xIDNew; yID = yIDNew; currentMaxXInclusive = xTiles[xID - minTileX]; currentMaxYInclusive = yTiles[yID - minTileY]; currentMinXInclusive = ((xID - minTileX - 1) >= 0) ? (xTiles[xID - minTileX - 1] + 1) : minx; currentMinYInclusive = ((yID - minTileY - 1) >= 0) ? (yTiles[yID - minTileY - 1] + 1) : miny; Raster tile = im.getTile(xID, yID); this.dataBuffer = tile.getDataBuffer(); this.sampleModelTranslateX = tile.getSampleModelTranslateX(); this.sampleModelTranslateY = tile.getSampleModelTranslateY(); } } public int getSample(int x, int y, int b) { makeCurrent(x, y); return sampleModel.getSample(x - sampleModelTranslateX, y - sampleModelTranslateY, b, dataBuffer); } public float getSampleFloat(int x, int y, int b) { makeCurrent(x, y); return sampleModel.getSampleFloat(x - sampleModelTranslateX, y - sampleModelTranslateY, b, dataBuffer); } public double getSampleDouble(int x, int y, int b) { makeCurrent(x, y); return sampleModel.getSampleDouble(x - sampleModelTranslateX, y - sampleModelTranslateY, b, dataBuffer); } public int[] getPixel(int x, int y, int[] iArray) { makeCurrent(x, y); return sampleModel.getPixel(x - sampleModelTranslateX, y - sampleModelTranslateY, iArray, dataBuffer); } public float[] getPixel(int x, int y, float[] fArray) { makeCurrent(x, y); return sampleModel.getPixel(x - sampleModelTranslateX, y - sampleModelTranslateY, fArray, dataBuffer); } public double[] getPixel(int x, int y, double[] dArray) { makeCurrent(x, y); return sampleModel.getPixel(x - sampleModelTranslateX, y - sampleModelTranslateY, dArray, dataBuffer); } public void done() { xTiles = null; yTiles = null; dataBuffer = null; } }