PlanarImage[] alphaChannels = null;
//
// IndexColorModel
//
final ImageWorker worker = new ImageWorker(image);
final int transparencyType=cm.getTransparency();
// in case of index color model we try to preserve it, so that output
// formats that can work with it can enjoy its extra compactness
if (cm instanceof IndexColorModel) {
IndexColorModel icm = (IndexColorModel) cm;
// try to find the index that matches the requested background color
final int bgColorIndex;
if(transparent) {
bgColorIndex = icm.getTransparentPixel();
} else {
if(icm.hasAlpha() && icm.isAlphaPremultiplied()) {
// uncommon case that we don't have the code to handle directly
bgColorIndex = -1;
} else {
if(icm.getTransparency() != Transparency.OPAQUE) {
// we have a translucent image, so the bg color needs to be merged into
// the palette
icm = ColorUtilities.applyBackgroundColor(icm, bgColor);
cm = icm;
ImageLayout ilColorModel = new ImageLayout(image);
ilColorModel.setColorModel(icm);
RenderingHints hints = new RenderingHints(JAI.KEY_IMAGE_LAYOUT, ilColorModel);
image = FormatDescriptor.create(image, image.getSampleModel().getDataType(), hints);
worker.setImage(image);
}
bgColorIndex = ColorUtilities.findColorIndex(bgColor, icm);
}
}
// we did not find the background color, well we have to expand to RGB and then tell Mosaic to use the RGB(A) color as the
// background
if (bgColorIndex == -1) {
// we need to expand the image to RGB
image = worker.forceComponentColorModel().getRenderedImage();
if(transparent) {
image = addAlphaChannel(image);
worker.setImage(image);
}
bgValues = new double[] { bgColor.getRed(), bgColor.getGreen(), bgColor.getBlue(),
transparent ? 0 : 255 };
cm = image.getColorModel();
} else {
// we found the background color in the original image palette therefore we set its index as the bkg value.
// The final Mosaic will use the IndexColorModel of this image anywa, therefore all we need to do is to force
// the background to point to the right color in the palette
bgValues = new double[] { bgColorIndex };
}
// collect alpha channels if we have them in order to reuse them later on for mosaic operation
if (cm.hasAlpha() && bgColorIndex == -1) {
worker.forceComponentColorModel();
final RenderedImage alpha = worker.retainLastBand().getRenderedImage();
alphaChannels = new PlanarImage[] { PlanarImage.wrapRenderedImage(alpha) };
}
}
//
// ComponentColorModel
//
// in case of component color model
if (cm instanceof ComponentColorModel) {
// convert to RGB if necessary
ComponentColorModel ccm = (ComponentColorModel) cm;
boolean hasAlpha = cm.hasAlpha();
// if we have a grayscale image see if we have to expand to RGB
if (ccm.getNumColorComponents() == 1) {
if((!isLevelOfGray(bgColor) && !transparent) || (ccm.getTransferType() == DataBuffer.TYPE_DOUBLE ||
ccm.getTransferType() == DataBuffer.TYPE_FLOAT
|| ccm.getTransferType() == DataBuffer.TYPE_UNDEFINED)) {
// expand to RGB, this is not a case we can optimize
final ImageWorker iw = new ImageWorker(image);
if (hasAlpha) {
final RenderedImage alpha = iw.retainLastBand().getRenderedImage();
// get first band
final RenderedImage gray = new ImageWorker(image).retainFirstBand()
.getRenderedImage();
image = new ImageWorker(gray).bandMerge(3).addBand(alpha, false)
.forceComponentColorModel().forceColorSpaceRGB().getRenderedImage();
} else {
image = iw.bandMerge(3).forceComponentColorModel().forceColorSpaceRGB()
.getRenderedImage();
}
} else if(!hasAlpha) {
// no transparency in the original data, so no need to expand to RGB
if(transparent) {
// we need to expand the image with an alpha channel
image = addAlphaChannel(image);
bgValues = new double[] { mapToGrayColor(bgColor, ccm), 0 };
} else {
bgValues = new double[] { mapToGrayColor(bgColor, ccm) };
}
} else {
// extract the alpha channel
final ImageWorker iw = new ImageWorker(image);
final RenderedImage alpha = iw.retainLastBand().getRenderedImage();
alphaChannels = new PlanarImage[] { PlanarImage.wrapRenderedImage(alpha) };
if (transparent) {
bgValues = new double[] { mapToGrayColor(bgColor, ccm), 0 };
} else {
bgValues = new double[] { mapToGrayColor(bgColor, ccm), 255 };
}
}
// get back the ColorModel
cm = image.getColorModel();
ccm = (ComponentColorModel) cm;
hasAlpha = cm.hasAlpha();
}
if(bgValues == null) {
if (hasAlpha) {
// get alpha
final ImageWorker iw = new ImageWorker(image);
final RenderedImage alpha = iw.retainLastBand().getRenderedImage();
alphaChannels = new PlanarImage[] { PlanarImage.wrapRenderedImage(alpha) };
if (transparent) {
bgValues = new double[] { bgColor.getRed(), bgColor.getGreen(),
bgColor.getBlue(), 0 };
} else {
bgValues = new double[] { bgColor.getRed(), bgColor.getGreen(),
bgColor.getBlue(), 255 };
}
} else {
if (transparent) {
image = addAlphaChannel(image);
// this will work fine for all situation where the color components are <= 3
// e.g., one band rasters with no colormap will have only one usually
bgValues = new double[] { 0, 0, 0, 0 };
} else {
// TODO: handle the case where the component color model is not RGB
// We cannot use ImageWorker as is because it basically seems to assume
// component -> 3 band in forceComponentColorModel()
// but I guess we'll need to turn the image into a 3 band RGB one.
bgValues = new double[] { bgColor.getRed(), bgColor.getGreen(),
bgColor.getBlue() };
}
}
}
}
//
// If we need to add a collar use mosaic or if we need to blend/apply a bkg color
if(!(imageBounds.contains(mapRasterArea) || imageBounds.equals(mapRasterArea))||transparencyType!=Transparency.OPAQUE) {
ROI[] rois = new ROI[] { new ROIShape(imageBounds) };
// build the transparency thresholds
double[][] thresholds = new double[][] { { ColorUtilities.getThreshold(image
.getSampleModel().getDataType()) } };
// apply the mosaic
image = MosaicDescriptor.create(new RenderedImage[] { image },
alphaChannels != null && transparencyType==Transparency.TRANSLUCENT ? MosaicDescriptor.MOSAIC_TYPE_BLEND: MosaicDescriptor.MOSAIC_TYPE_OVERLAY,
alphaChannels, rois, thresholds, bgValues, new RenderingHints(
JAI.KEY_IMAGE_LAYOUT, layout));
} else {
// Check if we need to crop a subset of the produced image, else return it right away
if (imageBounds.contains(mapRasterArea) && !imageBounds.equals(mapRasterArea)) { // the produced image does not need a final mosaicking operation but a crop!
ImageWorker iw = new ImageWorker(image);
iw.crop(0, 0, mapWidth, mapHeight);
image = iw.getRenderedImage();
}
}
return image;
}