/*
* $RCSfile: RasterFormatTag.java,v $
*
* Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
*
* Use is subject to license terms.
*
* $Revision: 1.1 $
* $Date: 2005/02/11 04:57:18 $
* $State: Exp $
*/
package com.lightcrafts.mediax.jai;
import java.awt.image.SampleModel;
import java.awt.image.ComponentSampleModel;
/**
* This class encapsulates the information needed for
* RasterAccessor to understand how a Raster is laid out. It's
* designed so that one RasterFormatTag can be constructed per
* source and that RasterFormatTag can cache information that
* the RasterAccessor would otherwise have to extract from the
* Raster each time it's constructed (generally each time
* OpImage.computeRect() is called.) Additionally, it can
* cache various arrays (i.e. bankIndices[] and bandOffsets[])
* that would otherwise be cloned everytime they were requested.
*
* Because of the way SampleModel.createCompatibleSampleModel()
* is designed not all fields of a particular SampleModel will
* match those of the SampleModel returned by
* SampleModel.createCompatibleSampleModel(). Values like
* pixelStride and numBands won't change, but values like
* bankIndicies[] and bandOffsets[] might if the underlying
* Raster is not pixelSequential. Rasters which are pixelSequential
* meet the following conditions 1) The SampleModel is a
* ComponentSampleModel. 2) The pixelStride is equal to the number
* of bands. 3) All the bankIndices[] are equal. 4) All the
* bandOffsets[] values are less than pixelStride 5) No two
* bandOffsets[] values are equal. For that reason,
* RasterFormatTags representing non pixelSequential rasters don't
* attempt to cache the bandOffsets[] or bankIndices[]. For such
* rasters, this information should be taken directly from the
* raster itself. Note that any RasterFormatTag that will cause
* data to be copied from the Raster will be pixelSequential as that
* is the format in which data is returned from Raster.getPixels()
* returns.
*
*/
public final class RasterFormatTag {
private static final int COPY_MASK = RasterAccessor.COPY_MASK;
private static final int UNCOPIED = RasterAccessor.UNCOPIED;
private static final int COPIED = RasterAccessor.COPIED;
private int formatTagID;
private int bankIndices[];
private int numBands;
private int bandOffsets[];
private int pixelStride;
private boolean isPixelSequential;
/**
* Constructs a RasterFormatTag given a sampleModel and a
* formatTagID. Generally, this constructor is called by
* RasterAccessor.findCompatibleTags(RenderedImage[] srcs,
* RenderedImage dst) and it takes care of setting the values
* correctly. In special cases, OpImages need to construct
* a RasterFormatTag without creating a RenderedImage. In this
* case a RasterFormatTag can be created using a formatTagID
* returned from
* RasterAccessor.findCompatibleTag(SampleModel[] srcs, SampleModel dst)
* and a sampleModel that was either passed in to the
* findCompatibleTag() call or one that was created using
* createCompatibleSampleModel() on one of the passed in
* SampleModels. Attempting to use arbitrary SampleModels
* with arbitrary formatTagIDs has undefined results.
*
* param sampleModel A <code>SampleModel</code> for the RasterFormagTag
* param formatTagID An <code>int</code> to indicate format tag id
*
*/
public RasterFormatTag(SampleModel sampleModel, int formatTagID) {
this.formatTagID = formatTagID;
if ((formatTagID & COPY_MASK) == UNCOPIED) {
ComponentSampleModel csm =
(ComponentSampleModel)sampleModel;
this.bankIndices = csm.getBankIndices();
this.numBands = csm.getNumDataElements();
this.bandOffsets = csm.getBandOffsets();
this.pixelStride = csm.getPixelStride();
if (pixelStride != bandOffsets.length) {
isPixelSequential = false;
} else {
isPixelSequential = true;
for (int i = 0; i < bandOffsets.length; i++) {
if (bandOffsets[i] >= pixelStride ||
bankIndices[i] != bankIndices[0]) {
isPixelSequential = false;
}
for (int j = i+1; j < bandOffsets.length; j++) {
if (bandOffsets[i] == bandOffsets[j]) {
isPixelSequential = false;
}
}
if (!isPixelSequential) break;
}
}
} else if ((formatTagID & COPY_MASK) == COPIED) {
numBands = sampleModel.getNumBands();
bandOffsets = new int[numBands];
pixelStride = numBands;
bankIndices = new int[numBands];
for (int i = 0; i < numBands; i++) {
bandOffsets[i] = i;
bankIndices[i] = 0;
}
isPixelSequential = true;
}
}
/**
* Returns whether or not the SampleModel represented by the
* RasterFormatTag is PixelSequential.
* Note that RasterFormatTag's that indicate
* data should be copied out of the Raster by the RasterAccessor
* will always return true for isPixelSequential().
* RasterFormatTags that indicate no copying is needed will only
* return true, if 1) The SampleModel is a ComponentSampleModel.
* 2) The pixelStride is equal to the number of bands.
* 3) All the bankIndices[] are equal. 4) All the bandOffsets[]
* values are less than pixelStride 5) No two bandOffset values
* are equal.
*/
public final boolean isPixelSequential() {
return isPixelSequential;
}
/**
* Returns the FormatTagID used to construct this RasterFormatTag.
* Valid values are defined in com.lightcrafts.mediax.jai.RasterAccessor.
*/
public final int getFormatTagID() {
return formatTagID;
}
/**
* Returns the bankIndices for the Raster if isPixelSequential()
* is true. Returns null otherwise. In the COPIED case, the
* bankIndices will all be 0.
*/
public final int[] getBankIndices() {
if (isPixelSequential) {
return bankIndices;
} else {
return null;
}
}
/** Returns the number of bands in the underlying Raster */
public final int getNumBands() {
return numBands;
}
/**
* Returns the bandOffsets for the Raster if isPixelSequential() is
* true. Returns null otherwise. In the COPIED case, bankIndices
* will be numBands sequential integers starting with 0.
*/
public final int[] getBandOffsets() {
if (isPixelSequential) {
return bandOffsets;
} else {
return null;
}
}
/** Returns the pixelStride of the underlying Raster */
public final int getPixelStride() {
return pixelStride;
}
}