* "Lookup operation not allowed".
*/
boolean isIdentity = true;
MathTransform1D[] transforms = new MathTransform1D[numBands];
for (int i=0; i<numBands; i++) {
MathTransform1D transform = nativeBands[i].getSampleToGeophysics();
if (transform!=null && !toGeo) try {
transform = transform.inverse(); // We want the geophysics to native transform.
} catch (NoninvertibleTransformException e) {
transform = null;
isIdentity = false;
}
transforms[i] = transform;
isIdentity &= transform.isIdentity();
}
if (isIdentity) {
return coverage;
}
/*
* STEP 2 - Computes the layout for the destination RenderedImage. We will use the same
* layout than the parent image, except for tile size if the parent image had
* only one big tile, and for the color model and sample model (since we are
* reformating data in the process of this operation).
*/
ImageLayout layout = ImageUtilities.getImageLayout(image);
ColorModel colors = targetBands[visibleBand].getColorModel(visibleBand, numBands);
SampleModel targetModel = colors.createCompatibleSampleModel(
layout.getTileWidth(image), layout.getTileHeight(image));
if (colors instanceof IndexColorModel && targetModel.getClass().equals(ComponentSampleModel.class)) {
// TODO: There is the 'IndexColorModel' hack (see method description).
// Consider removing this hack when we will target Java 6.
final int w = targetModel.getWidth();
final int h = targetModel.getHeight();
targetModel = new PixelInterleavedSampleModel(colors.getTransferType(), w,h,1,w, new int[1]);
}
layout = layout.setSampleModel(targetModel).setColorModel(colors);
ParameterBlock param = new ParameterBlock().addSource(image);
RenderingHints hints = new RenderingHints(JAI.KEY_IMAGE_LAYOUT, layout);
hints.put(JAI.KEY_REPLACE_INDEX_COLOR_MODEL, Boolean.FALSE);
hints.put(JAI.KEY_TRANSFORM_ON_COLORMAP, Boolean.FALSE);
String operation = null; // Will be set in step 3 or 4.
/*
* STEP 3 - Checks if the transcoding could be done with the JAI's "Lookup" operation. This
* is probably the fastest operation available for going to the geophysics view.
* Note that the transforms array may contains null elements, which will cause
* LookupTableFactory.create(...) to returns null.
*/
if (transforms != null) try {
final int sourceType = sourceModel.getDataType();
final int targetType = targetModel.getDataType();
LookupTableJAI table = LookupTableFactory.create(sourceType, targetType, transforms);
if (table != null) {
operation = "Lookup";
param = param.add(table);
}
} catch (TransformException exception) {
/*
* A value can't be transformed. Fallback on "Rescale" or "Piecewise" operations. We
* don't log yet because the more general operations are likely to fail for the same
* reason and we don't want to log the same TransformException twice.
*/
}
/*
* STEP 4 - Check if the transcoding could be done with a JAI's "Rescale" or "Piecewise"
* operations. The "Rescale" operation requires a completly linear relationship
* between the source and the destination sample values. The "Piecewise" operation
* is less strict: piecewise breakpoints are very similar to categories, but the
* transformation for all categories still have to be linear.
*/
if (operation == null) try {
boolean canRescale = true; // 'true' if the "Rescale" operation can be applied.
boolean canPiecewise = true; // 'true' if the "Piecewise" operation can be applied.
boolean conditional = false;// 'true' if isZeroExcluded(...) needs to be invoked.
double[] scales = null; // The first argument for "Rescale".
double[] offsets = null; // The second argument for "Rescale".
float[][][] breakpoints = null; // The only argument for "Piecewise".
testLinear: for (int i=0; i<numBands; i++) {
final List<Category> sources = sourceBands[i].getCategories();
final int numCategories = sources.size();
float[] sourceBreakpoints = null;
float[] targetBreakpoints = null;
double expectedSource = Double.NaN;
double expectedTarget = Double.NaN;
int jbp = 0; // Break point index (vary with j)
for (int j=0; j<numCategories; j++) {
final Category sourceCategory = sources.get(j);
final Category packedCategory = sourceCategory.geophysics(false);
MathTransform1D transform = packedCategory.getSampleToGeophysics();
final double offset, scale;
if (transform == null) {
/*
* A qualitative category was found. Those categories maps NaN values,
* which need the special processing performed by our "SampleTranscode"
* operation. However there is a few special cases where JAI operations
* could still fit:
*
* - In "packed to geophysics" transform, we can still use "Piecewise"
* if the minimum and maximum target value are equals (usually NaN).
*
* - In "geophysics to packed" transform, we can still use "Rescale"
* if the NaN value maps to 0.
*/
if (toGeo) {
canRescale = false;
final NumberRange target = sourceCategory.geophysics(true).getRange();
offset = target.getMinimum();
if (Double.doubleToRawLongBits(offset) != Double.doubleToRawLongBits(target.getMaximum())) {
canPiecewise = false;
break testLinear;
}
scale = 0;
} else {
canPiecewise = false;
assert !packedCategory.equals(sourceCategory) : packedCategory;
final NumberRange range = packedCategory.getRange();
if (range.getMinimum(true) == 0 && range.getMaximum(true) == 0) {
assert isNaN(sourceCategory.getRange().getMinimum()) : sourceCategory;
conditional = true;
continue;
}
canRescale = false;
break testLinear;
}
} else {
if (!toGeo) {
// We are going to convert geophysics values to packed ones.
transform = transform.inverse();
}
offset = transform.transform(0);
scale = transform.derivative(Double.NaN);
if (isNaN(scale) || isNaN(offset)) {
// One category doesn't use a linear transformation. We can't deal with
// that with "Rescale" or "Piecewise". Fallback on our "SampleTranscode".
canRescale = false;
canPiecewise = false;