com.github.jaiimageio.impl.plugins.raw.RawImageWriter Maven / Gradle / Ivy
/*
* $RCSfile: RawImageWriter.java,v $
*
*
* Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any
* kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
* WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
* EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
* NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
* USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
* DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
* ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
* CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
* REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
* INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed or intended for
* use in the design, construction, operation or maintenance of any
* nuclear facility.
*
* $Revision: 1.1 $
* $Date: 2005/02/11 05:01:42 $
* $State: Exp $
*/
package com.github.jaiimageio.impl.plugins.raw;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.image.BandedSampleModel;
import java.awt.image.ColorModel;
import java.awt.image.ComponentSampleModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferDouble;
import java.awt.image.DataBufferFloat;
import java.awt.image.DataBufferInt;
import java.awt.image.DataBufferShort;
import java.awt.image.DataBufferUShort;
import java.awt.image.MultiPixelPackedSampleModel;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.awt.image.SampleModel;
import java.awt.image.SinglePixelPackedSampleModel;
import java.awt.image.WritableRaster;
import java.io.IOException;
import javax.imageio.IIOImage;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.spi.ImageWriterSpi;
import javax.imageio.stream.ImageOutputStream;
import com.github.jaiimageio.impl.common.ImageUtil;
/**
* The Java Image IO plugin writer for encoding a binary RenderedImage into
* a Raw format.
*
* The encoding process may clip, subsample or select bands using the
* parameters specified in the ImageWriteParam
.
*
* Thus, when read this raw image the proper image data type
* should be provided.
*
* @see com.github.jaiimageio.plugins.RawImageWriteParam
*/
//
If the destination data is packed packed, the data is written in the
// order defined by the sample model. That the data is packed is defined as
// (1) if the sample model is SingleSamplePackedSampleModel
or
// BandedSampleModel
; or (2) the pixel stride or sanline stride
// equals to the band number; or (3) the pixel stride equals to the band
// number multiply the tile height; or (4) the scanline stride equals to the
// band number multiply the tile width; or (5) the data for a band is stored
// in a separate data bank.
//
//
Otherwise, the data is reordered in a packed pixel interleaved format,
// and then written into the stream. In this case the data order may be change.
// For example, the original image data is in the order of
//
// RRRRRRRRRRRRRRRRRRRR
// GGGGGGGGGGGGGGGGGGGG
// BBBBBBBBBBBBBBBBBBBB
// RRRRRRRRRRRRRRRRRRRR
// GGGGGGGGGGGGGGGGGGGG
// BBBBBBBBBBBBBBBBBBBB
//
//
// , and only the G and B bands are written in the stream. So the data in the
// stream will be in the order of
//
// GBGBGBGBGBGBGB
//
.
public class RawImageWriter extends ImageWriter {
/** The output stream to write into */
private ImageOutputStream stream = null;
/** The image index in this stream. */
private int imageIndex;
/** The tile width for encoding */
private int tileWidth;
/** The tile height for encoding */
private int tileHeight;
/** The tile grid offset for encoding */
private int tileXOffset, tileYOffset;
/** The source -> destination transformation */
private int scaleX, scaleY, xOffset, yOffset;
/** The source bands to be encoded. */
private int[] sourceBands = null;
/** The number of components in the image */
private int numBands;
/** The source raster if write raster. */
private RenderedImage input;
/** The input source raster. */
private Raster inputRaster;
private Rectangle destinationRegion = null;
private SampleModel sampleModel;
/** Coordinate transform or sub selection is needed before encoding. */
private boolean noTransform = true;
private boolean noSubband = true;
/** Indicates a raster
rather than a RenderedImage
* to be encoded.
*/
private boolean writeRaster = false;
/** Whether can write optimally. */
private boolean optimal = false;
/** The strides for pixel, band, and scanline. */
private int pxlStride, lineStride, bandStride;
/** Constructs RawImageWriter
based on the provided
* ImageWriterSpi
.
*/
public RawImageWriter(ImageWriterSpi originator) {
super(originator);
}
public void setOutput(Object output) {
super.setOutput(output); // validates output
if (output != null) {
if (!(output instanceof ImageOutputStream))
throw new IllegalArgumentException(I18N.getString("RawImageWriter0"));
this.stream = (ImageOutputStream)output;
} else
this.stream = null;
}
public IIOMetadata getDefaultStreamMetadata(ImageWriteParam param) {
return null;
}
public IIOMetadata getDefaultImageMetadata(ImageTypeSpecifier imageType,
ImageWriteParam param) {
return null;
}
public IIOMetadata convertStreamMetadata(IIOMetadata inData,
ImageWriteParam param) {
return null;
}
public IIOMetadata convertImageMetadata(IIOMetadata metadata,
ImageTypeSpecifier type,
ImageWriteParam param) {
return null;
}
public boolean canWriteRasters() {
return true;
}
public ImageWriteParam getDefaultWriteParam() {
return new RawImageWriteParam(getLocale());
}
public void write(IIOMetadata streamMetadata,
IIOImage image,
ImageWriteParam param) throws IOException {
clearAbortRequest();
processImageStarted(imageIndex++);
if (param == null)
param = getDefaultWriteParam();
writeRaster = image.hasRaster();
Rectangle sourceRegion = param.getSourceRegion();
ColorModel colorModel = null;
Rectangle originalRegion = null;
if (writeRaster) {
inputRaster = image.getRaster();
sampleModel = inputRaster.getSampleModel();
originalRegion = inputRaster.getBounds();
} else {
input = image.getRenderedImage();
sampleModel = input.getSampleModel();
originalRegion = new Rectangle(input.getMinX(), input.getMinY(),
input.getWidth(), input.getHeight());
colorModel = input.getColorModel();
}
if (sourceRegion == null)
sourceRegion = (Rectangle)originalRegion.clone();
else
sourceRegion = sourceRegion.intersection(originalRegion);
if (sourceRegion.isEmpty())
throw new RuntimeException(I18N.getString("RawImageWriter1"));
scaleX = param.getSourceXSubsampling();
scaleY = param.getSourceYSubsampling();
xOffset = param.getSubsamplingXOffset();
yOffset = param.getSubsamplingYOffset();
sourceRegion.translate(xOffset, yOffset);
sourceRegion.width -= xOffset;
sourceRegion.height -= yOffset;
xOffset = sourceRegion.x % scaleX;
yOffset = sourceRegion.y % scaleY;
int minX = sourceRegion.x / scaleX;
int minY = sourceRegion.y / scaleY;
int w = (sourceRegion.width + scaleX - 1) / scaleX;
int h = (sourceRegion.height + scaleY - 1) / scaleY;
destinationRegion = new Rectangle(minX, minY, w, h);
noTransform = destinationRegion.equals(originalRegion);
tileHeight = sampleModel.getHeight();
tileWidth = sampleModel.getWidth();
if (noTransform) {
if (writeRaster) {
tileXOffset = inputRaster.getMinX();
tileYOffset = inputRaster.getMinY();
} else {
tileXOffset = input.getTileGridXOffset();
tileYOffset = input.getTileGridYOffset();
}
} else {
tileXOffset = destinationRegion.x;
tileYOffset = destinationRegion.y;
}
sourceBands = param.getSourceBands();
boolean noSubband = true;
numBands = sampleModel.getNumBands();
if (sourceBands != null) {
sampleModel = sampleModel.createSubsetSampleModel(sourceBands);
colorModel = null;
noSubband = false;
numBands = sampleModel.getNumBands();
} else {
sourceBands = new int[numBands];
for (int i = 0; i < numBands; i++)
sourceBands[i] = i;
}
if (sampleModel instanceof ComponentSampleModel) {
ComponentSampleModel csm = (ComponentSampleModel)sampleModel;
int[] bandOffsets = csm.getBandOffsets();
bandStride = bandOffsets[0];
for (int i = 1; i < bandOffsets.length; i++)
if (bandStride > bandOffsets[i])
bandStride = bandOffsets[i];
int[] bankIndices = csm.getBankIndices();
int numBank = bankIndices[0];
for (int i = 1; i < bankIndices.length; i++)
if (numBank > bankIndices[i])
numBank = bankIndices[i];
pxlStride = csm.getPixelStride();
lineStride = csm.getScanlineStride();
optimal = bandStride == 0 ||
(pxlStride < lineStride && pxlStride == numBands) ||
(lineStride < pxlStride && lineStride == numBands) ||
(pxlStride < lineStride &&
lineStride == numBands * csm.getWidth()) ||
(lineStride < pxlStride &&
pxlStride == numBands * csm.getHeight()) ||
csm instanceof BandedSampleModel;
} else if (sampleModel instanceof SinglePixelPackedSampleModel ||
sampleModel instanceof MultiPixelPackedSampleModel) {
optimal = true;
}
int numXTiles = getMaxTileX() - getMinTileX() + 1;
int totalTiles = numXTiles * (getMaxTileY() - getMinTileY() + 1);
for (int y = getMinTileY(); y <= getMaxTileY(); y++) {
for (int x = getMinTileX(); x <= getMaxTileX(); x++) {
writeRaster(getTile(x, y));
float percentage = (x + y * numXTiles + 1.0F) / totalTiles;
processImageProgress(percentage * 100.0F);
}
}
stream.flush();
if (abortRequested())
processWriteAborted();
else
processImageComplete();
}
//XXX: just for test
public int getWidth() {
return destinationRegion.width;
}
public int getHeight() {
return destinationRegion.height;
}
private void writeRaster(Raster raster) throws IOException {
int numBank = 0;
int bandStride = 0;
int[] bankIndices = null;
int[] bandOffsets = null;
int bandSize = 0;
int numBand = sampleModel.getNumBands();
int type = sampleModel.getDataType();
if (sampleModel instanceof ComponentSampleModel) {
ComponentSampleModel csm = (ComponentSampleModel)sampleModel;
bandOffsets = csm.getBandOffsets();
for (int i = 0; i < numBand; i++)
if (bandStride < bandOffsets[i])
bandStride = bandOffsets[i];
bankIndices = csm.getBankIndices();
for (int i = 0; i < numBand; i++)
if (numBank < bankIndices[i])
numBank = bankIndices[i];
bandSize = (int)ImageUtil.getBandSize(sampleModel) ;
}
byte[] bdata = null;
short[] sdata = null;
int[] idata = null;
float[] fdata = null;
double[] ddata = null;
if (raster.getParent() != null &&
!sampleModel.equals(raster.getParent().getSampleModel())) {
WritableRaster ras =
Raster.createWritableRaster(sampleModel,
new Point(raster.getMinX(),
raster.getMinY()));
ras.setRect(raster);
raster = ras;
}
DataBuffer data = raster.getDataBuffer();
if (optimal) {
if (numBank > 0) { //multiple data bank
for (int i = 0; i < numBands; i++) {
int bank = bankIndices[sourceBands[i]];
switch (type) {
case DataBuffer.TYPE_BYTE:
bdata = ((DataBufferByte)data).getData(bank);
stream.write(bdata, 0, bdata.length);
break;
case DataBuffer.TYPE_SHORT:
sdata = ((DataBufferShort)data).getData(bank);
stream.writeShorts(sdata, 0, sdata.length);
break;
case DataBuffer.TYPE_USHORT:
sdata = ((DataBufferUShort)data).getData(bank);
stream.writeShorts(sdata, 0, sdata.length);
break;
case DataBuffer.TYPE_INT:
idata = ((DataBufferInt)data).getData(bank);
stream.writeInts(idata, 0, idata.length);
break;
case DataBuffer.TYPE_FLOAT:
fdata = ((DataBufferFloat)data).getData(bank);
stream.writeFloats(fdata, 0, fdata.length);
break;
case DataBuffer.TYPE_DOUBLE:
ddata = ((DataBufferDouble)data).getData(bank);
stream.writeDoubles(ddata, 0, ddata.length);
break;
}
}
} else { // Single data bank
switch (type) {
case DataBuffer.TYPE_BYTE:
bdata = ((DataBufferByte)data).getData();
break;
case DataBuffer.TYPE_SHORT:
sdata = ((DataBufferShort)data).getData();
break;
case DataBuffer.TYPE_USHORT:
sdata = ((DataBufferUShort)data).getData();
break;
case DataBuffer.TYPE_INT:
idata = ((DataBufferInt)data).getData();
break;
case DataBuffer.TYPE_FLOAT:
fdata = ((DataBufferFloat)data).getData();
break;
case DataBuffer.TYPE_DOUBLE:
ddata = ((DataBufferDouble)data).getData();
break;
}
if (!noSubband &&
bandStride >= raster.getWidth() *
raster.getHeight() * (numBands-1)) {
for (int i = 0; i < numBands; i++) {
int offset = bandOffsets[sourceBands[i]];
switch (type) {
case DataBuffer.TYPE_BYTE:
stream.write(bdata, offset, bandSize);
break;
case DataBuffer.TYPE_SHORT:
case DataBuffer.TYPE_USHORT:
stream.writeShorts(sdata, offset, bandSize);
break;
case DataBuffer.TYPE_INT:
stream.writeInts(idata, offset, bandSize);
break;
case DataBuffer.TYPE_FLOAT:
stream.writeFloats(fdata, offset, bandSize);
break;
case DataBuffer.TYPE_DOUBLE:
stream.writeDoubles(ddata, offset, bandSize);
break;
}
}
} else {
switch (type) {
case DataBuffer.TYPE_BYTE:
stream.write(bdata, 0, bdata.length);
break;
case DataBuffer.TYPE_SHORT:
case DataBuffer.TYPE_USHORT:
stream.writeShorts(sdata, 0, sdata.length);
break;
case DataBuffer.TYPE_INT:
stream.writeInts(idata, 0, idata.length);
break;
case DataBuffer.TYPE_FLOAT:
stream.writeFloats(fdata, 0, fdata.length);
break;
case DataBuffer.TYPE_DOUBLE:
stream.writeDoubles(ddata, 0, ddata.length);
break;
}
}
}
} else if (sampleModel instanceof ComponentSampleModel) {
// The others, must be a ComponentSampleModel
switch (type) {
case DataBuffer.TYPE_BYTE:
bdata = ((DataBufferByte)data).getData();
break;
case DataBuffer.TYPE_SHORT:
sdata = ((DataBufferShort)data).getData();
break;
case DataBuffer.TYPE_USHORT:
sdata = ((DataBufferUShort)data).getData();
break;
case DataBuffer.TYPE_INT:
idata = ((DataBufferInt)data).getData();
break;
case DataBuffer.TYPE_FLOAT:
fdata = ((DataBufferFloat)data).getData();
break;
case DataBuffer.TYPE_DOUBLE:
ddata = ((DataBufferDouble)data).getData();
break;
}
ComponentSampleModel csm = (ComponentSampleModel)sampleModel;
int offset =
csm.getOffset(raster.getMinX()-raster.getSampleModelTranslateX(),
raster.getMinY()-raster.getSampleModelTranslateY())
- bandOffsets[0];
int srcSkip = pxlStride;
int copyLength = 1;
int innerStep = pxlStride;
int width = raster.getWidth();
int height = raster.getHeight();
int innerBound = width;
int outerBound = height;
if (srcSkip < lineStride) {
if (bandStride > pxlStride)
copyLength = width;
srcSkip = lineStride;
} else {
if (bandStride > lineStride)
copyLength = height;
innerStep = lineStride;
innerBound = height;
outerBound = width;
}
int writeLength = innerBound * numBands;
byte[] destBBuf = null;
short[] destSBuf = null;
int[] destIBuf = null;
float[] destFBuf = null;
double[] destDBuf = null;
Object srcBuf = null;
Object dstBuf = null;
switch (type) {
case DataBuffer.TYPE_BYTE:
srcBuf = bdata;
dstBuf = destBBuf = new byte[writeLength];
break;
case DataBuffer.TYPE_SHORT:
case DataBuffer.TYPE_USHORT:
srcBuf = sdata;
dstBuf = destSBuf = new short[writeLength];
break;
case DataBuffer.TYPE_INT:
srcBuf = idata;
dstBuf = destIBuf = new int[writeLength];
break;
case DataBuffer.TYPE_FLOAT:
srcBuf = fdata;
dstBuf = destFBuf = new float[writeLength];
break;
case DataBuffer.TYPE_DOUBLE:
srcBuf = ddata;
dstBuf = destDBuf = new double[writeLength];
break;
}
if (copyLength > 1) {
for (int i = 0; i < outerBound; i++) {
for (int b = 0; b < numBands; b++) {
int bandOffset = bandOffsets[b];
System.arraycopy(srcBuf, offset + bandOffset,
dstBuf, b * innerBound, innerBound);
}
switch (type) {
case DataBuffer.TYPE_BYTE:
stream.write((byte[])dstBuf, 0, writeLength);
break;
case DataBuffer.TYPE_SHORT:
case DataBuffer.TYPE_USHORT:
stream.writeShorts((short[])dstBuf, 0, writeLength);
break;
case DataBuffer.TYPE_INT:
stream.writeInts((int[])dstBuf, 0, writeLength);
break;
case DataBuffer.TYPE_FLOAT:
stream.writeFloats((float[])dstBuf, 0, writeLength);
break;
case DataBuffer.TYPE_DOUBLE:
stream.writeDoubles((double[])dstBuf, 0, writeLength);
break;
}
offset += srcSkip;
}
} else {
switch (type) {
case DataBuffer.TYPE_BYTE: {
for (int i = 0; i < outerBound; i++) {
for (int b = 0, k = 0; b < numBands; b++) {
int bandOffset = bandOffsets[b];
for (int j = 0, m = offset; j < innerBound;
j++, m += innerStep)
// copy one sample to the destination buffer
destBBuf[k++] = bdata[m + bandOffset];
}
stream.write(destBBuf, 0, writeLength);
offset += srcSkip;
}
}
break;
case DataBuffer.TYPE_SHORT:
case DataBuffer.TYPE_USHORT: {
for (int i = 0; i < outerBound; i++) {
for (int b = 0, k = 0; b < numBands; b++) {
int bandOffset = bandOffsets[b];
for (int j = 0, m = offset; j < innerBound;
j++, m += innerStep)
// copy one sample to the destination buffer
destSBuf[k++] = sdata[m + bandOffset];
}
stream.writeShorts(destSBuf, 0, writeLength);
offset += srcSkip;
}
}
break;
case DataBuffer.TYPE_INT: {
for (int i = 0; i < outerBound; i++) {
for (int b = 0, k = 0; b < numBands; b++) {
int bandOffset = bandOffsets[b];
for (int j = 0, m = offset; j < innerBound;
j++, m += innerStep)
// copy one sample to the destination buffer
destIBuf[k++] = idata[m + bandOffset];
}
stream.writeInts(destIBuf, 0, writeLength);
offset += srcSkip;
}
}
break;
case DataBuffer.TYPE_FLOAT: {
for (int i = 0; i < outerBound; i++) {
for (int b = 0, k = 0; b < numBands; b++) {
int bandOffset = bandOffsets[b];
for (int j = 0, m = offset; j < innerBound;
j++, m += innerStep)
// copy one sample to the destination buffer
destFBuf[k++] = fdata[m + bandOffset];
}
stream.writeFloats(destFBuf, 0, writeLength);
offset += srcSkip;
}
}
break;
case DataBuffer.TYPE_DOUBLE: {
for (int i = 0; i < outerBound; i++) {
for (int b = 0, k = 0; b < numBands; b++) {
int bandOffset = bandOffsets[b];
for (int j = 0, m = offset; j < innerBound;
j++, m += innerStep)
// copy one sample to the destination buffer
destDBuf[k++] = ddata[m + bandOffset];
}
stream.writeDoubles(destDBuf, 0, writeLength);
offset += srcSkip;
}
}
break;
}
}
}
}
private Raster getTile(int tileX, int tileY) {
int sx = tileXOffset + tileX * tileWidth;
int sy = tileYOffset + tileY * tileHeight;
Rectangle bounds = new Rectangle(sx, sy, tileWidth, tileHeight);
if (writeRaster) {
bounds = bounds.intersection(destinationRegion);
if (noTransform) {
return inputRaster.createChild(bounds.x, bounds.y,
bounds.width, bounds.height,
bounds.x, bounds.y, sourceBands);
}
sx = bounds.x;
sy = bounds.y;
WritableRaster ras =
Raster.createWritableRaster(sampleModel, new Point(sx, sy));
int x = mapToSourceX(sx);
int y = mapToSourceY(sy);
int minY = inputRaster.getMinY();
int maxY = inputRaster.getMinY() + inputRaster.getHeight();
int cTileWidth = bounds.width;
int length = (cTileWidth - 1) * scaleX + 1;
for (int j = 0; j < bounds.height; j++, sy++, y += scaleY) {
if (y < minY || y >= maxY)
continue;
Raster source =
inputRaster.createChild(x, y, length, 1,
x, y, null);
int tempX = sx;
for (int i = 0, offset = x; i < cTileWidth;
i++, tempX++, offset += scaleX) {
for (int k = 0; k < numBands; k++) {
int p = source.getSample(offset, y, sourceBands[k]);
ras.setSample(tempX, sy, k, p);
}
}
}
return ras;
} else {
if (noTransform) {
Raster ras = input.getTile(tileX, tileY);
if (destinationRegion.contains(bounds) && noSubband)
return ras;
else {
bounds = bounds.intersection(destinationRegion);
return ras.createChild(bounds.x, bounds.y,
bounds.width, bounds.height,
bounds.x, bounds.y, sourceBands);
}
}
bounds = bounds.intersection(destinationRegion);
sx = bounds.x;
sy = bounds.y;
WritableRaster ras =
Raster.createWritableRaster(sampleModel, new Point(sx, sy));
int x = mapToSourceX(sx);
int y = mapToSourceY(sy);
int minY = input.getMinY();
int maxY = input.getMinY() + input.getHeight();
int cTileWidth = bounds.width;
int length = (cTileWidth -1) * scaleX + 1;
for (int j = 0; j < bounds.height; j++, sy++, y += scaleY) {
if (y < minY || y >= maxY)
continue;
Raster source =
input.getData(new Rectangle(x, y, length, 1));
int tempX = sx;
for (int i = 0, offset = x; i < cTileWidth;
i++, tempX++, offset += scaleX) {
for (int k = 0; k < numBands; k++) {
int p = source.getSample(offset, y, sourceBands[k]);
ras.setSample(tempX, sy, k, p);
}
}
}
return ras;
}
}
private int mapToSourceX(int x) {
return x * scaleX + xOffset;
}
private int mapToSourceY(int y) {
return y * scaleY + yOffset;
}
private int getMinTileX() {
return ToTile(destinationRegion.x, tileXOffset, tileWidth);
}
private int getMaxTileX() {
return ToTile(destinationRegion.x + destinationRegion.width - 1,
tileXOffset, tileWidth);
}
private int getMinTileY() {
return ToTile(destinationRegion.y, tileYOffset, tileHeight);
}
private int getMaxTileY() {
return ToTile(destinationRegion.y + destinationRegion.height - 1,
tileYOffset, tileHeight);
}
private static int ToTile(int pos, int tileOffset, int tileSize) {
pos -= tileOffset;
if (pos < 0) {
pos += 1 - tileSize; // force round to -infinity (ceiling)
}
return pos/tileSize;
}
public void reset() {
super.reset();
stream = null;
optimal = false;
sourceBands = null;
destinationRegion = null;
noTransform = true;
noSubband = true;
writeRaster = false;
}
}