com.github.jaiimageio.jpeg2000.impl.RenderedImageSrc Maven / Gradle / Ivy
Show all versions of jai-imageio-jpeg2000 Show documentation
/*
* $RCSfile: RenderedImageSrc.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.2 $
* $Date: 2006/09/22 23:07:25 $
* $State: Exp $
*/
package com.github.jaiimageio.jpeg2000.impl;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.image.ColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.awt.image.SampleModel;
import java.awt.image.WritableRaster;
import jj2000.j2k.JJ2KExceptionHandler;
import jj2000.j2k.image.BlkImgDataSrc;
import jj2000.j2k.image.DataBlk;
import jj2000.j2k.image.DataBlkInt;
import jj2000.j2k.image.ImgData;
import com.github.jaiimageio.impl.common.ImageUtil;
public class RenderedImageSrc implements BlkImgDataSrc {
/** The width of the image */
private int w;
/** The height of the image */
private int h;
/** The tile width for encoding */
int tileWidth;
/** The tile height for encoding */
int tileHeight;
/** The tile grid offset for encoding */
int tileXOffset, tileYOffset;
/** The source -> destination transformation */
int scaleX, scaleY, xOffset, yOffset;
/** The source bands to be encoded. */
int[] sourceBands = null;
/** The destination upper-left corner */
int minX, minY;
/** The number of components in the image */
private int nc;
/** The number of bits that determine the nominal dynamic range */
// XXX: Should be an int[] of length 'nc'.
private int rb;
/** Buffer for the 3 components of each pixel(in the current block) */
private int[][] barr = null;
/** Data block used only to store coordinates of the buffered blocks */
private DataBlkInt dbi = new DataBlkInt();
/** The line buffer. */
private byte buf[];
/** Temporary DataBlkInt object (needed when encoder uses floating-point
filters). This avoid allocating new DataBlk at each time */
private DataBlkInt intBlk;
private RenderedImage src;
private J2KImageWriteParamJava param;
/** The input source raster. */
private Raster raster;
/** The raster for a destination tile */
private Raster aTile;
private Point co = new Point();
private int dcOffset = 0;
private boolean isBinary = false;
private Rectangle destinationRegion;
private Rectangle sourceRegion;
private ColorModel cm;
private SampleModel sm;
private boolean noTransform = true;
private boolean noSubband = true;
/** Used to process abortion. */
private J2KImageWriter writer;
/** Indicates a raster
rather than a RenderedImage
* to be encoded.
*/
private boolean inputIsRaster = false;
/**
* Creates RenderedImageSrc
for encoding a Raster
.
*
* @param raster The Raster
to be encoded.
* @param param The J2KImageWriteParamJava
used in encoding.
* @param writer The J2KImageWriter
performs the encoding.
*
* @param IOException If an error occurs while opening the file.
*/
public RenderedImageSrc(Raster raster,
J2KImageWriteParamJava param,
J2KImageWriter writer) {
this.raster = raster;
this.param = param;
this.writer = writer;
this.inputIsRaster = true;
sourceRegion = param.getSourceRegion();
if (sourceRegion == null)
sourceRegion = new Rectangle(raster.getMinX(), raster.getMinY(),
raster.getWidth(), raster.getHeight());
else
sourceRegion = sourceRegion.intersection(raster.getBounds());
if (sourceRegion.isEmpty())
throw new RuntimeException(I18N.getString("J2KImageWriterCodecLib0"));
sm = raster.getSampleModel();
getFromParam();
setSampleModelAndMore();
setTile(0, 0);
}
/**
* Creates RenderedImageSrc
for encoding a
* RenderedImage
.
*
* @param src The RenderedImage
to be encoded.
* @param param The J2KImageWriteParamJava
used in encoding.
* @param writer The J2KImageWriter
performs the encoding.
*
* @param IOException If an error occurs while opening the file.
* */
public RenderedImageSrc(RenderedImage src,
J2KImageWriteParamJava param,
J2KImageWriter writer) {
this.src = src;
this.param = param;
this.writer = writer;
sourceRegion = param.getSourceRegion();
if (sourceRegion == null)
sourceRegion = new Rectangle(src.getMinX(), src.getMinY(),
src.getWidth(), src.getHeight());
else
sourceRegion = sourceRegion.intersection(new Rectangle(src.getMinX(),
src.getMinY(),
src.getWidth(),
src.getHeight()));
if (sourceRegion.isEmpty())
throw new RuntimeException(I18N.getString("J2KImageWriterCodecLib0"));
sm = src.getSampleModel();
cm = src.getColorModel();
getFromParam();
setSampleModelAndMore();
}
private void getFromParam() {
try {
tileWidth = param.getTileWidth();
tileHeight = param.getTileHeight();
tileXOffset = param.getTileGridXOffset();
tileYOffset = param.getTileGridYOffset();
} catch(IllegalStateException e) {
param.setTilingMode(param.MODE_EXPLICIT);
if (inputIsRaster) {
param.setTiling(raster.getWidth(), raster.getHeight(),
raster.getMinX(), raster.getMinY());
} else {
param.setTiling(src.getWidth(), src.getHeight(),
src.getMinX(), src.getMinY());
}
tileWidth = param.getTileWidth();
tileHeight = param.getTileHeight();
tileXOffset = param.getTileGridXOffset();
tileYOffset = param.getTileGridYOffset();
}
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;
minX = sourceRegion.x / scaleX;
minY = sourceRegion.y / scaleY;
w = (sourceRegion.width + scaleX - 1) / scaleX;
h = (sourceRegion.height + scaleY - 1) / scaleY;
tileXOffset += (minX - tileXOffset)/tileWidth * tileWidth;
tileYOffset += (minY - tileYOffset)/tileHeight * tileHeight;
destinationRegion = new Rectangle(minX, minY, w, h);
if (!destinationRegion.equals(sourceRegion) ||
tileWidth != sm.getWidth() ||
tileHeight != sm.getHeight() ||
(!inputIsRaster &&
(tileXOffset != src.getTileGridXOffset() ||
tileYOffset != src.getTileGridYOffset())) ||
(inputIsRaster &&
(tileXOffset != raster.getMinX() ||
tileYOffset != raster.getMinY())))
noTransform = false;
}
private void setSampleModelAndMore() {
nc = sm.getNumBands();
sourceBands = param.getSourceBands();
if (sourceBands != null) {
sm = sm.createSubsetSampleModel(sourceBands);
noSubband = false;
} else {
sourceBands = new int[nc];
for (int i = 0; i < nc; i++)
sourceBands[i] = i;
}
sm = sm.createCompatibleSampleModel(tileWidth, tileHeight);
nc = sm.getNumBands();
isBinary = ImageUtil.isBinary(sm);
if(cm != null) {
// XXX: rb should be set to getComponentSize();
rb = cm.getComponentSize(0);
for (int i = 1; i < cm.getNumComponents(); i++)
if (rb < cm.getComponentSize(i))
rb = cm.getComponentSize(i);
} else {
// XXX: rb should be set to getSampleSize();
rb = sm.getSampleSize(0);
for (int i = 1; i < sm.getNumBands(); i++)
if (rb < sm.getSampleSize(i))
rb = sm.getSampleSize(i);
}
if (!isOrigSigned(0) && rb > 1)
// XXX: if rb is an int[] this will have to change.
dcOffset = 1 << rb - 1;
}
public int getTilePartULX() {
return tileXOffset;
}
public int getTilePartULY() {
return tileYOffset;
}
/**
* Returns the width of the current tile in pixels.
*
* @return The total image width in pixels.
* */
public int getTileWidth() {
int width = tileWidth;
int maxX = getImgULX() + getImgWidth();
int x = co.x * tileWidth + tileXOffset;
if (x + tileWidth >= maxX)
width = maxX - x;
return width;
}
/**
* Returns the overall height of the current tile in pixels.
*
* @return The total image height in pixels. */
public int getTileHeight() {
int height = tileHeight;
int maxY = getImgULY() + getImgHeight();
int y = co.y * tileHeight + tileYOffset;
if (y + tileHeight >= maxY)
height = maxY - y;
return height;
}
public int getNomTileWidth() {
return tileWidth;
}
public int getNomTileHeight() {
return tileHeight;
}
/**
* Returns the overall width of the image in pixels. This is the image's
* width without accounting for any component subsampling or tiling. The
* value of w is returned.
*
* @return The total image's width in pixels.
* */
public int getImgWidth() {
return w;
}
/**
* Returns the overall height of the image in pixels. This is the image's
* height without accounting for any component subsampling or tiling. The
* value of h is returned.
*
* @return The total image's height in pixels.
* */
public int getImgHeight() {
return h;
}
/**
* Returns the number of components in the image. The value of nc
* is returned.
*
* @return The number of components in the image.
* */
public int getNumComps() {
return nc;
}
public int getTileGridXOffset() {
return param.getTileGridXOffset();
}
public int getTileGridYOffset() {
return param.getTileGridYOffset();
}
public int getTileCompHeight(int t, int c) {
return tileHeight;
}
public int getTileCompWidth(int t, int c) {
return tileWidth;
}
/**
* Returns the component subsampling factor in the horizontal direction,
* for the specified component. This is, approximately, the ratio of
* dimensions between the reference grid and the component itself, see the
* 'ImgData' interface desription for details.
*
* @param c The index of the component (between 0 and C-1)
*
* @return The horizontal subsampling factor of component 'c'
*
* @see ImgData
* */
public int getCompSubsX(int c) {
return 1;
}
/**
* Returns the component subsampling factor in the vertical direction, for
* the specified component. This is, approximately, the ratio of
* dimensions between the reference grid and the component itself, see the
* 'ImgData' interface desription for details.
*
* @param c The index of the component (between 0 and C-1)
*
* @return The vertical subsampling factor of component 'c'
*
* @see ImgData
* */
public int getCompSubsY(int c) {
return 1;
}
/**
* Returns the width in pixels of the specified component in the current
* tile. This default implementation assumes no tiling and no component
* subsampling (i.e., all components, or components, have the same
* dimensions in pixels).
*
* @param c The index of the component, from 0 to C-1.
*
* @return The width in pixels of component n in the current
* tile.
* */
public int getCompWidth(int n) {
return w;
}
/**
* Returns the height in pixels of the specified component in the current
* tile. This default implementation assumes no tiling and no component
* subsampling (i.e., all components, or components, have the same
* dimensions in pixels).
*
* @param c The index of the component, from 0 to C-1.
*
* @return The height in pixels of component c in the current
* tile.
* */
public int getCompHeight(int c) {
return h;
}
/**
* Returns the width in pixels of the specified component in the overall
* image. This default implementation assumes no component, or component,
* subsampling (i.e. all components have the same dimensions in pixels).
*
* @param c The index of the component, from 0 to C-1.
*
* @return The width in pixels of component c in the overall
* image.
* */
public int getCompImgWidth(int c) {
return w;
}
/**
* Returns the height in pixels of the specified component in the overall
* image. This default implementation assumes no component, or component,
* subsampling (i.e. all components have the same dimensions in pixels).
*
* @param c The index of the component, from 0 to C-1.
*
* @return The height in pixels of component c in the overall
* image.
* */
public int getCompImgHeight(int c) {
return h;
}
/**
* Changes the current tile, given the new coordinates.
*
* @param x The horizontal coordinate of the tile.
*
* @param y The vertical coordinate of the new tile.
* */
public void setTile(int x, int y) {
if (x >= getNumXTiles()) {
y += x/ getNumXTiles();
x = x % getNumXTiles();
}
co.x = x;
co.y = y;
aTile = null;
}
/**
* Advances to the next tile, in standard scan-line order (by rows then
* columns).
* */
public void nextTile() {
co.x++;
if (co.x >= getNumXTiles()) {
co.x = 0;
co.y++;
}
setTile(co.x, co.y);
}
/**
* Returns the coordinates of the current tile. This default
* implementation assumes no-tiling, so (0,0) is returned.
*
* @param co If not null this object is used to return the information. If
* null a new one is created and returned.
*
* @return The current tile's coordinates.
* */
public Point getTile(Point co) {
if (co != null)
return co;
else
return new Point(0, 0);
}
/**
* Returns the index of the current tile, relative to a standard scan-line
* order.
*
* @return The current tile's index (starts at 0).
* */
public int getTileIdx() {
return getNumXTiles() * co.y + co.x;
}
/**
* Returns the horizontal and vertical offset of the upper-left corner of
* the current tile, in the specified component, relative to the canvas
* origin, in the component coordinates (not in the reference grid
* coordinates). These are the coordinates of the current tile's (not
* active tile) upper-left corner relative to the canvas.
*
* @param co If not null the object is used to return the values, if null
* a new one is created and returned.
*
* @param c The index of the component (between 0 and C-1)
*
* @return The horizontal and vertical offsets of the upper-left corner of
* the current tile, for the specified component, relative to the canvas
* origin, in the component coordinates.
* */
public Point getTileOff(Point p, int c) {
if (p != null) {
p.x = co.x * tileWidth + tileXOffset;
p.y = co.y * tileHeight + tileYOffset;
return co;
} else
return new Point(co.x * tileWidth + tileXOffset,
co.y * tileHeight + tileYOffset);
}
/**
* Returns the horizontal coordinate of the upper-left corner of the
* active tile, with respect to the canvas origin, in the component
* coordinates, for the specified component.
*
* @param c The index of the component (between 0 and C-1)
*
* @return The horizontal coordinate of the upper-left corner of the
* active tile, with respect to the canvas origin, for component 'c', in
* the component coordinates.
* */
public int getCompULX(int c) {
return raster.getMinX();
}
/**
* Returns the vertical coordinate of the upper-left corner of the active
* tile, with respect to the canvas origin, in the component coordinates,
* for the specified component.
*
* @param c The index of the component (between 0 and C-1)
*
* @return The vertical coordinate of the upper-left corner of the active
* tile, with respect to the canvas origin, for component 'c', in the
* component coordinates.
* */
public int getCompULY(int c) {
return raster.getMinY();
}
/**
* Returns the horizontal coordinate of the image origin, the top-left
* corner, in the canvas system, on the reference grid.
*
* @return The horizontal coordinate of the image origin in the canvas
* system, on the reference grid.
* */
public int getImgULX() {
return destinationRegion.x;
}
/**
* Returns the vertical coordinate of the image origin, the top-left
* corner, in the canvas system, on the reference grid.
*
* @return The vertical coordinate of the image origin in the canvas
* system, on the reference grid.
* */
public int getImgULY() {
return destinationRegion.y;
}
/**
* Returns the number of tiles in the horizontal and vertical
* directions.
*
* @param co If not null this object is used to return the information. If
* null a new one is created and returned.
*
* @return The number of tiles in the horizontal (Point.x) and vertical
* (Point.y) directions.
* */
public Point getNumTiles(Point co) {
if (co != null) {
co.x = getNumXTiles();
co.y = getNumYTiles();
return co;
}
else {
return new Point(getNumXTiles(), getNumYTiles());
}
}
/**
* Returns the total number of tiles in the image. This default
* implementation assumes no tiling, so 1 is always returned.
*
* @return The total number of tiles in the image.
* */
public int getNumTiles() {
return getNumXTiles() * getNumYTiles();
}
/**
* Returns the number of bits corresponding to the nominal range of the
* data in the specified component. This is the value rb (range bits) that
* was specified in the constructor, which normally is 8 for non bilevel
* data, and 1 for bilevel data.
*
* If this number is b then the nominal range is between
* -2^(b-1) and 2^(b-1)-1, since unsigned data is level shifted to have a
* nominal avergae of 0.
*
* @param c The index of the component.
*
* @return The number of bits corresponding to the nominal range of the
* data. For floating-point data this value is not applicable and the
* return value is undefined.
* */
public int getNomRangeBits(int c) {
// Check component index
// XXX: Should be component-dependent.
return rb;
}
/**
* Returns the position of the fixed point in the specified component
* (i.e. the number of fractional bits), which is always 0 for this
* ImgReader.
*
* @param c The index of the component.
*
* @return The position of the fixed-point (i.e. the number of fractional
* bits). Always 0 for this ImgReader.
* */
public int getFixedPoint(int c) {
// Check component index
return 0;
}
/**
* Returns, in the blk argument, the block of image data containing the
* specifed rectangular area, in the specified component. The data is
* returned, as a reference to the internal data, if any, instead of as a
* copy, therefore the returned data should not be modified.
*
*
After being read the coefficients are level shifted by subtracting
* 2^(nominal bit range - 1)
*
*
The rectangular area to return is specified by the 'ulx', 'uly', 'w'
* and 'h' members of the 'blk' argument, relative to the current
* tile. These members are not modified by this method. The 'offset' and
* 'scanw' of the returned data can be arbitrary. See the 'DataBlk' class.
*
*
If the data array in blk is null, then a new one
* is created if necessary. The implementation of this interface may
* choose to return the same array or a new one, depending on what is more
* efficient. Therefore, the data array in blk prior to the
* method call should not be considered to contain the returned data, a
* new array may have been created. Instead, get the array from
* blk after the method has returned.
*
*
The returned data always has its 'progressive' attribute unset
* (i.e. false).
*
*
When an I/O exception is encountered the JJ2KExceptionHandler is
* used. The exception is passed to its handleException method. The action
* that is taken depends on the action that has been registered in
* JJ2KExceptionHandler. See JJ2KExceptionHandler for details.
*
*
This method implements buffering for the 3 components: When the
* first one is asked, all the 3 components are read and stored until they
* are needed.
*
* @param blk Its coordinates and dimensions specify the area to
* return. Some fields in this object are modified to return the data.
*
* @param c The index of the component from which to get the data. Only 0,
* 1 and 3 are valid.
*
* @return The requested DataBlk
*
* @see #getCompData
*
* @see JJ2KExceptionHandler
*/
public final DataBlk getInternCompData(DataBlk blk, int c) {
if (writer != null && writer.getAbortRequest())
throw new RuntimeException(J2KImageWriter.WRITE_ABORTED);
if (barr == null)
barr = new int[nc][];
// Check type of block provided as an argument
if(blk.getDataType()!=DataBlk.TYPE_INT){
if(intBlk==null)
intBlk = new DataBlkInt(blk.ulx,blk.uly,blk.w,blk.h);
else{
intBlk.ulx = blk.ulx;
intBlk.uly = blk.uly;
intBlk.w = blk.w;
intBlk.h = blk.h;
}
blk = intBlk;
}
float percentage =
(getTileIdx() + (blk.uly + 1.0F) / blk.h) / getNumTiles();
writer.processImageProgressWrapper(percentage * 100.0F);
// If asking a component for the first time for this block, read the 3
// components
if ((barr[c] == null) ||
(dbi.ulx > blk.ulx) || (dbi.uly > blk.uly) ||
(dbi.ulx+dbi.w < blk.ulx+blk.w) ||
(dbi.uly+dbi.h < blk.uly+blk.h)) {
int k,j,i,mi;
// Reset data arrays if needed
if (barr[c] == null || barr[c].length < blk.w*blk.h) {
barr[c] = new int[blk.w*blk.h];
}
blk.setData(barr[c]);
for (i = (c + 1) % nc; i != c; i = (i + 1) % nc)
if (barr[i] == null || barr[i].length < blk.w*blk.h) {
barr[i] = new int[blk.w*blk.h];
}
// set attributes of the DataBlk used for buffering
dbi.ulx = blk.ulx;
dbi.uly = blk.uly;
dbi.w = blk.w;
dbi.h = blk.h;
// get data from the image
if (aTile == null) {
aTile = getTile(co.x, co.y);
Rectangle temp = aTile.getBounds();
aTile = aTile.createTranslatedChild(temp.x-minX,
temp.y-minY);
}
for (i = 0; i < nc ; i++) {
aTile.getSamples(blk.ulx, blk.uly, blk.w, blk.h, i, barr[i]);
for (k = 0; k < barr[i].length; k++)
barr[i][k] -= dcOffset;
}
//getByteData(raster, new Rectangle(blk.ulx, blk.uly, blk.w, blk.h), barr);
// Set buffer attributes
blk.setData(barr[c]);
blk.offset = 0;
blk.scanw = blk.w;
} else { //Asking for the 2nd or 3rd block component
blk.setData(barr[c]);
blk.offset = (blk.ulx-dbi.ulx)*dbi.w+blk.ulx-dbi.ulx;
blk.scanw = dbi.scanw;
}
// Turn off the progressive attribute
blk.progressive = false;
return blk;
}
/**
* Returns, in the blk argument, a block of image data containing the
* specifed rectangular area, in the specified component. The data is
* returned, as a copy of the internal data, therefore the returned data
* can be modified "in place".
*
*
After being read the coefficients are level shifted by subtracting
* 2^(nominal bit range - 1)
*
*
The rectangular area to return is specified by the 'ulx', 'uly', 'w'
* and 'h' members of the 'blk' argument, relative to the current
* tile. These members are not modified by this method. The 'offset' of
* the returned data is 0, and the 'scanw' is the same as the block's
* width. See the 'DataBlk' class.
*
*
If the data array in 'blk' is 'null', then a new one is created. If
* the data array is not 'null' then it is reused, and it must be large
* enough to contain the block's data. Otherwise an 'ArrayStoreException'
* or an 'IndexOutOfBoundsException' is thrown by the Java system.
*
*
The returned data has its 'progressive' attribute unset
* (i.e. false).
*
*
When an I/O exception is encountered the JJ2KExceptionHandler is
* used. The exception is passed to its handleException method. The action
* that is taken depends on the action that has been registered in
* JJ2KExceptionHandler. See JJ2KExceptionHandler for details.
*
* @param blk Its coordinates and dimensions specify the area to
* return. If it contains a non-null data array, then it must have the
* correct dimensions. If it contains a null data array a new one is
* created. The fields in this object are modified to return the data.
*
* @param c The index of the component from which to get the data. Only
* 0,1 and 2 are valid.
*
* @return The requested DataBlk
*
* @see #getInternCompData
*
* @see JJ2KExceptionHandler
* */
public final DataBlk getCompData(DataBlk blk, int c) {
// NOTE: can not directly call getInterCompData since that returns
// internally buffered data.
int ulx,uly,w,h;
// Check type of block provided as an argument
if(blk.getDataType()!=DataBlk.TYPE_INT){
DataBlkInt tmp = new DataBlkInt(blk.ulx,blk.uly,blk.w,blk.h);
blk = tmp;
}
int bakarr[] = (int[])blk.getData();
// Save requested block size
ulx = blk.ulx;
uly = blk.uly;
w = blk.w;
h = blk.h;
// Force internal data buffer to be different from external
blk.setData(null);
getInternCompData(blk,c);
// Copy the data
if (bakarr == null) {
bakarr = new int[w*h];
}
if (blk.offset == 0 && blk.scanw == w) {
// Requested and returned block buffer are the same size
System.arraycopy(blk.getData(),0,bakarr,0,w*h);
}
else { // Requested and returned block are different
for (int i=h-1; i>=0; i--) { // copy line by line
System.arraycopy(blk.getData(),blk.offset+i*blk.scanw,
bakarr,i*w,w);
}
}
blk.setData(bakarr);
blk.offset = 0;
blk.scanw = blk.w;
return blk;
}
/**
* Returns true if the data read was originally signed in the specified
* component, false if not. This method always returns false since PPM
* data is always unsigned.
*
* @param c The index of the component, from 0 to N-1.
*
* @return always false, since PPM data is always unsigned.
* */
public boolean isOrigSigned(int c) {
if (isBinary) return true;
// Check component index
SampleModel sm = null;
if (inputIsRaster)
sm = raster.getSampleModel();
else
sm = src.getSampleModel();
if (sm.getDataType() == DataBuffer.TYPE_USHORT ||
sm.getDataType() == DataBuffer.TYPE_BYTE)
return false;
return true;
}
private int getNumXTiles() {
int x = destinationRegion.x;
int tx = tileXOffset;
int tw = tileWidth;
return ToTile(x + destinationRegion.width - 1, tx, tw) - ToTile(x, tx, tw) + 1;
}
private int getNumYTiles() {
int y = destinationRegion.y;
int ty = tileYOffset;
int th = tileHeight;
return ToTile(y + destinationRegion.height - 1, ty, th) - ToTile(y, ty, th) + 1;
}
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;
}
private Raster getTile(int tileX, int tileY) {
int sx = tileXOffset + tileX * tileWidth;
int sy = tileYOffset + tileY * tileHeight;
tileX += tileXOffset / tileWidth;
tileY += tileYOffset / tileHeight;
if (inputIsRaster) {
if (noTransform) {
return raster.createChild(sx, sy, getTileWidth(), getTileHeight(),
sx, sy, sourceBands);
}
WritableRaster ras =
Raster.createWritableRaster(sm, new Point(sx, sy));
int x = mapToSourceX(sx);
int y = mapToSourceY(sy);
int minY = raster.getMinY();
int maxY = raster.getMinY() + raster.getHeight();
int cTileWidth = getTileWidth();
for (int j = 0; j < getTileHeight(); j++, sy++, y += scaleY) {
if (y < minY || y >= maxY)
continue;
Raster source = raster.createChild(x, y, (cTileWidth - 1) * scaleX + 1, 1,
x, y, null);
int tempX = sx;
for (int i = 0, offset = x; i < cTileWidth; i++, tempX++, offset += scaleX) {
for (int k = 0; k < nc; k++) {
int p = source.getSample(offset, y, sourceBands[k]);
ras.setSample(tempX, sy, k, p);
}
}
}
return ras;
} else {
if (noTransform) {
Raster ras = src.getTile(tileX, tileY);
if (noSubband)
return ras;
else {
return ras.createChild(sx, sy, tileWidth, tileHeight,
sx, sy, sourceBands);
}
}
WritableRaster ras = Raster.createWritableRaster(sm, new Point(sx, sy));
int x = mapToSourceX(sx);
int y = mapToSourceY(sy);
int minY = src.getMinY();
int maxY = src.getMinY() + src.getHeight();
int length = tileWidth * scaleX;
if (x + length >= src.getWidth())
length = src.getWidth() - x;
int dLength = (length + scaleX -1 ) / scaleX;
for (int j = 0; j < tileHeight; j++, sy++, y += scaleY) {
if (y < minY || y >= maxY)
continue;
Raster source = src.getData(new Rectangle(x, y, length, 1));
int tempX = sx;
for (int i = 0, offset = x; i < dLength; i++, tempX++, offset += scaleX) {
for (int k = 0; k < nc; 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;
}
}