/* 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.scale; import java.awt.Rectangle; import java.awt.image.ColorModel; import java.awt.image.DataBuffer; import java.awt.image.DataBufferByte; import java.awt.image.DataBufferInt; import java.awt.image.DataBufferUShort; import java.awt.image.IndexColorModel; import java.awt.image.MultiPixelPackedSampleModel; import java.awt.image.Raster; import java.awt.image.RenderedImage; import java.awt.image.SampleModel; import java.awt.image.WritableRaster; import java.util.Map; import javax.media.jai.BorderExtender; import javax.media.jai.ImageLayout; import javax.media.jai.Interpolation; import javax.media.jai.InterpolationBicubic2; import javax.media.jai.InterpolationTable; import javax.media.jai.RasterAccessor; import javax.media.jai.RasterFormatTag; import javax.media.jai.iterator.RandomIter; import com.sun.media.jai.util.ImageUtil; import com.sun.media.jai.util.Rational; import it.geosolutions.jaiext.interpolators.InterpolationBicubic; import it.geosolutions.jaiext.interpolators.InterpolationBilinear; import it.geosolutions.jaiext.interpolators.InterpolationNearest; import it.geosolutions.jaiext.interpolators.InterpolationNoData; import it.geosolutions.jaiext.iterators.RandomIterFactory; import it.geosolutions.jaiext.range.Range; /** * This class is an extends the functionality of the ScaleOpImage class by adding the support for No Data values and by extending the ROI support for * all the image types and for binary images. The interpolation type performed by the scale operation is indicated by the Interpolation Object used. * For Nearest-Neighbor, Bilinear, Bicubic/Bicubic2 interpolation type, the new Interpolation class InterpolationNearest, InterpolationBilinear, * InterpolationBicubic should be used for having optimized calculation on the scale operation, ROI and No Data support. If these special * Interpolation objects are not used, the interpolation is performed by using the interpolate() method of the interpolator used in the selected * kernel, but without ROI and No Data support. Another main difference from the old Scale operations is the reduction of all the operations to one * singular class instead of having various different classes. */ // @SuppressWarnings("unchecked") public class ScaleGeneralOpImage extends ScaleOpImage { /** Nearest-Neighbor interpolator */ protected InterpolationNearest interpN = null; /** Bilinear interpolator */ protected InterpolationBilinear interpB = null; /** Bicubic interpolator */ protected InterpolationBicubic interpBN = null; // Simple constructor used for interpolators different from InterpolationNearest2, InterpolationBilinear2, InterpolationBicubic public ScaleGeneralOpImage(RenderedImage source, ImageLayout layout, Map configuration, BorderExtender extender, Interpolation interp, float scaleX, float scaleY, float transX, float transY, boolean useRoiAccessor, Range nodata, double[] backgroundValues) { super(source, layout, configuration, true, extender, interp, scaleX, scaleY, transX, transY, useRoiAccessor, backgroundValues); scaleOpInitialization(source,interp, nodata, backgroundValues); } private void scaleOpInitialization(RenderedImage source, Interpolation interp, Range nodata, double[] backgroundValues) { // If the source has an 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. ColorModel srcColorModel = source.getColorModel(); if (srcColorModel instanceof IndexColorModel && ImageUtil.isBinary(source.getSampleModel())) { sampleModel = source.getSampleModel() .createCompatibleSampleModel(tileWidth, tileHeight); colorModel = srcColorModel; } // selection of the inverse scale parameters both for the x and y axis if (invScaleXRational.num > invScaleXRational.denom) { invScaleXInt = invScaleXRational.num / invScaleXRational.denom; invScaleXFrac = invScaleXRational.num % invScaleXRational.denom; } else { invScaleXInt = 0; invScaleXFrac = invScaleXRational.num; } if (invScaleYRational.num > invScaleYRational.denom) { invScaleYInt = invScaleYRational.num / invScaleYRational.denom; invScaleYFrac = invScaleYRational.num % invScaleYRational.denom; } else { invScaleYInt = 0; invScaleYFrac = invScaleYRational.num; } // Interpolator settings interpolator = interp; double[] destNod = null; if (backgroundValues != null && backgroundValues.length > 0){ destNod = backgroundValues; } if (interpolator instanceof InterpolationNearest) { isNearestNew=true; interpN = (InterpolationNearest) interpolator; this.interp=interpN; interpN.setROIBounds(roiBounds); if(destNod == null){ destNod = new double[]{interpN.getDestinationNoData()}; } } else if (interpolator instanceof InterpolationBilinear) { isBilinearNew=true; interpB = (InterpolationBilinear) interpolator; this.interp=interpB; interpB.setROIBounds(roiBounds); if(destNod == null){ destNod = new double[]{interpB.getDestinationNoData()}; } } else if (interpolator instanceof InterpolationBicubic) { isBicubicNew=true; interpBN = (InterpolationBicubic) interpolator; this.interp=interpBN; interpBN.setROIBounds(roiBounds); if(destNod == null){ destNod = new double[]{interpBN.getDestinationNoData()}; } } else if (this.backgroundValues != null) { destNod = this.backgroundValues; } if(destNod == null){ destNod = new double[]{0d}; } this.destinationNoDataDouble = destNod; if(interpolator instanceof InterpolationNoData){ InterpolationNoData interpolationNoData = (InterpolationNoData)interpolator; interpolationNoData.setDestinationNoData(destNod[0]); if(nodata != null){ hasNoData = true; interpolationNoData.setNoDataRange(nodata); } interpolationNoData.setUseROIAccessor(this.useRoiAccessor); } // subsample bits used for the bilinear and bicubic interpolation subsampleBits = interp.getSubsampleBitsH(); // Internal precision required for position calculations one = 1 << subsampleBits; // Subsampling related variables shift2 = 2 * subsampleBits; round2 = 1 << (shift2 - 1); // Interpolation table used in the bicubic interpolation if (interpolator instanceof InterpolationTable) { InterpolationTable interpTable = (InterpolationTable) interpolator; precisionBits = interpTable.getPrecisionBits(); } // Number of subsample positions one = 1 << subsampleBits; if (precisionBits > 0) { round = 1 << (precisionBits - 1); } // Get the width and height and padding of the Interpolation kernel. interp_width = interp.getWidth(); interp_height = interp.getHeight(); interp_left = interp.getLeftPadding(); interp_top = interp.getTopPadding(); SampleModel sm = source.getSampleModel(); // Selection of the destination No Data switch (sm.getDataType()) { case DataBuffer.TYPE_BYTE: destinationNoDataByte = new byte[1]; destinationNoDataByte[0] = (byte) (((byte) destinationNoDataDouble[0]) & 0xff); break; case DataBuffer.TYPE_USHORT: destinationNoDataUShort = new short[1]; destinationNoDataUShort[0] = (short) (((short) destinationNoDataDouble[0]) & 0xffff); break; case DataBuffer.TYPE_SHORT: destinationNoDataShort = new short[1]; destinationNoDataShort[0] = (short) destinationNoDataDouble[0]; break; case DataBuffer.TYPE_INT: destinationNoDataInt = new int[1]; destinationNoDataInt[0] = (int) destinationNoDataDouble[0]; break; case DataBuffer.TYPE_FLOAT: destinationNoDataFloat = new float[1]; destinationNoDataFloat[0] = (float) destinationNoDataDouble[0]; break; case DataBuffer.TYPE_DOUBLE: break; default: throw new IllegalArgumentException("Wrong data Type"); } // Special case -- if the image is represented using // a MultiPixelPackedSampleModel and a byte, ushort, // or int DataBuffer we can access the pixel data directly. // Note that there is a potential loophole that has not been // resolved by Java2D as to whether the underlying DataBuffer // must be of one of the standard types. Here we make the // assumption that it will be -- we can't check without // forcing an actual tile to be computed. // isBinary = (sm instanceof MultiPixelPackedSampleModel) && (sm.getSampleSize(0) == 1) && (sm.getDataType() == DataBuffer.TYPE_BYTE || sm.getDataType() == DataBuffer.TYPE_USHORT || sm.getDataType() == DataBuffer.TYPE_INT); } /** This method executes the scale operation on a selected region of the image */ protected void computeRect(Raster[] sources, WritableRaster dest, Rectangle destRect) { // Retrieve format tags. RasterFormatTag[] formatTags = getFormatTags(); // Only one source raster is used Raster source = sources[0]; // Get the source rectangle Rectangle srcRect = source.getBounds(); // SRC and destination accessors are used for simplifying calculations RasterAccessor srcAccessor = new RasterAccessor(source, srcRect, formatTags[0], getSourceImage(0).getColorModel()); RasterAccessor dstAccessor = new RasterAccessor(dest, destRect, formatTags[1], getColorModel()); // Destination rectangle dimensions int dwidth = destRect.width; int dheight = destRect.height; // From the rasterAccessor are calculated the pixelStride and the scanLineStride int srcPixelStride = srcAccessor.getPixelStride(); int srcScanlineStride = srcAccessor.getScanlineStride(); // Initialization of the x and y position array int[] xpos = new int[dwidth]; int[] ypos = new int[dheight]; // Initialization of the x and y fractional position array Number xfracvalues[] = null, yfracvalues[] = null; // ROI support int[] yposRoi = null; // Scanline stride. It is used as integer because it can return null values Integer roiScanlineStride = null; // Roi rasterAccessor initialization RasterAccessor roiAccessor = null; // Roi raster initialization Raster roi = null; RandomIter roiIter = null; // ROI calculation only if the roi raster is present if (hasROI) { if (useRoiAccessor) { if(srcROIImage.getBounds().contains(srcRect)){ roi = srcROIImage.getData(srcRect); } else { roi = srcROIImgExt.getData(srcRect); } // creation of the rasterAccessor roiAccessor = new RasterAccessor(roi, srcRect, RasterAccessor.findCompatibleTags( new RenderedImage[] { srcROIImage }, srcROIImage)[0], srcROIImage.getColorModel()); // ROI scanlinestride roiScanlineStride = roiAccessor.getScanlineStride(); // Initialization of the roi y position array yposRoi = new int[dheight]; } else { roiIter = RandomIterFactory.create(srcROIImgExt, roiRect, true, true); } } // destination data type dataType = dest.getSampleModel().getDataType(); // initialization of the x and y fractional values yfracvalues = new Number[dheight]; xfracvalues = new Number[dwidth]; // Private method for calculating the x and y positions, x and y fractional positions and y roi positions if present preComputePositions(destRect, srcRect.x, srcRect.y, srcPixelStride, srcScanlineStride, xpos, ypos, xfracvalues, yfracvalues, roiScanlineStride, yposRoi); // This methods differs only for the presence of the roi or if the image is a binary one if (isBinary) { computeLoopBynary(srcAccessor, source, dest, destRect, xpos, ypos,yposRoi, xfracvalues, yfracvalues,roi,yposRoi,srcRect.x, srcRect.y, roiIter); } else { if (hasROI) { computeLoop(srcAccessor, destRect, dstAccessor, xpos, ypos, xfracvalues, yfracvalues, roiAccessor, roiIter, yposRoi); } else { computeLoop(srcAccessor, destRect, dstAccessor, xpos, ypos, xfracvalues, yfracvalues, null, null, null); } } } // This method precompute the integer and fractional position of every pixel private void preComputePositions(Rectangle destRect, int srcRectX, int srcRectY, int srcPixelStride, int srcScanlineStride, int xpos[], int ypos[], Number[] xfracvalues, Number[] yfracvalues, Integer roiScanlineStride, int[] yposRoi) { // Destination Rectangle position int dwidth = destRect.width; int dheight = destRect.height; // Loop variables based on the destination rectangle to be calculated. int dx = destRect.x; int dy = destRect.y; // Initially the y source value is calculated by the destination value and then performing the inverse // scale operation on it. long syNum = dy, syDenom = 1; // Subtract the X translation factor sy -= transY syNum = syNum * transYRationalDenom - transYRationalNum * syDenom; syDenom *= transYRationalDenom; // Add 0.5 syNum = 2 * syNum + syDenom; syDenom *= 2; // Multply by invScaleX syNum *= invScaleYRationalNum; syDenom *= invScaleYRationalDenom; if(interpBN!=null|| interpB!=null || interpolator instanceof InterpolationBilinear || interpolator instanceof InterpolationBicubic || interpolator instanceof InterpolationBicubic2){ // Subtract 0.5 syNum = 2 * syNum - syDenom; syDenom *= 2; } // Separate the y source coordinate into integer and fractional part int srcYInt = Rational.floor(syNum, syDenom); long srcYFrac = syNum % syDenom; if (srcYInt < 0) { srcYFrac = syDenom + srcYFrac; } // Normalize - Get a common denominator for the fracs of // src and invScaleY long commonYDenom = syDenom * invScaleYRationalDenom; srcYFrac *= invScaleYRationalDenom; long newInvScaleYFrac = invScaleYFrac * syDenom; // Initially the x source value is calculated by the destination value and then performing the inverse // scale operation on it. long sxNum = dx, sxDenom = 1; // Subtract the X translation factor sx -= transX sxNum = sxNum * transXRationalDenom - transXRationalNum * sxDenom; sxDenom *= transXRationalDenom; // Add 0.5 sxNum = 2 * sxNum + sxDenom; sxDenom *= 2; // Multply by invScaleX sxNum *= invScaleXRationalNum; sxDenom *= invScaleXRationalDenom; if(interpBN!=null|| interpB!=null || interpolator instanceof InterpolationBilinear || interpolator instanceof InterpolationBicubic || interpolator instanceof InterpolationBicubic2){ // Subtract 0.5 sxNum = 2 * sxNum - sxDenom; sxDenom *= 2; } // Separate the x source coordinate into integer and fractional part int srcXInt = Rational.floor(sxNum, sxDenom); long srcXFrac = sxNum % sxDenom; if (srcXInt < 0) { srcXFrac = sxDenom + srcXFrac; } // Normalize - Get a common denominator for the fracs of // src and invScaleX long commonXDenom = sxDenom * invScaleXRationalDenom; srcXFrac *= invScaleXRationalDenom; long newInvScaleXFrac = invScaleXFrac * sxDenom; // Store of the x positions for (int i = 0; i < dwidth; i++) { if(isBinary){ xpos[i] = srcXInt; }else{ xpos[i] = (srcXInt - srcRectX) * srcPixelStride; } // Calculate the yfrac value if (dataType < DataBuffer.TYPE_FLOAT) { xfracvalues[i] = (int) (((1.0f *srcXFrac )/ commonXDenom) * one); } else { xfracvalues[i] = (1.0f * srcXFrac )/ commonXDenom; } // Move onto the next source pixel. // Add the integral part of invScaleX to the integral part // of srcX srcXInt += invScaleXInt; // Add the fractional part of invScaleX to the fractional part // of srcX srcXFrac += newInvScaleXFrac; // If the fractional part is now greater than equal to the // denominator, divide so as to reduce the numerator to be less // than the denominator and add the overflow to the integral part. if (srcXFrac >= commonXDenom) { srcXInt += 1; srcXFrac -= commonXDenom; } } // Store of the y positions for (int i = 0; i < dheight; i++) { // Calculate the source position in the source data array. if(isBinary){ ypos[i] = srcYInt; }else{ ypos[i] = (srcYInt - srcRectY) * srcScanlineStride; } // If roi is present, the y position roi value is calculated if (yposRoi != null) { if(isBinary){ yposRoi[i] = srcYInt; }else{ yposRoi[i] = (srcYInt - srcRectY) * roiScanlineStride; } } // Calculate the yfrac value if (dataType < DataBuffer.TYPE_FLOAT) { yfracvalues[i] = (int) (((float) srcYFrac / (float) commonYDenom) * one); } else { yfracvalues[i] = (float) srcYFrac / (float) commonYDenom; } // Move onto the next source pixel. // Add the integral part of invScaleY to the integral part // of srcY srcYInt += invScaleYInt; // Add the fractional part of invScaleY to the fractional part // of srcY srcYFrac += newInvScaleYFrac; // If the fractional part is now greater than equal to the // denominator, divide so as to reduce the numerator to be less // than the denominator and add the overflow to the integral part. if (srcYFrac >= commonYDenom) { srcYInt += 1; srcYFrac -= commonYDenom; } } } // Method for calculating the destination pixels without using the roiAccessor private void computeLoop(RasterAccessor src, Rectangle dstRect, RasterAccessor dst, int[] xpos, int[] ypos, Number[] xfracvalues, Number[] yfracvalues, RasterAccessor roi, RandomIter roiIter, int[] yposRoi) { // Source PixelStride and ScanLineStride and bandOffsets int srcPixelStride = src.getPixelStride(); int srcScanlineStride = src.getScanlineStride(); int bandOffsets[] = src.getBandOffsets(); // Destination rectangle dimensions int dwidth = dstRect.width; int dheight = dstRect.height; // Destination image band numbers int dnumBands = dst.getNumBands(); // Destination bandOffsets, PixelStride and ScanLineStride int dstBandOffsets[] = dst.getBandOffsets(); int dstPixelStride = dst.getPixelStride(); int dstScanlineStride = dst.getScanlineStride(); // Destination and source data arrays (for all bands) // ONLY ONE OF THIS VALUES IS NOT NULL, THE OTHERS ARE ALL NULL byte[][] srcDataArraysByte = src.getByteDataArrays(); short[][] srcDataArraysUshort = src.getShortDataArrays(); short[][] srcDataArraysShort = src.getShortDataArrays(); int[][] srcDataArraysInt = src.getIntDataArrays(); float[][] srcDataArraysFloat = src.getFloatDataArrays(); double[][] srcDataArraysDouble = src.getDoubleDataArrays(); byte[][] dstDataArraysByte = dst.getByteDataArrays(); short[][] dstDataArraysUshort = dst.getShortDataArrays(); short[][] dstDataArraysShort = dst.getShortDataArrays(); int[][] dstDataArraysInt = dst.getIntDataArrays(); float[][] dstDataArraysFloat = dst.getFloatDataArrays(); double[][] dstDataArraysDouble = dst.getDoubleDataArrays(); // Destination and source data arrays (for a single band) byte[] dstDataByte = null; short[] dstDataUshort = null; short[] dstDataShort = null; int[] dstDataInt = null; float[] dstDataFloat = null; double[] dstDataDouble = null; byte[] srcDataByte = null; short[] srcDataUshort = null; short[] srcDataShort = null; int[] srcDataInt = null; float[] srcDataFloat = null; double[] srcDataDouble = null; // Array of samples required for the interpolation (Used only for general interpolators) int[][] samples = null; float[][] samplesf = null; double[][] samplesd = null; switch (dataType) { case DataBuffer.TYPE_BYTE: case DataBuffer.TYPE_USHORT: case DataBuffer.TYPE_SHORT: case DataBuffer.TYPE_INT: samples = new int[interp_height][interp_width]; break; case DataBuffer.TYPE_FLOAT: samplesf = new float[interp_height][interp_width]; break; case DataBuffer.TYPE_DOUBLE: samplesd = new double[interp_height][interp_width]; break; default: break; } // Destination pixel returned Number s = null; // for all bands for (int k = 0; k < dnumBands; k++) { switch (dataType) { case DataBuffer.TYPE_BYTE: srcDataByte = srcDataArraysByte[k]; dstDataByte = dstDataArraysByte[k]; break; case DataBuffer.TYPE_USHORT: srcDataUshort = srcDataArraysUshort[k]; dstDataUshort = dstDataArraysUshort[k]; break; case DataBuffer.TYPE_SHORT: srcDataShort = srcDataArraysShort[k]; dstDataShort = dstDataArraysShort[k]; break; case DataBuffer.TYPE_INT: srcDataInt = srcDataArraysInt[k]; dstDataInt = dstDataArraysInt[k]; break; case DataBuffer.TYPE_FLOAT: srcDataFloat = srcDataArraysFloat[k]; dstDataFloat = dstDataArraysFloat[k]; break; case DataBuffer.TYPE_DOUBLE: srcDataDouble = srcDataArraysDouble[k]; dstDataDouble = dstDataArraysDouble[k]; break; default: break; } // Line and band Offset initialization int dstlineOffset = dstBandOffsets[k]; int bandOffset = bandOffsets[k]; // cycle on the y values for (int j = 0; j < dheight; j++) { // pixel offset initialization int dstPixelOffset = dstlineOffset; // y position selection int posy = ypos[j] + bandOffset; // roi y position initialization Integer posyROI = null; // if roi accessor is used, roi position is calculated if (yposRoi != null && roi != null) { posyROI = yposRoi[j]; } // cycle on the x values for (int i = 0; i < dwidth; i++) { // x position selection int posx = xpos[i]; // fractional values selection Number[] fracValues = { xfracvalues[i], yfracvalues[j] }; if (interpBN != null) { // Bicubic/Bicubic2 interpolation(must be set at the interpolator creation) s = interpBN.interpolate(src, k, dnumBands, posx, posy, fracValues, posyROI, roi, roiIter, false); } else if (interpB != null) { // Bilinear interpolation s = interpB.interpolate(src, k, dnumBands, posx, posy, fracValues, posyROI, roi, roiIter, false); } else if (interpN != null) { // Nearest-Neighbor interpolation s = interpN.interpolate(src, k, dnumBands, posx, posy, posyROI, roi, roiIter, false); } else if (interpolator != null) { // GENERAL CASE WITH INTERPOLATORS DIFFERENT FROM THE ABOVE ONES int start = interp_left * srcPixelStride + interp_top * srcScanlineStride; start = posx + posy - start; int countH = 0, countV = 0; // loop on all the kernel pixels for saving the pixel values for (int yloop = 0; yloop < interp_height; yloop++) { int startY = start; for (int xloop = 0; xloop < interp_width; xloop++) { switch (dataType) { case DataBuffer.TYPE_BYTE: samples[countV][countH++] = srcDataByte[start] & 0xff; break; case DataBuffer.TYPE_USHORT: samples[countV][countH++] = srcDataUshort[start] & 0xffff; break; case DataBuffer.TYPE_SHORT: samples[countV][countH++] = srcDataShort[start]; break; case DataBuffer.TYPE_INT: samples[countV][countH++] = srcDataInt[start]; break; case DataBuffer.TYPE_FLOAT: samplesf[countV][countH++] = srcDataFloat[start]; break; case DataBuffer.TYPE_DOUBLE: samplesd[countV][countH++] = srcDataDouble[start]; break; default: break; } start += srcPixelStride; } countV++; countH = 0; start = startY + srcScanlineStride; } // Perform the interpolation switch (dataType) { case DataBuffer.TYPE_BYTE: case DataBuffer.TYPE_USHORT: case DataBuffer.TYPE_SHORT: case DataBuffer.TYPE_INT: s = interp.interpolate(samples, fracValues[0].intValue(), fracValues[1].intValue()); break; case DataBuffer.TYPE_FLOAT: s = interp.interpolate(samplesf, fracValues[0].floatValue(), fracValues[1].floatValue()); break; case DataBuffer.TYPE_DOUBLE: s = interp.interpolate(samplesd, fracValues[0].floatValue(), fracValues[1].floatValue()); break; default: break; } } else { throw new UnsupportedOperationException( "Scale operation cannot be performed without an interpolator"); } // The interpolated value is saved in the destination array switch (dataType) { case DataBuffer.TYPE_BYTE: dstDataByte[dstPixelOffset] = (byte) (s.byteValue() & 0xff); break; case DataBuffer.TYPE_USHORT: dstDataUshort[dstPixelOffset] = (short) (s.shortValue() & 0xffff); break; case DataBuffer.TYPE_SHORT: dstDataShort[dstPixelOffset] = s.shortValue(); break; case DataBuffer.TYPE_INT: dstDataInt[dstPixelOffset] = s.intValue(); break; case DataBuffer.TYPE_FLOAT: dstDataFloat[dstPixelOffset] = s.floatValue(); break; case DataBuffer.TYPE_DOUBLE: dstDataDouble[dstPixelOffset] = s.doubleValue(); break; default: break; } // destination pixel offset update dstPixelOffset += dstPixelStride; } // destination line offset update dstlineOffset += dstScanlineStride; } } } private void computeLoopBynary(RasterAccessor src, Raster source, WritableRaster dest, Rectangle destRect, int xvalues[], int yvalues[], int yvaluesROI[],Number[] xfracvalues, Number[] yfracvalues, Raster roi, int[] posYROI,int srcRectX,int srcRectY, RandomIter roiIter) { int dx = destRect.x; int dy = destRect.y; int dwidth = destRect.width; int dheight = destRect.height; MultiPixelPackedSampleModel sourceSM = (MultiPixelPackedSampleModel) source .getSampleModel(); int sourceTransX = source.getSampleModelTranslateX(); int sourceTransY = source.getSampleModelTranslateY(); int sourceDataBitOffset = sourceSM.getDataBitOffset(); int sourceScanlineStride = sourceSM.getScanlineStride(); int sourcePixelStride = sourceSM.getPixelBitStride(); MultiPixelPackedSampleModel roiSM=null; //int roiTransX =0; int roiTransY =0; //int roiDataBitOffset =0; int roiScanlineStride =0; DataBuffer roiDB =null; if(roi!=null){ roiSM = (MultiPixelPackedSampleModel) roi.getSampleModel(); //roiTransX = roi.getSampleModelTranslateX(); roiTransY = roi.getSampleModelTranslateY(); //roiDataBitOffset = roiSM.getDataBitOffset(); roiScanlineStride = roiSM.getScanlineStride(); roiDB = roi.getDataBuffer(); } MultiPixelPackedSampleModel destSM = (MultiPixelPackedSampleModel) dest.getSampleModel(); int destTransX = dest.getSampleModelTranslateX(); int destTransY = dest.getSampleModelTranslateY(); int destDataBitOffset = destSM.getDataBitOffset(); int destScanlineStride = destSM.getScanlineStride(); int[] sIntShortBytenum = new int[dwidth]; int[] sshift = new int[dwidth]; Number[] destData = null; Number[] sourceData = null; DataBuffer destDB = dest.getDataBuffer(); DataBuffer sourceDB = source.getDataBuffer(); byte[] sourceDataB = null; byte[] destDataB = null; short[] sourceDataS = null; short[] destDataS = null; int[] sourceDataI = null; int[] destDataI = null; int[] roiData = null; int bitshift = 0; int bitNum = 0; dataType=destSM.getDataType(); switch (dataType) { case DataBuffer.TYPE_BYTE: DataBufferByte destDBByte = (DataBufferByte) destDB; DataBufferByte sourceDBByte = (DataBufferByte) sourceDB; sourceDataB = sourceDBByte.getData(); destDataB = destDBByte.getData(); destData = new Number[destDataB.length]; for (int ii = 0; ii < destDataB.length; ii++) { destData[ii] = destDataB[ii]; } sourceData = new Number[sourceDataB.length]; for (int ii = 0; ii < sourceDataB.length; ii++) { sourceData[ii] = sourceDataB[ii]; } bitshift = 3; bitNum = 7; break; case DataBuffer.TYPE_USHORT: case DataBuffer.TYPE_SHORT: DataBufferUShort destDBShort = (DataBufferUShort) destDB; DataBufferUShort sourceDBShort = (DataBufferUShort) sourceDB; sourceDataS = sourceDBShort.getData(); destDataS = destDBShort.getData(); destData = new Number[destDataS.length]; for (int ii = 0; ii < destDataS.length; ii++) { destData[ii] = destDataS[ii]; } sourceData = new Number[sourceDataS.length]; for (int ii = 0; ii < sourceDataS.length; ii++) { sourceData[ii] = sourceDataS[ii]; } bitshift = 4; bitNum = 15; break; case DataBuffer.TYPE_INT: DataBufferInt destDBInt = (DataBufferInt) destDB; DataBufferInt sourceDBInt = (DataBufferInt) sourceDB; sourceDataI = sourceDBInt.getData(); destDataI = destDBInt.getData(); destData = new Number[destDataI.length]; for (int ii = 0; ii < destDataI.length; ii++) { destData[ii] = destDataI[ii]; } sourceData = new Number[sourceDataI.length]; for (int ii = 0; ii < sourceDataI.length; ii++) { sourceData[ii] = sourceDataI[ii]; } bitshift = 5; bitNum = 31; break; } if(roi!=null){ DataBufferByte roiDBByte=(DataBufferByte)roiDB; byte[] roiDataB=roiDBByte.getData(); roiData = new int[roiDataB.length]; for (int ii = 0; ii < roiDataB.length; ii++) { roiData[ii] = roiDataB[ii]; } } int sourceDBOffset = sourceDB.getOffset(); int roiDBOffset=0; int destDBOffset = destDB.getOffset(); if(roi!=null){ roiDBOffset= roiDB.getOffset(); } for (int i = 0; i < dwidth; i++) { int x = xvalues[i]; int sbitnum = sourceDataBitOffset + (x - sourceTransX); sIntShortBytenum[i] = sbitnum >> bitshift; sshift[i] = bitNum - (sbitnum & bitNum); } int sourceYOffset; int s; int x, y; int yfrac, xfrac; int xNextBitNo; int destYOffset = (dy - destTransY) * destScanlineStride + destDBOffset; int dbitnum = destDataBitOffset + (dx - destTransX); int destByteShortIntNum; int destBitShift; int[] coordinates = new int[2]; for (int j = 0; j < dheight; j++) { y = yvalues[j]; yfrac = yfracvalues[j].intValue(); sourceYOffset = (y - sourceTransY) * sourceScanlineStride + sourceDBOffset; dbitnum = destDataBitOffset + (dx - destTransX); int yROI =0; int roiYOffset = 0; if(roi!=null){ yROI = posYROI[j]; roiYOffset = (yROI - roiTransY) * roiScanlineStride + roiDBOffset; } for (int i = 0; i < dwidth; i++) { xfrac = xfracvalues[i].intValue(); x = xvalues[i]; coordinates[0] = src.getX() + (x-srcRectX)*sourcePixelStride; coordinates[1] = src.getY() + ((y-srcRectY)*sourceScanlineStride) / sourceScanlineStride; xNextBitNo = sourceDataBitOffset + (x + 1 - sourceTransX); if(interpN !=null){ s = interpN.interpolateBinary(xNextBitNo,sourceData,sourceYOffset, sourceScanlineStride, coordinates,roiData, roiYOffset, roiScanlineStride, roiIter); }else if (interpB != null) { s = interpB.interpolateBinary(xNextBitNo, sourceData, xfrac, yfrac, sourceYOffset, sourceScanlineStride, coordinates,roiData, roiYOffset, roiScanlineStride, roiIter); } else if (interpBN != null) { s = interpBN.interpolateBinary(xNextBitNo, sourceData, xfrac, yfrac, sourceYOffset, sourceScanlineStride, coordinates, roiData, roiYOffset, roiScanlineStride, roiIter); } else { throw new UnsupportedOperationException( "Binary interpolation not supported by interpolator different from" + "the ones that belong to InterpolationNearest2, InterpolationBilinear2 or InterpolationBicubic" + "class."); } destByteShortIntNum = dbitnum >> bitshift; destBitShift = bitNum - (dbitnum & bitNum); if (s == 1) { switch (dataType) { case DataBuffer.TYPE_BYTE: destDataB[destYOffset + destByteShortIntNum] |= (0x01 << destBitShift); break; case DataBuffer.TYPE_USHORT: case DataBuffer.TYPE_SHORT: destDataS[destYOffset + destByteShortIntNum] |= (0x01 << destBitShift); break; case DataBuffer.TYPE_INT: destDataI[destYOffset + destByteShortIntNum] |= (0x01 << destBitShift); break; } } else { switch (dataType) { case DataBuffer.TYPE_BYTE: destDataB[destYOffset + destByteShortIntNum] &= (0xff - (0x01 << destBitShift)); break; case DataBuffer.TYPE_USHORT: case DataBuffer.TYPE_SHORT: destDataS[destYOffset + destByteShortIntNum] &= (0xffff - (0x01 << destBitShift)); break; case DataBuffer.TYPE_INT: destDataI[destYOffset + destByteShortIntNum] &= (0xffffffff - (0x01 << destBitShift)); break; } } dbitnum++; } destYOffset += destScanlineStride; } } // } }