/*
* $RCSfile: BandCombineOpImage.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:56:15 $
* $State: Exp $
*/
package com.lightcrafts.media.jai.opimage;
import java.awt.Rectangle;
import java.awt.image.DataBuffer;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.awt.image.WritableRaster;
import java.util.Map;
import com.lightcrafts.mediax.jai.ImageLayout;
import com.lightcrafts.mediax.jai.PointOpImage;
import com.lightcrafts.mediax.jai.RasterAccessor;
import com.lightcrafts.mediax.jai.RasterFormatTag;
import com.lightcrafts.mediax.jai.RasterFactory;
import com.lightcrafts.media.jai.util.ImageUtil;
import com.lightcrafts.media.jai.util.JDKWorkarounds;
/**
* An <code>OpImage</code> implementing the "BandCombine" operation.
*
* <p>This <code>OpImage</code> performs the arbitrary interband
* linear combination of an image using the specified matrix. The
* width of the matrix must be one larger that the number of bands
* in the source image. The height of the matrix must be equal to
* the number of bands in the destination image. Because the matrix
* can be of arbitrary size, this function can be used to produce
* a destination image with a different number of bands from the
* source image.
* <p>The destination image is formed by performing a matrix-
* multiply operation between the bands of the source image and
* the specified matrix. The extra column of values is a constant
* that is added after the matrix-multiply operation takes place.
*
* @see com.lightcrafts.mediax.jai.operator.BandCombineDescriptor
* @see BandCombineCRIF
*
*
* @since EA3
*/
final class BandCombineOpImage extends PointOpImage {
private double[][] matrix;
/**
* Constructor.
*
* @param source The source image.
* @param layout The destination image layout.
* @param matrix The matrix of values used to perform the
* linear combination.
*/
public BandCombineOpImage(RenderedImage source,
Map config,
ImageLayout layout,
double[][] matrix) {
super(source, layout, config, true);
this.matrix = matrix;
int numBands = matrix.length; // matrix height is dst numBands
if (getSampleModel().getNumBands() != numBands) {
sampleModel = RasterFactory.createComponentSampleModel(sampleModel,
sampleModel.getDataType(),
tileWidth, tileHeight, numBands);
if(colorModel != null &&
!JDKWorkarounds.areCompatibleDataModels(sampleModel,
colorModel)) {
colorModel = ImageUtil.getCompatibleColorModel(sampleModel,
config);
}
}
}
/**
* Performs linear combination of source image with matrix
*
* @param sources Cobbled sources, guaranteed to provide all the
* source data necessary for computing the rectangle.
* @param dest The tile containing the rectangle to be computed.
* @param destRect The rectangle within the tile to be computed.
*/
protected void computeRect(Raster[] sources,
WritableRaster dest,
Rectangle destRect) {
// Retrieve format tags.
RasterFormatTag[] formatTags = getFormatTags();
RasterAccessor s = new RasterAccessor(sources[0], destRect,
formatTags[0],
getSourceImage(0).getColorModel());
RasterAccessor d = new RasterAccessor(dest, destRect,
formatTags[1], getColorModel());
switch (d.getDataType()) {
case DataBuffer.TYPE_BYTE:
computeRectByte(s, d);
break;
case DataBuffer.TYPE_USHORT:
computeRectUShort(s, d);
break;
case DataBuffer.TYPE_SHORT:
computeRectShort(s, d);
break;
case DataBuffer.TYPE_INT:
computeRectInt(s, d);
break;
case DataBuffer.TYPE_FLOAT:
computeRectFloat(s, d);
break;
case DataBuffer.TYPE_DOUBLE:
computeRectDouble(s, d);
break;
}
if (d.isDataCopy()) {
d.clampDataArrays();
d.copyDataToRaster();
}
}
private void computeRectByte(RasterAccessor src, RasterAccessor dst) {
int sLineStride = src.getScanlineStride();
int sPixelStride = src.getPixelStride();
int sbands = src.getNumBands();
int[] sBandOffsets = src.getBandOffsets();
byte[][] sData = src.getByteDataArrays();
int dwidth = dst.getWidth();
int dheight = dst.getHeight();
int dbands = dst.getNumBands();
int dLineStride = dst.getScanlineStride();
int dPixelStride = dst.getPixelStride();
int[] dBandOffsets = dst.getBandOffsets();
byte[][] dData = dst.getByteDataArrays();
int sso = 0, dso = 0;
for (int h = 0; h < dheight; h++) {
int spo = sso;
int dpo = dso;
for (int w = 0; w < dwidth; w++) {
for (int b = 0; b < dbands; b++) {
float sum = 0.0F;
double[] mat = matrix[b];
for (int k = 0; k < sbands; k++ ) {
sum += (float)mat[k] *
(float)(sData[k][spo+sBandOffsets[k]] & 0xFF);
}
dData[b][dpo+dBandOffsets[b]] = ImageUtil.clampRoundByte(sum + (float)mat[sbands]);
}
spo += sPixelStride;
dpo += dPixelStride;
}
sso += sLineStride;
dso += dLineStride;
}
}
private void computeRectUShort(RasterAccessor src, RasterAccessor dst) {
int sLineStride = src.getScanlineStride();
int sPixelStride = src.getPixelStride();
int sbands = src.getNumBands();
int[] sBandOffsets = src.getBandOffsets();
short[][] sData = src.getShortDataArrays();
int dwidth = dst.getWidth();
int dheight = dst.getHeight();
int dbands = dst.getNumBands();
int dLineStride = dst.getScanlineStride();
int dPixelStride = dst.getPixelStride();
int[] dBandOffsets = dst.getBandOffsets();
short[][] dData = dst.getShortDataArrays();
int sso = 0, dso = 0;
for (int h = 0; h < dheight; h++) {
int spo = sso;
int dpo = dso;
for (int w = 0; w < dwidth; w++) {
for (int b = 0; b < dbands; b++) {
float sum = 0.0F;
double[] mat = matrix[b];
for (int k = 0; k < sbands; k++ ) {
sum += (float)mat[k] *
(float)(sData[k][spo+sBandOffsets[k]] & 0xFFFF);
}
dData[b][dpo+dBandOffsets[b]] = ImageUtil.clampRoundUShort(sum + (float)matrix[b][sbands]);
}
spo += sPixelStride;
dpo += dPixelStride;
}
sso += sLineStride;
dso += dLineStride;
}
}
private void computeRectShort(RasterAccessor src, RasterAccessor dst) {
int sLineStride = src.getScanlineStride();
int sPixelStride = src.getPixelStride();
int sbands = src.getNumBands();
int[] sBandOffsets = src.getBandOffsets();
short[][] sData = src.getShortDataArrays();
int dwidth = dst.getWidth();
int dheight = dst.getHeight();
int dbands = dst.getNumBands();
int dLineStride = dst.getScanlineStride();
int dPixelStride = dst.getPixelStride();
int[] dBandOffsets = dst.getBandOffsets();
short[][] dData = dst.getShortDataArrays();
int sso = 0, dso = 0;
for (int h = 0; h < dheight; h++) {
int spo = sso;
int dpo = dso;
for (int w = 0; w < dwidth; w++) {
for (int b = 0; b < dbands; b++) {
float sum = 0.0F;
double[] mat = matrix[b];
for (int k = 0; k < sbands; k++ ) {
sum += (float)mat[k] *
(float)(sData[k][spo+sBandOffsets[k]]);
}
dData[b][dpo+dBandOffsets[b]] = ImageUtil.clampRoundUShort(sum + (float)matrix[b][sbands]);
}
spo += sPixelStride;
dpo += dPixelStride;
}
sso += sLineStride;
dso += dLineStride;
}
}
private void computeRectInt(RasterAccessor src, RasterAccessor dst) {
int sLineStride = src.getScanlineStride();
int sPixelStride = src.getPixelStride();
int sbands = src.getNumBands();
int[] sBandOffsets = src.getBandOffsets();
int[][] sData = src.getIntDataArrays();
int dwidth = dst.getWidth();
int dheight = dst.getHeight();
int dbands = dst.getNumBands();
int dLineStride = dst.getScanlineStride();
int dPixelStride = dst.getPixelStride();
int[] dBandOffsets = dst.getBandOffsets();
int[][] dData = dst.getIntDataArrays();
int sso = 0, dso = 0;
for (int h = 0; h < dheight; h++) {
int spo = sso;
int dpo = dso;
for (int w = 0; w < dwidth; w++) {
for (int b = 0; b < dbands; b++) {
float sum = 0.0F;
double[] mat = matrix[b];
for (int k = 0; k < sbands; k++ ) {
sum += (float)mat[k] *
(float)(sData[k][spo+sBandOffsets[k]]);
}
dData[b][dpo+dBandOffsets[b]] = ImageUtil.clampRoundInt(sum + (float)matrix[b][sbands]);
}
spo += sPixelStride;
dpo += dPixelStride;
}
sso += sLineStride;
dso += dLineStride;
}
}
private void computeRectFloat(RasterAccessor src, RasterAccessor dst) {
int sLineStride = src.getScanlineStride();
int sPixelStride = src.getPixelStride();
int sbands = src.getNumBands();
int[] sBandOffsets = src.getBandOffsets();
float[][] sData = src.getFloatDataArrays();
int dwidth = dst.getWidth();
int dheight = dst.getHeight();
int dbands = dst.getNumBands();
int dLineStride = dst.getScanlineStride();
int dPixelStride = dst.getPixelStride();
int[] dBandOffsets = dst.getBandOffsets();
float[][] dData = dst.getFloatDataArrays();
int sso = 0, dso = 0;
for (int h = 0; h < dheight; h++) {
int spo = sso;
int dpo = dso;
for (int w = 0; w < dwidth; w++) {
for (int b = 0; b < dbands; b++) {
float sum = 0.0F;
double[] mat = matrix[b];
for (int k = 0; k < sbands; k++ ) {
sum += (float)mat[k] * sData[k][spo+sBandOffsets[k]];
}
dData[b][dpo+dBandOffsets[b]] = sum + (float)matrix[b][sbands];
}
spo += sPixelStride;
dpo += dPixelStride;
}
sso += sLineStride;
dso += dLineStride;
}
}
private void computeRectDouble(RasterAccessor src, RasterAccessor dst) {
int sLineStride = src.getScanlineStride();
int sPixelStride = src.getPixelStride();
int sbands = src.getNumBands();
int[] sBandOffsets = src.getBandOffsets();
double[][] sData = src.getDoubleDataArrays();
int dwidth = dst.getWidth();
int dheight = dst.getHeight();
int dbands = dst.getNumBands();
int dLineStride = dst.getScanlineStride();
int dPixelStride = dst.getPixelStride();
int[] dBandOffsets = dst.getBandOffsets();
double[][] dData = dst.getDoubleDataArrays();
int sso = 0, dso = 0;
for (int h = 0; h < dheight; h++) {
int spo = sso;
int dpo = dso;
for (int w = 0; w < dwidth; w++) {
for (int b = 0; b < dbands; b++) {
double sum = 0.0D;
double[] mat = matrix[b];
for (int k = 0; k < sbands; k++ ) {
sum += mat[k] * sData[k][spo+sBandOffsets[k]];
}
dData[b][dpo+dBandOffsets[b]] = sum + matrix[b][sbands];
}
spo += sPixelStride;
dpo += dPixelStride;
}
sso += sLineStride;
dso += dLineStride;
}
}
}