/* 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.warp; import it.geosolutions.jaiext.iterators.RandomIterFactory; import it.geosolutions.jaiext.range.Range; import java.awt.image.ColorModel; import java.awt.image.DataBuffer; import java.awt.image.IndexColorModel; import java.awt.image.RenderedImage; import java.awt.image.SampleModel; import java.util.Map; import javax.media.jai.ImageLayout; import javax.media.jai.Interpolation; import javax.media.jai.PlanarImage; import javax.media.jai.ROI; import javax.media.jai.RasterAccessor; import javax.media.jai.Warp; import javax.media.jai.iterator.RandomIter; /** * An <code>OpImage</code> implementing the general "Warp" operation as described in <code>javax.media.jai.operator.WarpDescriptor</code>. It supports * the nearest-neighbor interpolation. * * <p> * The layout for the destination image may be specified via the <code>ImageLayout</code> parameter. However, only those settings suitable for this * operation will be used. The unsuitable settings will be replaced by default suitable values. An optional ROI object and a NoData Range can be used. * If a backward mapped pixel lies outside ROI or it is a NoData, then the destination pixel value is a background value. * * @since EA2 * @see javax.media.jai.Warp * @see javax.media.jai.WarpOpImage * @see javax.media.jai.operator.WarpDescriptor * @see WarpRIF * */ @SuppressWarnings("unchecked") final class WarpNearestOpImage extends WarpOpImage { /** LookupTable used for a faster NoData check */ private byte[][] byteLookupTable; /** * Constructs a WarpNearestOpImage. * * @param source The source image. * @param config RenderingHints used in calculations. * @param layout The destination image layout. * @param warp An object defining the warp algorithm. * @param interp An object describing the interpolation method. * @param roi input ROI object used. * @param noData NoData Range object used for checking if NoData are present. * */ public WarpNearestOpImage(final RenderedImage source, final Map<?, ?> config, final ImageLayout layout, final Warp warp, final Interpolation interp, final ROI sourceROI, Range noData, double[] bkg) { super(source, layout, config, false, null, // extender not needed in nearest-neighbor interpolation interp, warp, bkg, sourceROI, noData); /* * If the source has IndexColorModel, override the default setting in OpImage. The dest shall have exactly the same SampleModel and ColorModel * as the source. Note, in this case, the source should have an integral data type. */ final ColorModel srcColorModel = source.getColorModel(); if (srcColorModel instanceof IndexColorModel) { sampleModel = source.getSampleModel() .createCompatibleSampleModel(tileWidth, tileHeight); colorModel = srcColorModel; } /* * Selection of a destinationNoData value for each datatype */ SampleModel sm = source.getSampleModel(); // Source image data Type int srcDataType = sm.getDataType(); // Creation of a lookuptable containing the values to use for no data if (srcDataType == DataBuffer.TYPE_BYTE && hasNoData) { int numBands = getNumBands(); byteLookupTable = new byte[numBands][256]; for (int b = 0; b < numBands; b++) { for (int i = 0; i < byteLookupTable[0].length; i++) { byte value = (byte) i; if (noDataRange.contains(value)) { byteLookupTable[b][i] = (byte) backgroundValues[b]; } else { byteLookupTable[b][i] = value; } } } } } protected void computeRectByte(final PlanarImage src, final RasterAccessor dst, final RandomIter roiIter, boolean roiContainsTile) { // Random Iterator on the source image bounds final RandomIter iter = RandomIterFactory.create(src, src.getBounds(), TILE_CACHED, ARRAY_CALC); // Initial settings final int minX = src.getMinX(); final int maxX = src.getMaxX(); final int minY = src.getMinY(); final int maxY = src.getMaxY(); final int dstWidth = dst.getWidth(); final int dstHeight = dst.getHeight(); final int dstBands = dst.getNumBands(); final int lineStride = dst.getScanlineStride(); final int pixelStride = dst.getPixelStride(); final int[] bandOffsets = dst.getBandOffsets(); final byte[][] data = dst.getByteDataArrays(); final float[] warpData = new float[2 * dstWidth]; int lineOffset = 0; // NO ROI AND NODATA if (caseA || (caseB && roiContainsTile)) { for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; // Calculation of the warp for the selected row warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { /* * The warp object subtract 0.5 from backward mapped source coordinate. Need to do a round to get the nearest neighbor. This is * different from the standard nearest implementation. */ final int sx = round(warpData[count++]); final int sy = round(warpData[count++]); // If the pixel is outside the input image bounds if (sx < minX || sx >= maxX || sy < minY || sy >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (byte)backgroundValues[b]; } } } else { // Nearest interpolation for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (byte) (iter.getSample(sx, sy, b) & 0xFF); } } pixelOffset += pixelStride; } } // ONLY ROI } else if (caseB) { for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; // Calculation of the warp for the selected row warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { /* * The warp object subtract 0.5 from backward mapped source coordinate. Need to do a round to get the nearest neighbor. This is * different from the standard nearest implementation. */ final int sx = round(warpData[count++]); final int sy = round(warpData[count++]); if (sx < minX || sx >= maxX || sy < minY || sy >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (byte)backgroundValues[b]; } } } else { // SG if we falls outside the roi we use the background value if (!(roiBounds.contains(sx, sy) && roiIter.getSample(sx, sy, 0) > 0)) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (byte)backgroundValues[b]; } } } else { // Else the related source pixel is set for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (byte) (iter.getSample(sx, sy, b) & 0xFF); } } } pixelOffset += pixelStride; } } // ONLY NODATA } else if (caseC || (hasROI && hasNoData && roiContainsTile)) { for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; // Calculation of the warp for the selected row warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { /* * The warp object subtract 0.5 from backward mapped source coordinate. Need to do a round to get the nearest neighbor. This is * different from the standard nearest implementation. */ final int sx = round(warpData[count++]); final int sy = round(warpData[count++]); if (sx < minX || sx >= maxX || sy < minY || sy >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (byte)backgroundValues[b]; } } } else { // The related source pixel is set if it isn't a nodata for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = byteLookupTable[b][iter.getSample( sx, sy, b)]; } } pixelOffset += pixelStride; } } // BOTH ROI AND NODATA } else { for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; // Calculation of the warp for the selected row warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { /* * The warp object subtract 0.5 from backward mapped source coordinate. Need to do a round to get the nearest neighbor. This is * different from the standard nearest implementation. */ final int sx = round(warpData[count++]); final int sy = round(warpData[count++]); if (sx < minX || sx >= maxX || sy < minY || sy >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (byte)backgroundValues[b]; } } } else { // SG if we falls outside the roi we use the background value if (!(roiBounds.contains(sx, sy) && roiBounds.contains(sx, sy) && roiIter.getSample(sx, sy, 0) > 0)) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (byte)backgroundValues[b]; } } } else { // The related source pixel is set if it isn't a nodata for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = byteLookupTable[b][iter .getSample(sx, sy, b)]; } } } pixelOffset += pixelStride; } } } iter.done(); } protected void computeRectUShort(final PlanarImage src, final RasterAccessor dst, final RandomIter roiIter, boolean roiContainsTile) { // Random Iterator on the source image bounds final RandomIter iter = RandomIterFactory.create(src, src.getBounds(), TILE_CACHED, ARRAY_CALC); // Initial settings final int minX = src.getMinX(); final int maxX = src.getMaxX(); final int minY = src.getMinY(); final int maxY = src.getMaxY(); final int dstWidth = dst.getWidth(); final int dstHeight = dst.getHeight(); final int dstBands = dst.getNumBands(); final int lineStride = dst.getScanlineStride(); final int pixelStride = dst.getPixelStride(); final int[] bandOffsets = dst.getBandOffsets(); final short[][] data = dst.getShortDataArrays(); final float[] warpData = new float[2 * dstWidth]; int lineOffset = 0; // NO ROI AND NODATA if (caseA || (caseB && roiContainsTile)) { for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; // Calculation of the warp for the selected row warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { /* * The warp object subtract 0.5 from backward mapped source coordinate. Need to do a round to get the nearest neighbor. This is * different from the standard nearest implementation. */ final int sx = round(warpData[count++]); final int sy = round(warpData[count++]); // If the pixel is outside the input image bounds if (sx < minX || sx >= maxX || sy < minY || sy >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (short)backgroundValues[b]; } } } else { // Nearest interpolation for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (short) (iter.getSample(sx, sy, b) & 0xFFFF); } } pixelOffset += pixelStride; } } // ONLY ROI } else if (caseB) { for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; // Calculation of the warp for the selected row warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { /* * The warp object subtract 0.5 from backward mapped source coordinate. Need to do a round to get the nearest neighbor. This is * different from the standard nearest implementation. */ final int sx = round(warpData[count++]); final int sy = round(warpData[count++]); if (sx < minX || sx >= maxX || sy < minY || sy >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (short)backgroundValues[b]; } } } else { // SG if we falls outside the roi we use the background value if (!(roiBounds.contains(sx, sy) && roiBounds.contains(sx, sy) && roiIter.getSample(sx, sy, 0) > 0)) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (short)backgroundValues[b]; } } } else { // Else the related source pixel is set for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (short) (iter.getSample(sx, sy, b) & 0xFFFF); } } } pixelOffset += pixelStride; } } // ONLY NODATA } else if (caseC || (hasROI && hasNoData && roiContainsTile)) { short inputValue = 0; for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; // Calculation of the warp for the selected row warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { /* * The warp object subtract 0.5 from backward mapped source coordinate. Need to do a round to get the nearest neighbor. This is * different from the standard nearest implementation. */ final int sx = round(warpData[count++]); final int sy = round(warpData[count++]); if (sx < minX || sx >= maxX || sy < minY || sy >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (short)backgroundValues[b]; } } } else { // The related source pixel is set if it isn't a nodata for (int b = 0; b < dstBands; b++) { // Input value selected inputValue = (short) (iter.getSample(sx, sy, b) & 0xFFFF); if (noDataRange.contains(inputValue)) { data[b][pixelOffset + bandOffsets[b]] = (short)backgroundValues[b]; } else { data[b][pixelOffset + bandOffsets[b]] = inputValue; } } } pixelOffset += pixelStride; } } // BOTH ROI AND NODATA } else { short inputValue = 0; for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; // Calculation of the warp for the selected row warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { /* * The warp object subtract 0.5 from backward mapped source coordinate. Need to do a round to get the nearest neighbor. This is * different from the standard nearest implementation. */ final int sx = round(warpData[count++]); final int sy = round(warpData[count++]); if (sx < minX || sx >= maxX || sy < minY || sy >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (short)backgroundValues[b]; } } } else { // SG if we falls outside the roi we use the background value if (!(roiBounds.contains(sx, sy) && roiIter.getSample(sx, sy, 0) > 0)) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (short)backgroundValues[b]; } } } else { // The related source pixel is set if it isn't a nodata for (int b = 0; b < dstBands; b++) { // Input value selected inputValue = (short) (iter.getSample(sx, sy, b) & 0xFFFF); if (noDataRange.contains(inputValue)) { data[b][pixelOffset + bandOffsets[b]] = (short)backgroundValues[b]; } else { data[b][pixelOffset + bandOffsets[b]] = inputValue; } } } } pixelOffset += pixelStride; } } } iter.done(); } protected void computeRectShort(final PlanarImage src, final RasterAccessor dst, final RandomIter roiIter, boolean roiContainsTile) { // Random Iterator on the source image bounds final RandomIter iter = RandomIterFactory.create(src, src.getBounds(), TILE_CACHED, ARRAY_CALC); // Initial settings final int minX = src.getMinX(); final int maxX = src.getMaxX(); final int minY = src.getMinY(); final int maxY = src.getMaxY(); final int dstWidth = dst.getWidth(); final int dstHeight = dst.getHeight(); final int dstBands = dst.getNumBands(); final int lineStride = dst.getScanlineStride(); final int pixelStride = dst.getPixelStride(); final int[] bandOffsets = dst.getBandOffsets(); final short[][] data = dst.getShortDataArrays(); final float[] warpData = new float[2 * dstWidth]; int lineOffset = 0; // NO ROI AND NODATA if (caseA || (caseB && roiContainsTile)) { for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; // Calculation of the warp for the selected row warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { /* * The warp object subtract 0.5 from backward mapped source coordinate. Need to do a round to get the nearest neighbor. This is * different from the standard nearest implementation. */ final int sx = round(warpData[count++]); final int sy = round(warpData[count++]); // If the pixel is outside the input image bounds if (sx < minX || sx >= maxX || sy < minY || sy >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (short)backgroundValues[b]; } } } else { // Nearest interpolation for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (short) iter.getSample(sx, sy, b); } } pixelOffset += pixelStride; } } // ONLY ROI } else if (caseB) { for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; // Calculation of the warp for the selected row warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { /* * The warp object subtract 0.5 from backward mapped source coordinate. Need to do a round to get the nearest neighbor. This is * different from the standard nearest implementation. */ final int sx = round(warpData[count++]); final int sy = round(warpData[count++]); if (sx < minX || sx >= maxX || sy < minY || sy >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (short)backgroundValues[b]; } } } else { // SG if we falls outside the roi we use the background value if (!(roiBounds.contains(sx, sy) && roiIter.getSample(sx, sy, 0) > 0)) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (short)backgroundValues[b]; } } } else { // Else the related source pixel is set for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (short) iter.getSample(sx, sy, b); } } } pixelOffset += pixelStride; } } // ONLY NODATA } else if (caseC || (hasROI && hasNoData && roiContainsTile)) { short inputValue = 0; for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; // Calculation of the warp for the selected row warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { /* * The warp object subtract 0.5 from backward mapped source coordinate. Need to do a round to get the nearest neighbor. This is * different from the standard nearest implementation. */ final int sx = round(warpData[count++]); final int sy = round(warpData[count++]); if (sx < minX || sx >= maxX || sy < minY || sy >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (short)backgroundValues[b]; } } } else { // The related source pixel is set if it isn't a nodata for (int b = 0; b < dstBands; b++) { // Input value selected inputValue = (short) iter.getSample(sx, sy, b); if (noDataRange.contains(inputValue)) { data[b][pixelOffset + bandOffsets[b]] = (short)backgroundValues[b]; } else { data[b][pixelOffset + bandOffsets[b]] = inputValue; } } } pixelOffset += pixelStride; } } // BOTH ROI AND NODATA } else { short inputValue = 0; for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; // Calculation of the warp for the selected row warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { /* * The warp object subtract 0.5 from backward mapped source coordinate. Need to do a round to get the nearest neighbor. This is * different from the standard nearest implementation. */ final int sx = round(warpData[count++]); final int sy = round(warpData[count++]); if (sx < minX || sx >= maxX || sy < minY || sy >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (short)backgroundValues[b]; } } } else { // SG if we falls outside the roi we use the background value if (!(roiBounds.contains(sx, sy) && roiIter.getSample(sx, sy, 0) > 0)) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (short)backgroundValues[b]; } } } else { // The related source pixel is set if it isn't a nodata for (int b = 0; b < dstBands; b++) { // Input value selected inputValue = (short) iter.getSample(sx, sy, b); if (noDataRange.contains(inputValue)) { data[b][pixelOffset + bandOffsets[b]] = (short)backgroundValues[b]; } else { data[b][pixelOffset + bandOffsets[b]] = inputValue; } } } } pixelOffset += pixelStride; } } } iter.done(); } protected void computeRectInt(final PlanarImage src, final RasterAccessor dst, final RandomIter roiIter, boolean roiContainsTile) { // Random Iterator on the source image bounds final RandomIter iter = RandomIterFactory.create(src, src.getBounds(), TILE_CACHED, ARRAY_CALC); // Initial settings final int minX = src.getMinX(); final int maxX = src.getMaxX(); final int minY = src.getMinY(); final int maxY = src.getMaxY(); final int dstWidth = dst.getWidth(); final int dstHeight = dst.getHeight(); final int dstBands = dst.getNumBands(); final int lineStride = dst.getScanlineStride(); final int pixelStride = dst.getPixelStride(); final int[] bandOffsets = dst.getBandOffsets(); final int[][] data = dst.getIntDataArrays(); final float[] warpData = new float[2 * dstWidth]; int lineOffset = 0; // NO ROI AND NODATA if (caseA || (caseB && roiContainsTile)) { for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; // Calculation of the warp for the selected row warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { /* * The warp object subtract 0.5 from backward mapped source coordinate. Need to do a round to get the nearest neighbor. This is * different from the standard nearest implementation. */ final int sx = round(warpData[count++]); final int sy = round(warpData[count++]); // If the pixel is outside the input image bounds if (sx < minX || sx >= maxX || sy < minY || sy >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (int)backgroundValues[b]; } } } else { // Nearest interpolation for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = iter.getSample(sx, sy, b); } } pixelOffset += pixelStride; } } // ONLY ROI } else if (caseB) { for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; // Calculation of the warp for the selected row warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { /* * The warp object subtract 0.5 from backward mapped source coordinate. Need to do a round to get the nearest neighbor. This is * different from the standard nearest implementation. */ final int sx = round(warpData[count++]); final int sy = round(warpData[count++]); if (sx < minX || sx >= maxX || sy < minY || sy >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (int)backgroundValues[b]; } } } else { // SG if we falls outside the roi we use the background value if (!(roiBounds.contains(sx, sy) && roiIter.getSample(sx, sy, 0) > 0)) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (int)backgroundValues[b]; } } } else { // Else the related source pixel is set for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = iter.getSample(sx, sy, b); } } } pixelOffset += pixelStride; } } // ONLY NODATA } else if (caseC || (hasROI && hasNoData && roiContainsTile)) { int inputValue = 0; for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; // Calculation of the warp for the selected row warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { /* * The warp object subtract 0.5 from backward mapped source coordinate. Need to do a round to get the nearest neighbor. This is * different from the standard nearest implementation. */ final int sx = round(warpData[count++]); final int sy = round(warpData[count++]); if (sx < minX || sx >= maxX || sy < minY || sy >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (int)backgroundValues[b]; } } } else { // The related source pixel is set if it isn't a nodata for (int b = 0; b < dstBands; b++) { // Input value selected inputValue = iter.getSample(sx, sy, b); if (noDataRange.contains(inputValue)) { data[b][pixelOffset + bandOffsets[b]] = (int)backgroundValues[b]; } else { data[b][pixelOffset + bandOffsets[b]] = inputValue; } } } pixelOffset += pixelStride; } } // BOTH ROI AND NODATA } else { int inputValue = 0; for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; // Calculation of the warp for the selected row warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { /* * The warp object subtract 0.5 from backward mapped source coordinate. Need to do a round to get the nearest neighbor. This is * different from the standard nearest implementation. */ final int sx = round(warpData[count++]); final int sy = round(warpData[count++]); if (sx < minX || sx >= maxX || sy < minY || sy >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (int)backgroundValues[b]; } } } else { // SG if we falls outside the roi we use the background value if (!(roiBounds.contains(sx, sy) && roiIter.getSample(sx, sy, 0) > 0)) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (int)backgroundValues[b]; } } } else { // The related source pixel is set if it isn't a nodata for (int b = 0; b < dstBands; b++) { // Input value selected inputValue = iter.getSample(sx, sy, b); if (noDataRange.contains(inputValue)) { data[b][pixelOffset + bandOffsets[b]] = (int)backgroundValues[b]; } else { data[b][pixelOffset + bandOffsets[b]] = inputValue; } } } } pixelOffset += pixelStride; } } } iter.done(); } protected void computeRectFloat(final PlanarImage src, final RasterAccessor dst, final RandomIter roiIter, boolean roiContainsTile) { // Random Iterator on the source image bounds final RandomIter iter = RandomIterFactory.create(src, src.getBounds(), TILE_CACHED, ARRAY_CALC); // Initial settings final int minX = src.getMinX(); final int maxX = src.getMaxX(); final int minY = src.getMinY(); final int maxY = src.getMaxY(); final int dstWidth = dst.getWidth(); final int dstHeight = dst.getHeight(); final int dstBands = dst.getNumBands(); final int lineStride = dst.getScanlineStride(); final int pixelStride = dst.getPixelStride(); final int[] bandOffsets = dst.getBandOffsets(); final float[][] data = dst.getFloatDataArrays(); final float[] warpData = new float[2 * dstWidth]; int lineOffset = 0; // NO ROI AND NODATA if (caseA || (caseB && roiContainsTile)) { for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; // Calculation of the warp for the selected row warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { /* * The warp object subtract 0.5 from backward mapped source coordinate. Need to do a round to get the nearest neighbor. This is * different from the standard nearest implementation. */ final int sx = round(warpData[count++]); final int sy = round(warpData[count++]); // If the pixel is outside the input image bounds if (sx < minX || sx >= maxX || sy < minY || sy >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (float)backgroundValues[b]; } } } else { // Nearest interpolation for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = iter.getSampleFloat(sx, sy, b); } } pixelOffset += pixelStride; } } // ONLY ROI } else if (caseB) { for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; // Calculation of the warp for the selected row warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { /* * The warp object subtract 0.5 from backward mapped source coordinate. Need to do a round to get the nearest neighbor. This is * different from the standard nearest implementation. */ final int sx = round(warpData[count++]); final int sy = round(warpData[count++]); if (sx < minX || sx >= maxX || sy < minY || sy >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (float)backgroundValues[b]; } } } else { // SG if we falls outside the roi we use the background value if (!(roiBounds.contains(sx, sy) && roiIter.getSample(sx, sy, 0) > 0)) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (float)backgroundValues[b]; } } } else { // Else the related source pixel is set for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = iter.getSampleFloat(sx, sy, b); } } } pixelOffset += pixelStride; } } // ONLY NODATA } else if (caseC || (hasROI && hasNoData && roiContainsTile)) { float inputValue = 0; for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; // Calculation of the warp for the selected row warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { /* * The warp object subtract 0.5 from backward mapped source coordinate. Need to do a round to get the nearest neighbor. This is * different from the standard nearest implementation. */ final int sx = round(warpData[count++]); final int sy = round(warpData[count++]); if (sx < minX || sx >= maxX || sy < minY || sy >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (float)backgroundValues[b]; } } } else { // The related source pixel is set if it isn't a nodata for (int b = 0; b < dstBands; b++) { // Input value selected inputValue = iter.getSampleFloat(sx, sy, b); if (noDataRange.contains(inputValue)) { data[b][pixelOffset + bandOffsets[b]] = (float)backgroundValues[b]; } else { data[b][pixelOffset + bandOffsets[b]] = inputValue; } } } pixelOffset += pixelStride; } } // BOTH ROI AND NODATA } else { float inputValue = 0; for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; // Calculation of the warp for the selected row warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { /* * The warp object subtract 0.5 from backward mapped source coordinate. Need to do a round to get the nearest neighbor. This is * different from the standard nearest implementation. */ final int sx = round(warpData[count++]); final int sy = round(warpData[count++]); if (sx < minX || sx >= maxX || sy < minY || sy >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (float)backgroundValues[b]; } } } else { // SG if we falls outside the roi we use the background value if (!(roiBounds.contains(sx, sy) && roiIter.getSample(sx, sy, 0) > 0)) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = (float)backgroundValues[b]; } } } else { // The related source pixel is set if it isn't a nodata for (int b = 0; b < dstBands; b++) { // Input value selected inputValue = iter.getSampleFloat(sx, sy, b); if (noDataRange.contains(inputValue)) { data[b][pixelOffset + bandOffsets[b]] = (float)backgroundValues[b]; } else { data[b][pixelOffset + bandOffsets[b]] = inputValue; } } } } pixelOffset += pixelStride; } } } iter.done(); } protected void computeRectDouble(final PlanarImage src, final RasterAccessor dst, final RandomIter roiIter, boolean roiContainsTile) { // Random Iterator on the source image bounds final RandomIter iter = RandomIterFactory.create(src, src.getBounds(), TILE_CACHED, ARRAY_CALC); // Initial settings final int minX = src.getMinX(); final int maxX = src.getMaxX(); final int minY = src.getMinY(); final int maxY = src.getMaxY(); final int dstWidth = dst.getWidth(); final int dstHeight = dst.getHeight(); final int dstBands = dst.getNumBands(); final int lineStride = dst.getScanlineStride(); final int pixelStride = dst.getPixelStride(); final int[] bandOffsets = dst.getBandOffsets(); final double[][] data = dst.getDoubleDataArrays(); final float[] warpData = new float[2 * dstWidth]; int lineOffset = 0; // NO ROI AND NODATA if (caseA || (caseB && roiContainsTile)) { for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; // Calculation of the warp for the selected row warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { /* * The warp object subtract 0.5 from backward mapped source coordinate. Need to do a round to get the nearest neighbor. This is * different from the standard nearest implementation. */ final int sx = round(warpData[count++]); final int sy = round(warpData[count++]); // If the pixel is outside the input image bounds if (sx < minX || sx >= maxX || sy < minY || sy >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = backgroundValues[b]; } } } else { // Nearest interpolation for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = iter.getSampleDouble(sx, sy, b); } } pixelOffset += pixelStride; } } // ONLY ROI } else if (caseB) { for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; // Calculation of the warp for the selected row warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { /* * The warp object subtract 0.5 from backward mapped source coordinate. Need to do a round to get the nearest neighbor. This is * different from the standard nearest implementation. */ final int sx = round(warpData[count++]); final int sy = round(warpData[count++]); if (sx < minX || sx >= maxX || sy < minY || sy >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = backgroundValues[b]; } } } else { // SG if we falls outside the roi we use the background value if (!(roiBounds.contains(sx, sy) && roiIter.getSample(sx, sy, 0) > 0)) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = backgroundValues[b]; } } } else { // Else the related source pixel is set for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = iter.getSampleDouble(sx, sy, b); } } } pixelOffset += pixelStride; } } // ONLY NODATA } else if (caseC || (hasROI && hasNoData && roiContainsTile)) { double inputValue = 0; for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; // Calculation of the warp for the selected row warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { /* * The warp object subtract 0.5 from backward mapped source coordinate. Need to do a round to get the nearest neighbor. This is * different from the standard nearest implementation. */ final int sx = round(warpData[count++]); final int sy = round(warpData[count++]); if (sx < minX || sx >= maxX || sy < minY || sy >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = backgroundValues[b]; } } } else { // The related source pixel is set if it isn't a nodata for (int b = 0; b < dstBands; b++) { // Input value selected inputValue = iter.getSampleDouble(sx, sy, b); if (noDataRange.contains(inputValue)) { data[b][pixelOffset + bandOffsets[b]] = backgroundValues[b]; } else { data[b][pixelOffset + bandOffsets[b]] = inputValue; } } } pixelOffset += pixelStride; } } // BOTH ROI AND NODATA } else { double inputValue = 0; for (int h = 0; h < dstHeight; h++) { int pixelOffset = lineOffset; lineOffset += lineStride; // Calculation of the warp for the selected row warp.warpRect(dst.getX(), dst.getY() + h, dstWidth, 1, warpData); int count = 0; for (int w = 0; w < dstWidth; w++) { /* * The warp object subtract 0.5 from backward mapped source coordinate. Need to do a round to get the nearest neighbor. This is * different from the standard nearest implementation. */ final int sx = round(warpData[count++]); final int sy = round(warpData[count++]); if (sx < minX || sx >= maxX || sy < minY || sy >= maxY) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = backgroundValues[b]; } } } else { // SG if we falls outside the roi we use the background value if (!(roiBounds.contains(sx, sy) && roiIter.getSample(sx, sy, 0) > 0)) { /* Fill with a background color. */ if (setBackground) { for (int b = 0; b < dstBands; b++) { data[b][pixelOffset + bandOffsets[b]] = backgroundValues[b]; } } } else { // The related source pixel is set if it isn't a nodata for (int b = 0; b < dstBands; b++) { // Input value selected inputValue = iter.getSampleDouble(sx, sy, b); if (noDataRange.contains(inputValue)) { data[b][pixelOffset + bandOffsets[b]] = backgroundValues[b]; } else { data[b][pixelOffset + bandOffsets[b]] = inputValue; } } } } pixelOffset += pixelStride; } } } iter.done(); } }