/*
* $RCSfile: AffineNearestOpImage.java,v $
*
* Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
*
* Use is subject to license terms.
*
* $Revision: 1.2 $
* $Date: 2005/12/20 22:05:47 $
* $State: Exp $
*/
package com.lightcrafts.media.jai.opimage;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.image.ColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.IndexColorModel;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.awt.image.WritableRaster;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import com.lightcrafts.mediax.jai.ImageLayout;
import com.lightcrafts.mediax.jai.Interpolation;
import com.lightcrafts.mediax.jai.RasterAccessor;
import com.lightcrafts.mediax.jai.RasterFormatTag;
import com.lightcrafts.mediax.jai.util.Range;
import java.util.Map;
import com.lightcrafts.mediax.jai.BorderExtender;
/**
* An OpImage subclass that performs nearest-neighbour Affine mapping
*/
class AffineNearestOpImage extends AffineOpImage {
/**
* Constructs an AffineNearestOpImage from a RenderedImage source,
*
* @param source a RenderedImage.
* @param layout an ImageLayout optionally containing the tile grid layout,
* SampleModel, and ColorModel, or null.
* @param interp an Interpolation object to use for resampling
* @param transform the desired AffineTransform.
*/
public AffineNearestOpImage(RenderedImage source,
BorderExtender extender,
Map config,
ImageLayout layout,
AffineTransform transform,
Interpolation interp,
double[] backgroundValues) {
super(source,
extender,
config,
layout,
transform,
interp,
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) {
sampleModel = source.getSampleModel().createCompatibleSampleModel(
tileWidth, tileHeight);
colorModel = srcColorModel;
}
}
// Scanline clipping stuff
/**
* Sets clipMinX, clipMaxX based on s_ix, s_iy, ifracx, ifracy,
* dst_min_x, and dst_min_y. Padding factors are added and
* subtracted from the source bounds as given by
* src_rect_{x,y}{1,2}. For example, for nearest-neighbor interpo
* the padding factors should be set to (0, 0, 0, 0); for
* bilinear, (0, 1, 0, 1); and for bicubic, (1, 2, 1, 2).
*
* <p> The returned Range object will be for the Integer class and
* will contain extrema equivalent to clipMinX and clipMaxX.
*/
protected Range performScanlineClipping(float src_rect_x1,
float src_rect_y1,
float src_rect_x2,
float src_rect_y2,
int s_ix, int s_iy,
int ifracx, int ifracy,
int dst_min_x, int dst_max_x,
int lpad, int rpad,
int tpad, int bpad) {
int clipMinX = dst_min_x;
int clipMaxX = dst_max_x;
long xdenom = incx*geom_frac_max + ifracdx;
if (xdenom != 0) {
long clipx1 = (long)src_rect_x1 + lpad;
long clipx2 = (long)src_rect_x2 - rpad;
long x1 = ((clipx1 - s_ix)*geom_frac_max - ifracx) +
dst_min_x*xdenom;
long x2 = ((clipx2 - s_ix)*geom_frac_max - ifracx) +
dst_min_x*xdenom;
// Moving backwards, switch roles of left and right edges
if (xdenom < 0) {
long tmp = x1;
x1 = x2;
x2 = tmp;
}
int dx1 = ceilRatio(x1, xdenom);
clipMinX = Math.max(clipMinX, dx1);
int dx2 = floorRatio(x2, xdenom) + 1;
clipMaxX = Math.min(clipMaxX, dx2);
} else {
// xdenom == 0, all points have same x coordinate as the first
if (s_ix < src_rect_x1 || s_ix >= src_rect_x2) {
clipMinX = clipMaxX = dst_min_x;
return new Range(Integer.class,
new Integer(clipMinX),
new Integer(clipMaxX));
}
}
long ydenom = incy*geom_frac_max + ifracdy;
if (ydenom != 0) {
long clipy1 = (long)src_rect_y1 + tpad;
long clipy2 = (long)src_rect_y2 - bpad;
long y1 = ((clipy1 - s_iy)*geom_frac_max - ifracy) +
dst_min_x*ydenom;
long y2 = ((clipy2 - s_iy)*geom_frac_max - ifracy) +
dst_min_x*ydenom;
// Moving backwards, switch roles of top and bottom edges
if (ydenom < 0) {
long tmp = y1;
y1 = y2;
y2 = tmp;
}
int dx1 = ceilRatio(y1, ydenom);
clipMinX = Math.max(clipMinX, dx1);
int dx2 = floorRatio(y2, ydenom) + 1;
clipMaxX = Math.min(clipMaxX, dx2);
} else {
// ydenom == 0, all points have same y coordinate as the first
if (s_iy < src_rect_y1 || s_iy >= src_rect_y2) {
clipMinX = clipMaxX = dst_min_x;
}
}
if (clipMinX > dst_max_x)
clipMinX = dst_max_x;
if (clipMaxX < dst_min_x)
clipMaxX = dst_min_x;
return new Range(Integer.class,
new Integer(clipMinX),
new Integer(clipMaxX));
}
/**
* Sets s_ix, s_iy, ifracx, ifracy to their values at x == clipMinX
* from their initial values at x == dst_min_x.
*
* <p> The return Point array will contain the updated values of s_ix
* and s_iy in the first element and those of ifracx and ifracy in the
* second element.
*/
protected Point[] advanceToStartOfScanline(int dst_min_x, int clipMinX,
int s_ix, int s_iy,
int ifracx, int ifracy) {
// Skip output up to clipMinX
long skip = clipMinX - dst_min_x;
long dx =
((long)ifracx + skip*ifracdx)/geom_frac_max;
long dy =
((long)ifracy + skip*ifracdy)/geom_frac_max;
s_ix += skip*incx + (int)dx;
s_iy += skip*incy + (int)dy;
long lfracx = ifracx + skip*ifracdx;
if (lfracx >= 0) {
ifracx = (int)(lfracx % geom_frac_max);
} else {
ifracx = (int)(-(-lfracx % geom_frac_max));
}
long lfracy = ifracy + skip*ifracdy;
if (lfracy >= 0) {
ifracy = (int)(lfracy % geom_frac_max);
} else {
ifracy = (int)(-(-lfracy % geom_frac_max));
}
return new Point[] {new Point(s_ix, s_iy), new Point(ifracx, ifracy)};
}
// computeRect() and data type-specific loop methods.
/**
* Performs an affine transform on a specified rectangle. The sources are
* cobbled.
*
* @param sources an array of source Rasters, guaranteed to provide all
* necessary source data for computing the output.
* @param dest a WritableRaster tile containing the area to be computed.
* @param destRect the rectangle within dest to be processed.
*/
protected void computeRect(Raster [] sources,
WritableRaster dest,
Rectangle destRect) {
// Retrieve format tags.
RasterFormatTag[] formatTags = getFormatTags();
Raster source = sources[0];
Rectangle srcRect = source.getBounds();
int srcRectX = srcRect.x;
int srcRectY = srcRect.y;
//
// Get data for the source rectangle & the destination rectangle
//
RasterAccessor srcAccessor =
new RasterAccessor(source,
srcRect,
formatTags[0],
getSourceImage(0).getColorModel());
RasterAccessor dstAccessor =
new RasterAccessor(dest,
destRect,
formatTags[1],
getColorModel());
switch (dstAccessor.getDataType()) {
case DataBuffer.TYPE_BYTE:
int dstNumBands = dstAccessor.getNumBands();
if (dstNumBands == 1) {
byteLoop_1band(srcAccessor,
destRect,
srcRectX,
srcRectY,
dstAccessor);
} else if (dstNumBands == 3) {
byteLoop_3band(srcAccessor,
destRect,
srcRectX,
srcRectY,
dstAccessor);
} else {
byteLoop(srcAccessor,
destRect,
srcRectX,
srcRectY,
dstAccessor);
}
break;
case DataBuffer.TYPE_INT:
intLoop(srcAccessor,
destRect,
srcRectX,
srcRectY,
dstAccessor);
break;
case DataBuffer.TYPE_SHORT:
case DataBuffer.TYPE_USHORT:
shortLoop(srcAccessor,
destRect,
srcRectX,
srcRectY,
dstAccessor);
break;
case DataBuffer.TYPE_FLOAT:
floatLoop(srcAccessor,
destRect,
srcRectX,
srcRectY,
dstAccessor);
break;
case DataBuffer.TYPE_DOUBLE:
doubleLoop(srcAccessor,
destRect,
srcRectX,
srcRectY,
dstAccessor);
break;
}
//
// If the RasterAccessor object set up a temporary buffer for the
// op to write to, tell the RasterAccessor to write that data
// to the raster, that we're done with it.
//
if (dstAccessor.isDataCopy()) {
dstAccessor.clampDataArrays();
dstAccessor.copyDataToRaster();
}
}
private void byteLoop(RasterAccessor src,
Rectangle destRect,
int srcRectX,
int srcRectY,
RasterAccessor dst) {
float src_rect_x1 = src.getX();
float src_rect_y1 = src.getY();
float src_rect_x2 = src_rect_x1 + src.getWidth();
float src_rect_y2 = src_rect_y1 + src.getHeight();
float s_x, s_y;
int src_x, src_y, src_pos;
double fracx, fracy;
int dstPixelOffset;
int dstOffset = 0;
Point2D dst_pt = new Point2D.Float();
Point2D src_pt = new Point2D.Float();
int dwidth = dst.getWidth();
int dheight = dst.getHeight();
byte dstDataArrays[][] = dst.getByteDataArrays();
int dstBandOffsets[] = dst.getBandOffsets();
int dstPixelStride = dst.getPixelStride();
int dstScanlineStride = dst.getScanlineStride();
byte srcDataArrays[][] = src.getByteDataArrays();
int bandOffsets[] = src.getBandOffsets();
int srcPixelStride = src.getPixelStride();
int srcScanlineStride = src.getScanlineStride();
int dst_num_bands = dst.getNumBands();
int dst_min_x = destRect.x;
int dst_min_y = destRect.y;
int dst_max_x = destRect.x + destRect.width;
int dst_max_y = destRect.y + destRect.height;
int incxStride = incx*srcPixelStride;
int incx1Stride = incx1*srcPixelStride;
int incyStride = incy*srcScanlineStride;
int incy1Stride = incy1*srcScanlineStride;
byte[] backgroundByte = new byte[dst_num_bands];
for (int i = 0; i < dst_num_bands; i++)
backgroundByte[i] = (byte)backgroundValues[i];
for (int y = dst_min_y; y < dst_max_y; y++) {
dstPixelOffset = dstOffset;
// Backward map the first point in the line
// The energy is at the (pt_x + 0.5, pt_y + 0.5)
dst_pt.setLocation((double)dst_min_x + 0.5,
(double)y + 0.5);
mapDestPoint(dst_pt, src_pt);
// Get the mapped source coordinates
s_x = (float)src_pt.getX();
s_y = (float)src_pt.getY();
// Floor to get the integral coordinate
int s_ix = (int) Math.floor(s_x);
int s_iy = (int) Math.floor(s_y);
fracx = s_x - (double)s_ix;
fracy = s_y - (double)s_iy;
int ifracx = (int) Math.floor(fracx * geom_frac_max);
int ifracy = (int) Math.floor(fracy * geom_frac_max);
// Compute clipMinX, clipMinY
Range clipRange =
performScanlineClipping(src_rect_x1, src_rect_y1,
// Last point in the source is
// x2 = x1 + width - 1
// y2 = y1 + height - 1
src_rect_x2 - 1, src_rect_y2 - 1,
s_ix, s_iy,
ifracx, ifracy,
dst_min_x, dst_max_x,
0, 0, 0, 0);
int clipMinX = ((Integer)clipRange.getMinValue()).intValue();
int clipMaxX = ((Integer)clipRange.getMaxValue()).intValue();
// Advance s_ix, s_iy, ifracx, ifracy
Point[] startPts = advanceToStartOfScanline(dst_min_x, clipMinX,
s_ix, s_iy,
ifracx, ifracy);
s_ix = startPts[0].x;
s_iy = startPts[0].y;
ifracx = startPts[1].x;
ifracy = startPts[1].y;
// Translate to/from SampleModel space & Raster space
src_pos = (s_iy - srcRectY)*srcScanlineStride +
(s_ix - srcRectX)*srcPixelStride;
if (setBackground) {
for (int x = dst_min_x; x < clipMinX; x++) {
for (int k2=0; k2 < dst_num_bands; k2++)
dstDataArrays[k2]
[dstPixelOffset+dstBandOffsets[k2]] =
backgroundByte[k2];
dstPixelOffset += dstPixelStride;
}
} else // Advance to first pixel
dstPixelOffset += (clipMinX - dst_min_x)*dstPixelStride;
for (int x = clipMinX; x < clipMaxX; x++) {
for (int k2=0; k2 < dst_num_bands; k2++) {
dstDataArrays[k2]
[dstPixelOffset+dstBandOffsets[k2]] =
srcDataArrays[k2][src_pos + bandOffsets[k2]];
}
// walk
if (ifracx < ifracdx1) {
/*
// DEBUG
s_ix += incx;
*/
src_pos += incxStride;
ifracx += ifracdx;
} else {
/*
// DEBUG
s_ix += incx1;
*/
src_pos += incx1Stride;
ifracx -= ifracdx1;
}
if (ifracy < ifracdy1) {
/*
// DEBUG
s_iy += incy;
*/
src_pos += incyStride;
ifracy += ifracdy;
} else {
/*
// DEBUG
s_iy += incy1;
*/
src_pos += incy1Stride;
ifracy -= ifracdy1;
}
// Go to next pixel
dstPixelOffset += dstPixelStride;
}
if (setBackground && clipMinX <= clipMaxX) {
for (int x = clipMaxX; x < dst_max_x ; x++) {
for (int k2=0; k2 < dst_num_bands; k2++)
dstDataArrays[k2]
[dstPixelOffset+dstBandOffsets[k2]] =
backgroundByte[k2];
dstPixelOffset += dstPixelStride;
}
}
// Go to the next line in the destination rectangle
dstOffset += dstScanlineStride;
}
}
private void byteLoop_1band(RasterAccessor src,
Rectangle destRect,
int srcRectX,
int srcRectY,
RasterAccessor dst) {
float src_rect_x1 = src.getX();
float src_rect_y1 = src.getY();
float src_rect_x2 = src_rect_x1 + src.getWidth();
float src_rect_y2 = src_rect_y1 + src.getHeight();
float s_x, s_y;
int src_x, src_y, src_pos;
double fracx, fracy;
int dstPixelOffset;
int dstOffset = 0;
Point2D dst_pt = new Point2D.Float();
Point2D src_pt = new Point2D.Float();
int dwidth = dst.getWidth();
int dheight = dst.getHeight();
byte dstDataArrays[][] = dst.getByteDataArrays();
int dstBandOffsets[] = dst.getBandOffsets();
int dstPixelStride = dst.getPixelStride();
int dstScanlineStride = dst.getScanlineStride();
byte[] dstDataArray0 = dstDataArrays[0];
int dstBandOffset0 = dstBandOffsets[0];
byte srcDataArrays[][] = src.getByteDataArrays();
int bandOffsets[] = src.getBandOffsets();
int srcPixelStride = src.getPixelStride();
int srcScanlineStride = src.getScanlineStride();
byte[] srcDataArray0 = srcDataArrays[0];
int bandOffsets0 = bandOffsets[0];
int dst_min_x = destRect.x;
int dst_min_y = destRect.y;
int dst_max_x = destRect.x + destRect.width;
int dst_max_y = destRect.y + destRect.height;
int incxStride = incx*srcPixelStride;
int incx1Stride = incx1*srcPixelStride;
int incyStride = incy*srcScanlineStride;
int incy1Stride = incy1*srcScanlineStride;
byte backgroundByte = (byte)backgroundValues[0];
for (int y = dst_min_y; y < dst_max_y; y++) {
dstPixelOffset = dstOffset;
// Backward map the first point in the line
// The energy is at the (pt_x + 0.5, pt_y + 0.5)
dst_pt.setLocation((double)dst_min_x + 0.5,
(double)y + 0.5);
mapDestPoint(dst_pt, src_pt);
// Get the mapped source coordinates
s_x = (float)src_pt.getX();
s_y = (float)src_pt.getY();
// Floor to get the integral coordinate
int s_ix = (int) Math.floor(s_x);
int s_iy = (int) Math.floor(s_y);
fracx = s_x - (double)s_ix;
fracy = s_y - (double)s_iy;
int ifracx = (int) Math.floor(fracx * geom_frac_max);
int ifracy = (int) Math.floor(fracy * geom_frac_max);
// Compute clipMinX, clipMinY
Range clipRange =
performScanlineClipping(src_rect_x1, src_rect_y1,
// Last point in the source is
// x2 = x1 + width - 1
// y2 = y1 + height - 1
src_rect_x2 - 1, src_rect_y2 - 1,
s_ix, s_iy,
ifracx, ifracy,
dst_min_x, dst_max_x,
0, 0, 0, 0);
int clipMinX = ((Integer)clipRange.getMinValue()).intValue();
int clipMaxX = ((Integer)clipRange.getMaxValue()).intValue();
// Advance s_ix, s_iy, ifracx, ifracy
Point[] startPts = advanceToStartOfScanline(dst_min_x, clipMinX,
s_ix, s_iy,
ifracx, ifracy);
s_ix = startPts[0].x;
s_iy = startPts[0].y;
ifracx = startPts[1].x;
ifracy = startPts[1].y;
// Translate to/from SampleModel space & Raster space
src_pos = (s_iy - srcRectY)*srcScanlineStride +
(s_ix - srcRectX)*srcPixelStride;
if (setBackground) {
for (int x = dst_min_x; x < clipMinX; x++) {
dstDataArray0[dstPixelOffset + dstBandOffset0] =
backgroundByte;
dstPixelOffset += dstPixelStride;
}
} else // Advance to first pixel
dstPixelOffset += (clipMinX - dst_min_x)*dstPixelStride;
for (int x = clipMinX; x < clipMaxX; x++) {
dstDataArray0[dstPixelOffset + dstBandOffset0] =
srcDataArray0[src_pos + bandOffsets0];
// walk
if (ifracx < ifracdx1) {
/*
// DEBUG
s_ix += incx;
*/
src_pos += incxStride;
ifracx += ifracdx;
} else {
/*
// DEBUG
s_ix += incx1;
*/
src_pos += incx1Stride;
ifracx -= ifracdx1;
}
if (ifracy < ifracdy1) {
/*
// DEBUG
s_iy += incy;
*/
src_pos += incyStride;
ifracy += ifracdy;
} else {
/*
// DEBUG
s_iy += incy1;
*/
src_pos += incy1Stride;
ifracy -= ifracdy1;
}
// Go to next pixel
dstPixelOffset += dstPixelStride;
}
if (setBackground && clipMinX <= clipMaxX) {
for (int x = clipMaxX; x < dst_max_x; x++) {
dstDataArray0[dstPixelOffset + dstBandOffset0] =
backgroundByte;
dstPixelOffset += dstPixelStride;
}
}
// Go to the next line in the destination rectangle
dstOffset += dstScanlineStride;
}
}
private void byteLoop_3band(RasterAccessor src,
Rectangle destRect,
int srcRectX,
int srcRectY,
RasterAccessor dst) {
float src_rect_x1 = src.getX();
float src_rect_y1 = src.getY();
float src_rect_x2 = src_rect_x1 + src.getWidth();
float src_rect_y2 = src_rect_y1 + src.getHeight();
float s_x, s_y;
int src_x, src_y, src_pos;
double fracx, fracy;
int dstPixelOffset;
int dstOffset = 0;
Point2D dst_pt = new Point2D.Float();
Point2D src_pt = new Point2D.Float();
int dwidth = dst.getWidth();
int dheight = dst.getHeight();
byte dstDataArrays[][] = dst.getByteDataArrays();
int dstBandOffsets[] = dst.getBandOffsets();
int dstPixelStride = dst.getPixelStride();
int dstScanlineStride = dst.getScanlineStride();
byte[] dstDataArray0 = dstDataArrays[0];
byte[] dstDataArray1 = dstDataArrays[1];
byte[] dstDataArray2 = dstDataArrays[2];
int dstBandOffset0 = dstBandOffsets[0];
int dstBandOffset1 = dstBandOffsets[1];
int dstBandOffset2 = dstBandOffsets[2];
byte srcDataArrays[][] = src.getByteDataArrays();
int bandOffsets[] = src.getBandOffsets();
int srcPixelStride = src.getPixelStride();
int srcScanlineStride = src.getScanlineStride();
byte[] srcDataArray0 = srcDataArrays[0];
byte[] srcDataArray1 = srcDataArrays[1];
byte[] srcDataArray2 = srcDataArrays[2];
int bandOffsets0 = bandOffsets[0];
int bandOffsets1 = bandOffsets[1];
int bandOffsets2 = bandOffsets[2];
int dst_min_x = destRect.x;
int dst_min_y = destRect.y;
int dst_max_x = destRect.x + destRect.width;
int dst_max_y = destRect.y + destRect.height;
int incxStride = incx*srcPixelStride;
int incx1Stride = incx1*srcPixelStride;
int incyStride = incy*srcScanlineStride;
int incy1Stride = incy1*srcScanlineStride;
byte background0 = (byte)backgroundValues[0];
byte background1 = (byte)backgroundValues[1];
byte background2 = (byte)backgroundValues[2];
for (int y = dst_min_y; y < dst_max_y; y++) {
dstPixelOffset = dstOffset;
// Backward map the first point in the line
// The energy is at the (pt_x + 0.5, pt_y + 0.5)
dst_pt.setLocation((double)dst_min_x + 0.5,
(double)y + 0.5);
mapDestPoint(dst_pt, src_pt);
// Get the mapped source coordinates
s_x = (float)src_pt.getX();
s_y = (float)src_pt.getY();
// Floor to get the integral coordinate
int s_ix = (int) Math.floor(s_x);
int s_iy = (int) Math.floor(s_y);
fracx = s_x - (double)s_ix;
fracy = s_y - (double)s_iy;
int ifracx = (int) Math.floor(fracx * geom_frac_max);
int ifracy = (int) Math.floor(fracy * geom_frac_max);
// Compute clipMinX, clipMinY
Range clipRange =
performScanlineClipping(src_rect_x1, src_rect_y1,
// Last point in the source is
// x2 = x1 + width - 1
// y2 = y1 + height - 1
src_rect_x2 - 1, src_rect_y2 - 1,
s_ix, s_iy,
ifracx, ifracy,
dst_min_x, dst_max_x,
0, 0, 0, 0);
int clipMinX = ((Integer)clipRange.getMinValue()).intValue();
int clipMaxX = ((Integer)clipRange.getMaxValue()).intValue();
// Advance s_ix, s_iy, ifracx, ifracy
Point[] startPts = advanceToStartOfScanline(dst_min_x, clipMinX,
s_ix, s_iy,
ifracx, ifracy);
s_ix = startPts[0].x;
s_iy = startPts[0].y;
ifracx = startPts[1].x;
ifracy = startPts[1].y;
// Translate to/from SampleModel space & Raster space
src_pos = (s_iy - srcRectY)*srcScanlineStride +
(s_ix - srcRectX)*srcPixelStride;
if (setBackground) {
for (int x = dst_min_x; x < clipMinX; x++) {
dstDataArray0[dstPixelOffset + dstBandOffset0] =
background0;
dstDataArray1[dstPixelOffset + dstBandOffset1] =
background1;
dstDataArray2[dstPixelOffset + dstBandOffset2] =
background2;
dstPixelOffset += dstPixelStride;
}
} else // Advance to first pixel
dstPixelOffset += (clipMinX - dst_min_x)*dstPixelStride;
for (int x = clipMinX; x < clipMaxX; x++) {
dstDataArray0[dstPixelOffset + dstBandOffset0] =
srcDataArray0[src_pos + bandOffsets0];
dstDataArray1[dstPixelOffset + dstBandOffset1] =
srcDataArray1[src_pos + bandOffsets1];
dstDataArray2[dstPixelOffset + dstBandOffset2] =
srcDataArray2[src_pos + bandOffsets2];
// walk
if (ifracx < ifracdx1) {
/*
// DEBUG
s_ix += incx;
*/
src_pos += incxStride;
ifracx += ifracdx;
} else {
/*
// DEBUG
s_ix += incx1;
*/
src_pos += incx1Stride;
ifracx -= ifracdx1;
}
if (ifracy < ifracdy1) {
/*
// DEBUG
s_iy += incy;
*/
src_pos += incyStride;
ifracy += ifracdy;
} else {
/*
// DEBUG
s_iy += incy1;
*/
src_pos += incy1Stride;
ifracy -= ifracdy1;
}
// Go to next pixel
dstPixelOffset += dstPixelStride;
}
if (setBackground && clipMinX <= clipMaxX) {
for (int x = clipMaxX; x < dst_max_x; x++) {
dstDataArray0[dstPixelOffset + dstBandOffset0] =
background0;
dstDataArray1[dstPixelOffset + dstBandOffset1] =
background1;
dstDataArray2[dstPixelOffset + dstBandOffset2] =
background2;
dstPixelOffset += dstPixelStride;
}
}
// Go to the next line in the destination rectangle
dstOffset += dstScanlineStride;
}
}
private void intLoop(RasterAccessor src,
Rectangle destRect,
int srcRectX,
int srcRectY,
RasterAccessor dst) {
float src_rect_x1 = src.getX();
float src_rect_y1 = src.getY();
float src_rect_x2 = src_rect_x1 + src.getWidth();
float src_rect_y2 = src_rect_y1 + src.getHeight();
float s_x, s_y;
int src_x, src_y, src_pos;
double fracx, fracy;
int dstPixelOffset;
int dstOffset = 0;
Point2D dst_pt = new Point2D.Float();
Point2D src_pt = new Point2D.Float();
int dwidth = dst.getWidth();
int dheight = dst.getHeight();
int dstDataArrays[][] = dst.getIntDataArrays();
int dstBandOffsets[] = dst.getBandOffsets();
int dstPixelStride = dst.getPixelStride();
int dstScanlineStride = dst.getScanlineStride();
int srcDataArrays[][] = src.getIntDataArrays();
int bandOffsets[] = src.getBandOffsets();
int srcPixelStride = src.getPixelStride();
int srcScanlineStride = src.getScanlineStride();
int dst_num_bands = dst.getNumBands();
int dst_min_x = destRect.x;
int dst_min_y = destRect.y;
int dst_max_x = destRect.x + destRect.width;
int dst_max_y = destRect.y + destRect.height;
int incxStride = incx*srcPixelStride;
int incx1Stride = incx1*srcPixelStride;
int incyStride = incy*srcScanlineStride;
int incy1Stride = incy1*srcScanlineStride;
int[] backgroundInt = new int[dst_num_bands];
for (int i = 0; i < dst_num_bands; i++)
backgroundInt[i] = (int)backgroundValues[i];
for (int y = dst_min_y; y < dst_max_y; y++) {
dstPixelOffset = dstOffset;
// Backward map the first point in the line
// The energy is at the (pt_x + 0.5, pt_y + 0.5)
dst_pt.setLocation((double)dst_min_x + 0.5,
(double)y + 0.5);
mapDestPoint(dst_pt, src_pt);
// Get the mapped source coordinates
s_x = (float)src_pt.getX();
s_y = (float)src_pt.getY();
// Floor value to get the integral coordinate
int s_ix = (int) Math.floor(s_x);
int s_iy = (int) Math.floor(s_y);
fracx = s_x - (double)s_ix;
fracy = s_y - (double)s_iy;
int ifracx = (int) Math.floor(fracx * geom_frac_max);
int ifracy = (int) Math.floor(fracy * geom_frac_max);
// Compute clipMinX, clipMinY
Range clipRange =
performScanlineClipping(src_rect_x1, src_rect_y1,
// Last point in the source is
// x2 = x1 + width - 1
// y2 = y1 + height - 1
src_rect_x2 - 1, src_rect_y2 - 1,
s_ix, s_iy,
ifracx, ifracy,
dst_min_x, dst_max_x,
0, 0, 0, 0);
int clipMinX = ((Integer)clipRange.getMinValue()).intValue();
int clipMaxX = ((Integer)clipRange.getMaxValue()).intValue();
// Advance s_ix, s_iy, ifracx, ifracy
Point[] startPts = advanceToStartOfScanline(dst_min_x, clipMinX,
s_ix, s_iy,
ifracx, ifracy);
s_ix = startPts[0].x;
s_iy = startPts[0].y;
ifracx = startPts[1].x;
ifracy = startPts[1].y;
// Translate to/from SampleModel space & Raster space
src_pos = (s_iy - srcRectY)*srcScanlineStride +
(s_ix - srcRectX)*srcPixelStride;
if (setBackground) {
for (int x = dst_min_x; x < clipMinX; x++) {
for (int k2=0; k2 < dst_num_bands; k2++)
dstDataArrays[k2]
[dstPixelOffset+dstBandOffsets[k2]] =
backgroundInt[k2];
dstPixelOffset += dstPixelStride;
}
} else // Advance to first pixel
dstPixelOffset += (clipMinX - dst_min_x)*dstPixelStride;
for (int x = clipMinX; x < clipMaxX; x++) {
for (int k2=0; k2 < dst_num_bands; k2++) {
dstDataArrays[k2]
[dstPixelOffset+dstBandOffsets[k2]] =
srcDataArrays[k2][src_pos + bandOffsets[k2]];
}
// walk
if (ifracx < ifracdx1) {
/*
// DEBUG
s_ix += incx;
*/
src_pos += incxStride;
ifracx += ifracdx;
} else {
/*
// DEBUG
s_ix += incx1;
*/
src_pos += incx1Stride;
ifracx -= ifracdx1;
}
if (ifracy < ifracdy1) {
/*
// DEBUG
s_iy += incy;
*/
src_pos += incyStride;
ifracy += ifracdy;
} else {
/*
// DEBUG
s_iy += incy1;
*/
src_pos += incy1Stride;
ifracy -= ifracdy1;
}
dstPixelOffset += dstPixelStride;
}
if (setBackground && clipMinX <= clipMaxX) {
for (int x = clipMaxX; x < dst_max_x ; x++) {
for (int k2=0; k2 < dst_num_bands; k2++)
dstDataArrays[k2]
[dstPixelOffset+dstBandOffsets[k2]] =
backgroundInt[k2];
dstPixelOffset += dstPixelStride;
}
}
dstOffset += dstScanlineStride;
}
}
private void shortLoop(RasterAccessor src,
Rectangle destRect,
int srcRectX,
int srcRectY,
RasterAccessor dst) {
float src_rect_x1 = src.getX();
float src_rect_y1 = src.getY();
float src_rect_x2 = src_rect_x1 + src.getWidth();
float src_rect_y2 = src_rect_y1 + src.getHeight();
float s_x, s_y;
int src_x, src_y, src_pos;
double fracx, fracy;
int dstPixelOffset;
int dstOffset = 0;
Point2D dst_pt = new Point2D.Float();
Point2D src_pt = new Point2D.Float();
int dwidth = dst.getWidth();
int dheight = dst.getHeight();
short dstDataArrays[][] = dst.getShortDataArrays();
int dstBandOffsets[] = dst.getBandOffsets();
int dstPixelStride = dst.getPixelStride();
int dstScanlineStride = dst.getScanlineStride();
short srcDataArrays[][] = src.getShortDataArrays();
int bandOffsets[] = src.getBandOffsets();
int srcPixelStride = src.getPixelStride();
int srcScanlineStride = src.getScanlineStride();
int dst_num_bands = dst.getNumBands();
int dst_min_x = destRect.x;
int dst_min_y = destRect.y;
int dst_max_x = destRect.x + destRect.width;
int dst_max_y = destRect.y + destRect.height;
int incxStride = incx*srcPixelStride;
int incx1Stride = incx1*srcPixelStride;
int incyStride = incy*srcScanlineStride;
int incy1Stride = incy1*srcScanlineStride;
short[] backgroundShort = new short[dst_num_bands];
for (int i = 0; i < dst_num_bands; i++)
backgroundShort[i] = (short)backgroundValues[i];
for (int y = dst_min_y; y < dst_max_y; y++) {
dstPixelOffset = dstOffset;
// Backward map the first point in the line
// The energy is at the (pt_x + 0.5, pt_y + 0.5)
dst_pt.setLocation((double)dst_min_x + 0.5,
(double)y + 0.5);
mapDestPoint(dst_pt, src_pt);
// Get the mapped source coordinates
s_x = (float)src_pt.getX();
s_y = (float)src_pt.getY();
// Floor value to get the integral coordinate
int s_ix = (int) Math.floor(s_x);
int s_iy = (int) Math.floor(s_y);
fracx = s_x - (double)s_ix;
fracy = s_y - (double)s_iy;
int ifracx = (int) Math.floor(fracx * geom_frac_max);
int ifracy = (int) Math.floor(fracy * geom_frac_max);
// Compute clipMinX, clipMinY
Range clipRange =
performScanlineClipping(src_rect_x1, src_rect_y1,
// Last point in the source is
// x2 = x1 + width - 1
// y2 = y1 + height - 1
src_rect_x2 - 1, src_rect_y2 - 1,
s_ix, s_iy,
ifracx, ifracy,
dst_min_x, dst_max_x,
0, 0, 0, 0);
int clipMinX = ((Integer)clipRange.getMinValue()).intValue();
int clipMaxX = ((Integer)clipRange.getMaxValue()).intValue();
// Advance s_ix, s_iy, ifracx, ifracy
Point[] startPts = advanceToStartOfScanline(dst_min_x, clipMinX,
s_ix, s_iy,
ifracx, ifracy);
s_ix = startPts[0].x;
s_iy = startPts[0].y;
ifracx = startPts[1].x;
ifracy = startPts[1].y;
// Translate to/from SampleModel space & Raster space
src_pos = (s_iy - srcRectY)*srcScanlineStride +
(s_ix - srcRectX)*srcPixelStride;
if (setBackground) {
for (int x = dst_min_x; x < clipMinX; x++) {
for (int k2=0; k2 < dst_num_bands; k2++)
dstDataArrays[k2]
[dstPixelOffset+dstBandOffsets[k2]] =
backgroundShort[k2];
dstPixelOffset += dstPixelStride;
}
} else // Advance to first pixel
dstPixelOffset += (clipMinX - dst_min_x)*dstPixelStride;
for (int x = clipMinX; x < clipMaxX; x++) {
for (int k2=0; k2 < dst_num_bands; k2++) {
dstDataArrays[k2]
[dstPixelOffset+dstBandOffsets[k2]] =
srcDataArrays[k2][src_pos + bandOffsets[k2]];
}
// walk
if (ifracx < ifracdx1) {
/*
// DEBUG
s_ix += incx;
*/
src_pos += incxStride;
ifracx += ifracdx;
} else {
/*
// DEBUG
s_ix += incx1;
*/
src_pos += incx1Stride;
ifracx -= ifracdx1;
}
if (ifracy < ifracdy1) {
/*
// DEBUG
s_iy += incy;
*/
src_pos += incyStride;
ifracy += ifracdy;
} else {
/*
// DEBUG
s_iy += incy1;
*/
src_pos += incy1Stride;
ifracy -= ifracdy1;
}
dstPixelOffset += dstPixelStride;
}
if (setBackground && clipMinX <= clipMaxX) {
for (int x = clipMaxX; x < dst_max_x ; x++) {
for (int k2=0; k2 < dst_num_bands; k2++)
dstDataArrays[k2]
[dstPixelOffset+dstBandOffsets[k2]] =
backgroundShort[k2];
dstPixelOffset += dstPixelStride;
}
}
dstOffset += dstScanlineStride;
}
}
private void floatLoop(RasterAccessor src,
Rectangle destRect,
int srcRectX,
int srcRectY,
RasterAccessor dst) {
float src_rect_x1 = src.getX();
float src_rect_y1 = src.getY();
float src_rect_x2 = src_rect_x1 + src.getWidth();
float src_rect_y2 = src_rect_y1 + src.getHeight();
float s_x, s_y;
int src_x, src_y, src_pos;
double fracx, fracy;
int dstPixelOffset;
int dstOffset = 0;
Point2D dst_pt = new Point2D.Float();
Point2D src_pt = new Point2D.Float();
int dwidth = dst.getWidth();
int dheight = dst.getHeight();
float dstDataArrays[][] = dst.getFloatDataArrays();
int dstBandOffsets[] = dst.getBandOffsets();
int dstPixelStride = dst.getPixelStride();
int dstScanlineStride = dst.getScanlineStride();
float srcDataArrays[][] = src.getFloatDataArrays();
int bandOffsets[] = src.getBandOffsets();
int srcPixelStride = src.getPixelStride();
int srcScanlineStride = src.getScanlineStride();
int dst_num_bands = dst.getNumBands();
int dst_min_x = destRect.x;
int dst_min_y = destRect.y;
int dst_max_x = destRect.x + destRect.width;
int dst_max_y = destRect.y + destRect.height;
int incxStride = incx*srcPixelStride;
int incx1Stride = incx1*srcPixelStride;
int incyStride = incy*srcScanlineStride;
int incy1Stride = incy1*srcScanlineStride;
float[] backgroundFloat = new float[dst_num_bands];
for (int i = 0; i < dst_num_bands; i++)
backgroundFloat[i] = (float)backgroundValues[i];
for (int y = dst_min_y; y < dst_max_y; y++) {
dstPixelOffset = dstOffset;
// Backward map the first point in the line
// The energy is at the (pt_x + 0.5, pt_y + 0.5)
dst_pt.setLocation((double)dst_min_x + 0.5,
(double)y + 0.5);
mapDestPoint(dst_pt, src_pt);
// Get the mapped source coordinates
s_x = (float)src_pt.getX();
s_y = (float)src_pt.getY();
// Floor value to get the integral coordinate
int s_ix = (int) Math.floor(s_x);
int s_iy = (int) Math.floor(s_y);
fracx = s_x - (double)s_ix;
fracy = s_y - (double)s_iy;
int ifracx = (int) Math.floor(fracx * geom_frac_max);
int ifracy = (int) Math.floor(fracy * geom_frac_max);
// Compute clipMinX, clipMinY
Range clipRange =
performScanlineClipping(src_rect_x1, src_rect_y1,
// Last point in the source is
// x2 = x1 + width - 1
// y2 = y1 + height - 1
src_rect_x2 - 1, src_rect_y2 - 1,
s_ix, s_iy,
ifracx, ifracy,
dst_min_x, dst_max_x,
0, 0, 0, 0);
int clipMinX = ((Integer)clipRange.getMinValue()).intValue();
int clipMaxX = ((Integer)clipRange.getMaxValue()).intValue();
// Advance s_ix, s_iy, ifracx, ifracy
Point[] startPts = advanceToStartOfScanline(dst_min_x, clipMinX,
s_ix, s_iy,
ifracx, ifracy);
s_ix = startPts[0].x;
s_iy = startPts[0].y;
ifracx = startPts[1].x;
ifracy = startPts[1].y;
// Translate to/from SampleModel space & Raster space
src_pos = (s_iy - srcRectY)*srcScanlineStride +
(s_ix - srcRectX)*srcPixelStride;
if (setBackground) {
for (int x = dst_min_x; x < clipMinX; x++) {
for (int k2=0; k2 < dst_num_bands; k2++)
dstDataArrays[k2]
[dstPixelOffset+dstBandOffsets[k2]] =
backgroundFloat[k2];
dstPixelOffset += dstPixelStride;
}
} else // Advance to first pixel
dstPixelOffset += (clipMinX - dst_min_x)*dstPixelStride;
for (int x = clipMinX; x < clipMaxX; x++) {
for (int k2=0; k2 < dst_num_bands; k2++) {
dstDataArrays[k2]
[dstPixelOffset+dstBandOffsets[k2]] =
srcDataArrays[k2][src_pos + bandOffsets[k2]];
}
// walk
if (ifracx < ifracdx1) {
/*
// DEBUG
s_ix += incx;
*/
src_pos += incxStride;
ifracx += ifracdx;
} else {
/*
// DEBUG
s_ix += incx1;
*/
src_pos += incx1Stride;
ifracx -= ifracdx1;
}
if (ifracy < ifracdy1) {
/*
// DEBUG
s_iy += incy;
*/
src_pos += incyStride;
ifracy += ifracdy;
} else {
/*
// DEBUG
s_iy += incy1;
*/
src_pos += incy1Stride;
ifracy -= ifracdy1;
}
dstPixelOffset += dstPixelStride;
}
if (setBackground && clipMinX <= clipMaxX) {
for (int x = clipMaxX; x < dst_max_x ; x++) {
for (int k2=0; k2 < dst_num_bands; k2++)
dstDataArrays[k2]
[dstPixelOffset+dstBandOffsets[k2]] =
backgroundFloat[k2];
dstPixelOffset += dstPixelStride;
}
}
dstOffset += dstScanlineStride;
}
}
private void doubleLoop(RasterAccessor src,
Rectangle destRect,
int srcRectX,
int srcRectY,
RasterAccessor dst) {
float src_rect_x1 = src.getX();
float src_rect_y1 = src.getY();
float src_rect_x2 = src_rect_x1 + src.getWidth();
float src_rect_y2 = src_rect_y1 + src.getHeight();
float s_x, s_y;
int src_x, src_y, src_pos;
double fracx, fracy;
int dstPixelOffset;
int dstOffset = 0;
Point2D dst_pt = new Point2D.Float();
Point2D src_pt = new Point2D.Float();
int dwidth = dst.getWidth();
int dheight = dst.getHeight();
double dstDataArrays[][] = dst.getDoubleDataArrays();
int dstBandOffsets[] = dst.getBandOffsets();
int dstPixelStride = dst.getPixelStride();
int dstScanlineStride = dst.getScanlineStride();
double srcDataArrays[][] = src.getDoubleDataArrays();
int bandOffsets[] = src.getBandOffsets();
int srcPixelStride = src.getPixelStride();
int srcScanlineStride = src.getScanlineStride();
int dst_num_bands = dst.getNumBands();
int dst_min_x = destRect.x;
int dst_min_y = destRect.y;
int dst_max_x = destRect.x + destRect.width;
int dst_max_y = destRect.y + destRect.height;
int incxStride = incx*srcPixelStride;
int incx1Stride = incx1*srcPixelStride;
int incyStride = incy*srcScanlineStride;
int incy1Stride = incy1*srcScanlineStride;
for (int y = dst_min_y; y < dst_max_y; y++) {
dstPixelOffset = dstOffset;
// Backward map the first point in the line
// The energy is at the (pt_x + 0.5, pt_y + 0.5)
dst_pt.setLocation((double)dst_min_x + 0.5,
(double)y + 0.5);
mapDestPoint(dst_pt, src_pt);
// Get the mapped source coordinates
s_x = (float)src_pt.getX();
s_y = (float)src_pt.getY();
// Floor value to get the integral coordinate
int s_ix = (int) Math.floor(s_x);
int s_iy = (int) Math.floor(s_y);
fracx = s_x - (double)s_ix;
fracy = s_y - (double)s_iy;
int ifracx = (int) Math.floor(fracx * geom_frac_max);
int ifracy = (int) Math.floor(fracy * geom_frac_max);
// Compute clipMinX, clipMinY
Range clipRange =
performScanlineClipping(src_rect_x1, src_rect_y1,
src_rect_x2 - 1, src_rect_y2 - 1,
s_ix, s_iy,
ifracx, ifracy,
dst_min_x, dst_max_x,
0, 0, 0, 0);
int clipMinX = ((Integer)clipRange.getMinValue()).intValue();
int clipMaxX = ((Integer)clipRange.getMaxValue()).intValue();
// Advance s_ix, s_iy, ifracx, ifracy
Point[] startPts = advanceToStartOfScanline(dst_min_x, clipMinX,
s_ix, s_iy,
ifracx, ifracy);
s_ix = startPts[0].x;
s_iy = startPts[0].y;
ifracx = startPts[1].x;
ifracy = startPts[1].y;
// Translate to/from SampleModel space & Raster space
src_pos = (s_iy - srcRectY)*srcScanlineStride +
(s_ix - srcRectX)*srcPixelStride;
if (setBackground) {
for (int x = dst_min_x; x < clipMinX; x++) {
for (int k2=0; k2 < dst_num_bands; k2++)
dstDataArrays[k2]
[dstPixelOffset+dstBandOffsets[k2]] =
backgroundValues[k2];
dstPixelOffset += dstPixelStride;
}
} else // Advance to first pixel
dstPixelOffset += (clipMinX - dst_min_x)*dstPixelStride;
for (int x = clipMinX; x < clipMaxX; x++) {
for (int k2=0; k2 < dst_num_bands; k2++) {
dstDataArrays[k2]
[dstPixelOffset+dstBandOffsets[k2]] =
srcDataArrays[k2][src_pos + bandOffsets[k2]];
}
// walk
if (ifracx < ifracdx1) {
/*
// DEBUG
s_ix += incx;
*/
src_pos += incxStride;
ifracx += ifracdx;
} else {
/*
// DEBUG
s_ix += incx1;
*/
src_pos += incx1Stride;
ifracx -= ifracdx1;
}
if (ifracy < ifracdy1) {
/*
// DEBUG
s_iy += incy;
*/
src_pos += incyStride;
ifracy += ifracdy;
} else {
/*
// DEBUG
s_iy += incy1;
*/
src_pos += incy1Stride;
ifracy -= ifracdy1;
}
dstPixelOffset += dstPixelStride;
}
if (setBackground && clipMinX <= clipMaxX) {
for (int x = clipMaxX; x < dst_max_x ; x++) {
for (int k2=0; k2 < dst_num_bands; k2++)
dstDataArrays[k2]
[dstPixelOffset+dstBandOffsets[k2]] =
backgroundValues[k2];
dstPixelOffset += dstPixelStride;
}
}
dstOffset += dstScanlineStride;
}
}
}