com.github.jaiimageio.jpeg2000.impl.J2KReadState Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jai-imageio-jpeg2000 Show documentation
Show all versions of jai-imageio-jpeg2000 Show documentation
JPEG2000 support for Java Advanced Imaging Image I/O Tools API core.
This module is licensed under the [JJ2000 license](LICENSE.txt) and
is therefore NOT compatible with the GPL 3 license. It should be
compatible with the LGPL 2.1 license.
/*
* $RCSfile: J2KReadState.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.8 $
* $Date: 2006/10/03 23:40:14 $
* $State: Exp $
*/
package com.github.jaiimageio.jpeg2000.impl;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Transparency;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.MultiPixelPackedSampleModel;
import java.awt.image.PixelInterleavedSampleModel;
import java.awt.image.Raster;
import java.awt.image.SampleModel;
import java.awt.image.WritableRaster;
import java.io.EOFException;
import java.io.IOException;
import java.util.Hashtable;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.stream.ImageInputStream;
import jj2000.j2k.codestream.HeaderInfo;
import jj2000.j2k.codestream.reader.BitstreamReaderAgent;
import jj2000.j2k.codestream.reader.HeaderDecoder;
import jj2000.j2k.decoder.DecoderSpecs;
import jj2000.j2k.entropy.decoder.EntropyDecoder;
import jj2000.j2k.fileformat.reader.FileFormatReader;
import jj2000.j2k.image.DataBlkInt;
import jj2000.j2k.image.ImgDataConverter;
import jj2000.j2k.image.invcomptransf.InvCompTransf;
import jj2000.j2k.io.RandomAccessIO;
import jj2000.j2k.quantization.dequantizer.Dequantizer;
import jj2000.j2k.roi.ROIDeScaler;
import jj2000.j2k.wavelet.synthesis.InverseWT;
import com.github.jaiimageio.impl.common.ImageUtil;
public class J2KReadState {
/** The input stream we read from */
private ImageInputStream iis = null;
private FileFormatReader ff;
private HeaderInfo hi;
private HeaderDecoder hd;
private RandomAccessIO in;
private BitstreamReaderAgent breader;
private EntropyDecoder entdec;
private ROIDeScaler roids;
private Dequantizer deq;
private InverseWT invWT;
private InvCompTransf ictransf;
private ImgDataConverter converter,converter2;
private DecoderSpecs decSpec = null;
private J2KImageReadParamJava j2krparam = null;
private int[] destinationBands = null;
private int[] sourceBands = null;
private int[] levelShift = null; // level shift for each component
private int[] minValues = null; // The min values
private int[] maxValues = null; // The max values
private int[] fracBits = null; // fractional bits for each component
private DataBlkInt[] dataBlocks = null; // data-blocks to request data from src
private int[] bandOffsets = null;
private int maxDepth = 0;
private boolean isSigned = false;
private ColorModel colorModel = null;
private SampleModel sampleModel = null;
private int nComp = 0;
private int tileWidth = 0;
private int tileHeight = 0;
/** Source to destination transform */
private int scaleX, scaleY, xOffset, yOffset;
private Rectangle destinationRegion = null;
private Point sourceOrigin;
/** Tile grid offsets of the source, also used for destination. */
private int tileXOffset, tileYOffset;
private int width;
private int height;
private int[] pixbuf = null;
private byte[] bytebuf = null;
private int[] channelMap = null;
private boolean noTransform = true;
/** The resolution level requested. */
private int resolution;
/** The subsampling step sizes. */
private int stepX, stepY;
/** Tile step sizes. */
private int tileStepX, tileStepY;
private J2KMetadata metadata;
private BufferedImage destImage;
/** Cache the J2KImageReader
which creates this object. This
* variable is used to monitor the abortion.
*/
private J2KImageReader reader;
/** Constructs J2KReadState
.
* @param iis The input stream.
* @param param The reading parameters.
* @param metadata The J2KMetadata
to cache the metadata read
* from the input stream.
* @param reader The J2KImageReader
which holds this state.
* It is necessary for processing abortion.
* @throw IllegalArgumentException If the provided iis
,
* param
or metadata
is null
.
*/
public J2KReadState(ImageInputStream iis,
J2KImageReadParamJava param,
J2KMetadata metadata,
J2KImageReader reader) {
if (iis == null || param == null || metadata == null)
throw new IllegalArgumentException(I18N.getString("J2KReadState0"));
this.iis = iis;
this.j2krparam = param;
this.metadata = metadata;
this.reader = reader;
initializeRead(0, param, metadata);
}
/** Constructs J2KReadState
.
* @param iis The input stream.
* @param param The reading parameters.
* @param reader The J2KImageReader
which holds this state.
* It is necessary for processing abortion.
* @throw IllegalArgumentException If the provided iis
,
* or param
is null
.
*/
public J2KReadState(ImageInputStream iis,
J2KImageReadParamJava param,
J2KImageReader reader) {
if (iis == null || param == null)
throw new IllegalArgumentException(I18N.getString("J2KReadState0"));
this.iis = iis;
this.j2krparam = param;
this.reader = reader;
initializeRead(0, param, null);
}
public int getWidth() throws IOException {
return width;
}
public int getHeight() throws IOException {
return height;
}
public HeaderDecoder getHeader() {
return hd;
}
public Raster getTile(int tileX, int tileY,
WritableRaster raster) throws IOException {
Point nT = ictransf.getNumTiles(null);
if (noTransform) {
if (tileX >= nT.x || tileY >= nT.y)
throw new IllegalArgumentException(I18N.getString("J2KImageReader0"));
ictransf.setTile(tileX*tileStepX, tileY*tileStepY);
// The offset of the active tiles is the same for all components,
// since we don't support different component dimensions.
int tOffx;
int tOffy;
int cTileWidth;
int cTileHeight;
if(raster != null &&
(this.resolution < hd.getDecoderSpecs().dls.getMin()) ||
stepX != 1 || stepY != 1) {
tOffx = raster.getMinX();
tOffy = raster.getMinY();
cTileWidth = Math.min(raster.getWidth(),
ictransf.getTileWidth());
cTileHeight = Math.min(raster.getHeight(),
ictransf.getTileHeight());
} else {
tOffx = ictransf.getCompULX(0) -
(ictransf.getImgULX() + ictransf.getCompSubsX(0) - 1) /
ictransf.getCompSubsX(0) + destinationRegion.x;
tOffy = ictransf.getCompULY(0)-
(ictransf.getImgULY() + ictransf.getCompSubsY(0) - 1) /
ictransf.getCompSubsY(0) + destinationRegion.y;
cTileWidth = ictransf.getTileWidth();
cTileHeight = ictransf.getTileHeight();
}
if (raster == null)
raster = Raster.createWritableRaster(sampleModel,
new Point(tOffx, tOffy));
int numBands = sampleModel.getNumBands();
if (tOffx + cTileWidth >=
destinationRegion.width + destinationRegion.x)
cTileWidth =
destinationRegion.width + destinationRegion.x - tOffx;
if (tOffy + cTileHeight >=
destinationRegion.height + destinationRegion.y)
cTileHeight =
destinationRegion.height + destinationRegion.y - tOffy;
//create the line buffer for pixel data if it is not large enough
// or null
if (pixbuf == null || pixbuf.length < cTileWidth * numBands)
pixbuf = new int[cTileWidth * numBands];
boolean prog = false;
// Deliver in lines to reduce memory usage
for (int l=0; l < cTileHeight;l++) {
if (reader.getAbortRequest())
break;
// Request line data
for (int i = 0; i < numBands; i++) {
if (reader.getAbortRequest())
break;
DataBlkInt db = dataBlocks[i];
db.ulx = 0;
db.uly = l;
db.w = cTileWidth;
db.h = 1;
ictransf.getInternCompData(db, channelMap[sourceBands[i]]);
prog = prog || db.progressive;
int[] data = db.data;
int k1 = db.offset + cTileWidth - 1;
int fracBit = fracBits[i];
int lS = levelShift[i];
int min = minValues[i];
int max = maxValues[i];
if (ImageUtil.isBinary(sampleModel)) {
// Force min max to 0 and 1.
min = 0;
max = 1;
if (bytebuf == null || bytebuf.length < cTileWidth * numBands)
bytebuf = new byte[cTileWidth * numBands];
for (int j = cTileWidth - 1;
j >= 0; j--) {
int tmp = (data[k1--] >> fracBit) + lS;
bytebuf[j] =
(byte)((tmp < min) ? min :
((tmp > max) ? max : tmp));
}
ImageUtil.setUnpackedBinaryData(bytebuf,
raster,
new Rectangle(tOffx,
tOffy + l,
cTileWidth,
1));
} else {
for (int j = cTileWidth - 1;
j >= 0; j--) {
int tmp = (data[k1--] >> fracBit) + lS;
pixbuf[j] = (tmp < min) ? min :
((tmp > max) ? max : tmp);
}
raster.setSamples(tOffx,
tOffy + l,
cTileWidth,
1,
destinationBands[i],
pixbuf);
}
}
}
} else {
readSubsampledRaster(raster);
}
return raster;
}
public Rectangle getDestinationRegion() {
return destinationRegion;
}
public BufferedImage readBufferedImage() throws IOException {
colorModel = getColorModel();
sampleModel = getSampleModel();
WritableRaster raster = null;
BufferedImage image = j2krparam.getDestination();
int x = destinationRegion.x;
int y = destinationRegion.y;
destinationRegion.setLocation(j2krparam.getDestinationOffset());
if (image == null) {
// If the destination type is specified, use the color model of it.
ImageTypeSpecifier type = j2krparam.getDestinationType();
if (type != null)
colorModel = type.getColorModel();
raster = Raster.createWritableRaster(
sampleModel.createCompatibleSampleModel(destinationRegion.x +
destinationRegion.width,
destinationRegion.y +
destinationRegion.height),
new Point(0, 0));
image = new BufferedImage(colorModel, raster,
colorModel.isAlphaPremultiplied(),
new Hashtable());
} else
raster = image.getWritableTile(0, 0);
destImage = image;
readSubsampledRaster(raster);
destinationRegion.setLocation(x, y);
destImage = null;
return image;
}
public Raster readAsRaster() throws IOException {
BufferedImage image = j2krparam.getDestination();
WritableRaster raster = null;
if (image == null) {
raster = Raster.createWritableRaster(
sampleModel.createCompatibleSampleModel(destinationRegion.x +
destinationRegion.width,
destinationRegion.y +
destinationRegion.height),
new Point(0, 0));
} else
raster = image.getWritableTile(0, 0);
readSubsampledRaster(raster);
return raster;
}
private void initializeRead(int imageIndex, J2KImageReadParamJava param,
J2KMetadata metadata) {
try {
iis.mark();
in = new IISRandomAccessIO(iis);
// **** File Format ****
// If the codestream is wrapped in the jp2 fileformat, Read the
// file format wrapper
ff = new FileFormatReader(in, metadata);
ff.readFileFormat();
in.seek(ff.getFirstCodeStreamPos());
hi = new HeaderInfo();
try{
hd = new HeaderDecoder(in, j2krparam, hi);
} catch(EOFException e){
throw new RuntimeException(I18N.getString("J2KReadState2"));
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
this.width = hd.getImgWidth();
this.height = hd.getImgHeight();
Rectangle sourceRegion = param.getSourceRegion();
sourceOrigin = new Point();
sourceRegion =
new Rectangle(hd.getImgULX(), hd.getImgULY(),
this.width, this.height);
// if the subsample rate for components are not consistent
boolean compConsistent = true;
stepX = hd.getCompSubsX(0);
stepY = hd.getCompSubsY(0);
for (int i = 1; i < nComp; i++) {
if (stepX != hd.getCompSubsX(i) || stepY != hd.getCompSubsY(i))
throw new RuntimeException(I18N.getString("J2KReadState12"));
}
// Get minimum number of resolution levels available across
// all tile-components.
int minResLevels = hd.getDecoderSpecs().dls.getMin();
// Set current resolution level.
this.resolution = param != null ?
param.getResolution() : minResLevels;
if(resolution < 0 || resolution > minResLevels) {
resolution = minResLevels;
}
// Convert source region to lower resolution level.
if(resolution != minResLevels || stepX != 1 || stepY != 1) {
sourceRegion =
J2KImageReader.getReducedRect(sourceRegion, minResLevels,
resolution, stepX, stepY);
}
destinationRegion = (Rectangle)sourceRegion.clone();
J2KImageReader.computeRegionsWrapper(param,
false,
this.width,
this.height,
param.getDestination(),
sourceRegion,
destinationRegion);
sourceOrigin = new Point(sourceRegion.x, sourceRegion.y);
scaleX = param.getSourceXSubsampling();
scaleY = param.getSourceYSubsampling();
xOffset = param.getSubsamplingXOffset();
yOffset = param.getSubsamplingYOffset();
this.width = destinationRegion.width;
this.height = destinationRegion.height;
Point tileOffset = hd.getTilingOrigin(null);
this.tileWidth = hd.getNomTileWidth();
this.tileHeight = hd.getNomTileHeight();
// Convert tile 0 to lower resolution level.
if(resolution != minResLevels || stepX != 1 || stepY != 1) {
Rectangle tileRect = new Rectangle(tileOffset);
tileRect.width = tileWidth;
tileRect.height = tileHeight;
tileRect =
J2KImageReader.getReducedRect(tileRect, minResLevels,
resolution, stepX, stepY);
tileOffset = tileRect.getLocation();
tileWidth = tileRect.width;
tileHeight = tileRect.height;
}
tileXOffset = tileOffset.x;
tileYOffset = tileOffset.y;
// Set the tile step sizes. These values are used because it
// is possible that tiles will be empty. In particular at lower
// resolution levels when subsampling is used this may be the
// case. This method of calculation will work at least for
// Profile-0 images.
if(tileWidth*(1 << (minResLevels - resolution))*stepX >
hd.getNomTileWidth()) {
tileStepX =
(tileWidth*(1 << (minResLevels - resolution))*stepX +
hd.getNomTileWidth() - 1)/hd.getNomTileWidth();
} else {
tileStepX = 1;
}
if(tileHeight*(1 << (minResLevels - resolution))*stepY >
hd.getNomTileHeight()) {
tileStepY =
(tileHeight*(1 << (minResLevels - resolution))*stepY +
hd.getNomTileHeight() - 1)/hd.getNomTileHeight();
} else {
tileStepY = 1;
}
if (!destinationRegion.equals(sourceRegion))
noTransform = false;
// **** Header decoder ****
// Instantiate header decoder and read main header
decSpec = hd.getDecoderSpecs();
// **** Instantiate decoding chain ****
// Get demixed bitdepths
nComp = hd.getNumComps();
int[] depth = new int[nComp];
for (int i=0; i maxDepth)
maxDepth = depth[i];
dataBlocks[i] = new DataBlkInt();
//XXX: may need to change if ChannelDefinition is used to
// define the color channels, such as BGR order
bandOffsets[i] = i;
if (hd.isOriginalSigned(sourceBands[i]))
isSigned = true;
else {
levelShift[i] =
1<<(ictransf.getNomRangeBits(sourceBands[i])-1);
}
// Get the number of bits in the image, and decide what the max
// value should be, depending on whether it is signed or not
int nomRangeBits = ictransf.getNomRangeBits(sourceBands[i]);
maxValues[i] = (1 << (isSigned == true ? (nomRangeBits-1) :
nomRangeBits)) - 1;
minValues[i] = isSigned ? -(maxValues[i]+1) : 0;
fracBits[i] = ictransf.getFixedPoint(sourceBands[i]);
}
iis.reset();
} catch (IllegalArgumentException e){
throw new RuntimeException(e.getMessage(), e);
} catch (Error e) {
if(e.getMessage()!=null)
throw new RuntimeException(e.getMessage(), e);
else {
throw new RuntimeException(I18N.getString("J2KReadState9"), e);
}
} catch (RuntimeException e) {
if(e.getMessage()!=null)
throw new RuntimeException(I18N.getString("J2KReadState10") + " " +
e.getMessage(), e);
else {
throw new RuntimeException(I18N.getString("J2KReadState10"), e);
}
} catch (Throwable e) {
throw new RuntimeException(I18N.getString("J2KReadState10"), e);
}
}
private Raster readSubsampledRaster(WritableRaster raster) throws IOException {
if (raster == null)
raster = Raster.createWritableRaster(
sampleModel.createCompatibleSampleModel(destinationRegion.x +
destinationRegion.width,
destinationRegion.y +
destinationRegion.height),
new Point(destinationRegion.x, destinationRegion.y));
int pixbuf[] = null; // line buffer for pixel data
boolean prog = false; // Flag for progressive data
Point nT = ictransf.getNumTiles(null);
int numBands = sourceBands.length;
Rectangle destRect = raster.getBounds().intersection(destinationRegion);
int offx = destinationRegion.x;
int offy = destinationRegion.y;
int sourceSX = (destRect.x - offx) * scaleX + sourceOrigin.x;
int sourceSY = (destRect.y - offy) * scaleY + sourceOrigin.y;
int sourceEX = (destRect.width - 1)* scaleX + sourceSX;
int sourceEY = (destRect.height - 1) * scaleY + sourceSY;
int startXTile = (sourceSX - tileXOffset) / tileWidth;
int startYTile = (sourceSY - tileYOffset) / tileHeight;
int endXTile = (sourceEX - tileXOffset) / tileWidth;
int endYTile = (sourceEY - tileYOffset) / tileHeight;
startXTile = clip(startXTile, 0, nT.x - 1);
startYTile = clip(startYTile, 0, nT.y - 1);
endXTile = clip(endXTile, 0, nT.x - 1);
endYTile = clip(endYTile, 0, nT.y - 1);
int totalXTiles = endXTile - startXTile + 1;
int totalYTiles = endYTile - startYTile + 1;
int totalTiles = totalXTiles * totalYTiles;
// Start the data delivery to the cached consumers tile by tile
for(int y=startYTile; y <= endYTile; y++){
if (reader.getAbortRequest())
break;
// Loop on horizontal tiles
for(int x=startXTile; x <= endXTile; x++){
if (reader.getAbortRequest())
break;
float initialFraction =
(x - startXTile + (y - startYTile)*totalXTiles)/totalTiles;
ictransf.setTile(x*tileStepX,y*tileStepY);
int sx = hd.getCompSubsX(0);
int cTileWidth = (ictransf.getTileWidth() + sx - 1)/sx;
int sy = hd.getCompSubsY(0);
int cTileHeight = (ictransf.getTileHeight() + sy - 1)/sy;
// Offsets within the tile.
int tx = 0;
int ty = 0;
// The region for this tile
int startX = tileXOffset + x * tileWidth;
int startY = tileYOffset + y * tileHeight;
// sourceSX is guaranteed to be >= startX
if (sourceSX > startX) {
if(startX >= hd.getImgULX()) {
tx = sourceSX - startX; // Intra-tile offset.
cTileWidth -= tx; // Reduce effective width.
}
startX = sourceSX; // Absolute position.
}
// sourceSY is guaranteed to be >= startY
if (sourceSY > startY) {
if(startY >= hd.getImgULY()) {
ty = sourceSY - startY; // Intra-tile offset.
cTileHeight -= ty; // Reduce effective width.
}
startY = sourceSY; // Absolute position.
}
// Decrement dimensions if end position is within tile.
if (sourceEX < startX + cTileWidth - 1) {
cTileWidth += sourceEX - startX - cTileWidth + 1;
}
if (sourceEY < startY + cTileHeight - 1) {
cTileHeight += sourceEY - startY - cTileHeight + 1;
}
// The start X in the destination
int x1 = (startX + scaleX - 1 - sourceOrigin.x) / scaleX;
int x2 = (startX + scaleX -1 + cTileWidth - sourceOrigin.x) /
scaleX;
int lineLength = x2 - x1;
if (pixbuf == null || pixbuf.length < lineLength)
pixbuf = new int[lineLength]; // line buffer for pixel data
x2 = (x2 - 1) * scaleX + sourceOrigin.x - startX;
int y1 = (startY + scaleY -1 - sourceOrigin.y) /scaleY;
x1 += offx;
y1 += offy;
// Deliver in lines to reduce memory usage
for (int l = ty, m = y1;
l < ty + cTileHeight;
l += scaleY, m++) {
if (reader.getAbortRequest())
break;
// Request line data
for (int i = 0; i < numBands; i++) {
DataBlkInt db = dataBlocks[i];
db.ulx = tx;
db.uly = l;
db.w = cTileWidth;
db.h = 1;
ictransf.getInternCompData(db, channelMap[sourceBands[i]]);
prog = prog || db.progressive;
int[] data = db.data;
int k1 = db.offset + x2;
int fracBit = fracBits[i];
int lS = levelShift[i];
int min = minValues[i];
int max = maxValues[i];
if (ImageUtil.isBinary(sampleModel)) {
// Force min max to 0 and 1.
min = 0;
max = 1;
if (bytebuf == null || bytebuf.length < cTileWidth * numBands)
bytebuf = new byte[cTileWidth * numBands];
for (int j = lineLength - 1; j >= 0; j--, k1-=scaleX) {
int tmp = (data[k1] >> fracBit) + lS;
bytebuf[j] =
(byte)((tmp < min) ? min :
((tmp > max) ? max : tmp));
}
ImageUtil.setUnpackedBinaryData(bytebuf,
raster,
new Rectangle(x1,
m,
lineLength,
1));
} else {
for (int j = lineLength - 1; j >= 0; j--, k1-=scaleX) {
int tmp = (data[k1] >> fracBit) + lS;
pixbuf[j] = (tmp < min) ? min :
((tmp > max) ? max : tmp);
}
// Send the line data to the BufferedImage
raster.setSamples(x1,
m,
lineLength,
1,
destinationBands[i],
pixbuf);
}
}
if (destImage != null)
reader.processImageUpdateWrapper(destImage, x1, m,
cTileWidth, 1, 1, 1,
destinationBands);
float fraction = initialFraction +
(l - ty + 1.0F)/cTileHeight/totalTiles;
reader.processImageProgressWrapper(100.0f*fraction);
}
} // End loop on horizontal tiles
} // End loop on vertical tiles
return raster;
}
public ImageTypeSpecifier getImageType()
throws IOException {
getSampleModel();
getColorModel();
return new ImageTypeSpecifier(colorModel, sampleModel);
}
public SampleModel getSampleModel() {
if (sampleModel != null)
return sampleModel;
if (nComp == 1 && (maxDepth == 1 || maxDepth == 2 || maxDepth == 4))
sampleModel =
new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE,
tileWidth,
tileHeight,
maxDepth);
else if (maxDepth <= 8)
sampleModel =
new PixelInterleavedSampleModel(DataBuffer.TYPE_BYTE,
tileWidth,
tileHeight,
nComp,
tileWidth * nComp,
bandOffsets);
else if (maxDepth <=16)
sampleModel =
new PixelInterleavedSampleModel(isSigned ?
DataBuffer.TYPE_SHORT :
DataBuffer.TYPE_USHORT,
tileWidth, tileHeight,
nComp,
tileWidth * nComp,
bandOffsets);
else if (maxDepth <= 32)
sampleModel =
new PixelInterleavedSampleModel(DataBuffer.TYPE_INT,
tileWidth,
tileHeight,
nComp,
tileWidth * nComp,
bandOffsets);
else
throw new IllegalArgumentException(I18N.getString("J2KReadState11") + " " +
+ maxDepth);
return sampleModel;
}
public ColorModel getColorModel() {
if (colorModel != null)
return colorModel;
// Attempt to get the ColorModel from the JP2 boxes.
colorModel = ff.getColorModel();
if (colorModel != null)
return colorModel;
if(hi.siz.csiz <= 4) {
// XXX: Code essentially duplicated from FileFormatReader.getColorModel().
// Create the ColorModel from the SIZ marker segment parameters.
ColorSpace cs;
if(hi.siz.csiz > 2) {
cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
} else {
cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
}
int[] bitsPerComponent = new int[hi.siz.csiz];
boolean isSigned = false;
int maxBitDepth = -1;
for(int i = 0; i < hi.siz.csiz; i++) {
bitsPerComponent[i] = hi.siz.getOrigBitDepth(i);
if(maxBitDepth < bitsPerComponent[i]) {
maxBitDepth = bitsPerComponent[i];
}
isSigned |= hi.siz.isOrigSigned(i);
}
boolean hasAlpha = hi.siz.csiz % 2 == 0;
int type = -1;
if (maxBitDepth <= 8) {
type = DataBuffer.TYPE_BYTE;
} else if (maxBitDepth <= 16) {
type = isSigned ? DataBuffer.TYPE_SHORT : DataBuffer.TYPE_USHORT;
} else if (maxBitDepth <= 32) {
type = DataBuffer.TYPE_INT;
}
if (type != -1) {
if(hi.siz.csiz == 1 &&
(maxBitDepth == 1 || maxBitDepth == 2 || maxBitDepth == 4)) {
colorModel = ImageUtil.createColorModel(getSampleModel());
} else {
colorModel = new ComponentColorModel(cs,
bitsPerComponent,
hasAlpha,
false,
hasAlpha ?
Transparency.TRANSLUCENT :
Transparency.OPAQUE ,
type);
}
return colorModel;
}
}
if(sampleModel == null) {
sampleModel = getSampleModel();
}
if (sampleModel == null)
return null;
return ImageUtil.createColorModel(null, sampleModel);
}
/**
* Returns the bounding rectangle of the upper left tile at
* the current resolution level.
*/
Rectangle getTile0Rect() {
return new Rectangle(tileXOffset, tileYOffset, tileWidth, tileHeight);
}
private int clip(int value, int min, int max) {
if (value < min)
value = min;
if (value > max)
value = max;
return value;
}
private void clipDestination(Rectangle dest) {
Point offset = j2krparam.getDestinationOffset();
if (dest.x < offset.x) {
dest.width += dest.x - offset.x;
dest.x = offset.x ;
}
if (dest.y < offset.y) {
dest.height += dest.y - offset.y;
dest.y = offset.y ;
}
}
}