FileDocCategorySizeDatePackage
BandCombineOp.javaAPI DocAndroid 1.5 API21196Wed May 06 22:41:54 BST 2009java.awt.image

BandCombineOp

public class BandCombineOp extends Object implements RasterOp
The BandCombineOp class translates coordinates from coordinates in the source Raster to coordinates in the destination Raster by an arbitrary linear combination of the bands in a source Raster, using a specified matrix. The number of bands in the matrix should equal to the number of bands in the source Raster plus 1.
since
Android 1.0

Fields Summary
static final int[]
offsets3c
The Constant offsets3c.
static final int[]
offsets4ac
The Constant offsets4ac.
static final int[]
masks3c
The Constant masks3c.
static final int[]
masks4ac
The Constant masks4ac.
private static final int[]
piOffsets
The Constant piOffsets.
private static final int[]
piInvOffsets
The Constant piInvOffsets.
private static final int
TYPE_BYTE3C
The Constant TYPE_BYTE3C.
private static final int
TYPE_BYTE4AC
The Constant TYPE_BYTE4AC.
private static final int
TYPE_USHORT3C
The Constant TYPE_USHORT3C.
private static final int
TYPE_SHORT3C
The Constant TYPE_SHORT3C.
private int
mxWidth
The mx width.
private int
mxHeight
The mx height.
private float[]
matrix
The matrix.
private RenderingHints
rHints
The r hints.
Constructors Summary
public BandCombineOp(float[] matrix, RenderingHints hints)
Instantiates a new BandCombineOp object with the specified matrix.

param
matrix the specified matrix for band combining.
param
hints the RenderingHints.


     
        // XXX - todo
        // System.loadLibrary("imageops");
    
        this.mxHeight = matrix.length;
        this.mxWidth = matrix[0].length;
        this.matrix = new float[mxHeight][mxWidth];

        for (int i = 0; i < mxHeight; i++) {
            System.arraycopy(matrix[i], 0, this.matrix[i], 0, mxWidth);
        }

        this.rHints = hints;
    
Methods Summary
private final java.awt.image.BandCombineOp$SampleModelInfocheckSampleModel(java.awt.image.SampleModel sm)
Check sample model.

param
sm the sm.
return
the sample model info.

        SampleModelInfo ret = new SampleModelInfo();

        if (sm instanceof PixelInterleavedSampleModel) {
            // Check PixelInterleavedSampleModel
            if (sm.getDataType() != DataBuffer.TYPE_BYTE) {
                return null;
            }

            ret.channels = sm.getNumBands();
            ret.stride = ((ComponentSampleModel)sm).getScanlineStride();
            ret.channelsOrder = ((ComponentSampleModel)sm).getBandOffsets();

        } else if (sm instanceof SinglePixelPackedSampleModel) {
            // Check SinglePixelPackedSampleModel
            SinglePixelPackedSampleModel sppsm1 = (SinglePixelPackedSampleModel)sm;

            ret.channels = sppsm1.getNumBands();
            if (sppsm1.getDataType() != DataBuffer.TYPE_INT) {
                return null;
            }

            // Check sample models
            for (int i = 0; i < ret.channels; i++) {
                if (sppsm1.getSampleSize(i) != 8) {
                    return null;
                }
            }

            ret.channelsOrder = new int[ret.channels];
            int bitOffsets[] = sppsm1.getBitOffsets();
            for (int i = 0; i < ret.channels; i++) {
                if (bitOffsets[i] % 8 != 0) {
                    return null;
                }

                ret.channelsOrder[i] = bitOffsets[i] / 8;
            }

            ret.channels = 4;
            ret.stride = sppsm1.getScanlineStride() * 4;
        } else {
            return null;
        }

        return ret;
    
public java.awt.image.WritableRastercreateCompatibleDestRaster(java.awt.image.Raster src)

        int numBands = src.getNumBands();
        if (mxWidth != numBands && mxWidth != (numBands + 1) || numBands != mxHeight) {
            // awt.254=Number of bands in the source raster ({0}) is
            // incompatible with the matrix [{1}x{2}]
            throw new IllegalArgumentException(Messages.getString("awt.254", //$NON-NLS-1$
                    new Object[] {
                            numBands, mxWidth, mxHeight
                    }));
        }

        return src.createCompatibleWritableRaster(src.getWidth(), src.getHeight());
    
public java.awt.image.WritableRasterfilter(java.awt.image.Raster src, java.awt.image.WritableRaster dst)

        int numBands = src.getNumBands();

        if (mxWidth != numBands && mxWidth != (numBands + 1)) {
            // awt.254=Number of bands in the source raster ({0}) is
            // incompatible with the matrix [{1}x{2}]
            throw new IllegalArgumentException(Messages.getString("awt.254", //$NON-NLS-1$
                    new Object[] {
                            numBands, mxWidth, mxHeight
                    }));
        }

        if (dst == null) {
            dst = createCompatibleDestRaster(src);
        } else if (dst.getNumBands() != mxHeight) {
            // awt.255=Number of bands in the destination raster ({0}) is
            // incompatible with the matrix [{1}x{2}]
            throw new IllegalArgumentException(Messages.getString("awt.255", //$NON-NLS-1$
                    new Object[] {
                            dst.getNumBands(), mxWidth, mxHeight
                    }));
        }

        // XXX - todo
        // if (ippFilter(src, dst) != 0)
        if (verySlowFilter(src, dst) != 0) {
            // awt.21F=Unable to transform source
            throw new ImagingOpException(Messages.getString("awt.21F")); //$NON-NLS-1$
        }

        return dst;
    
public final java.awt.geom.Rectangle2DgetBounds2D(java.awt.image.Raster src)

        return src.getBounds();
    
public final float[][]getMatrix()
Gets the matrix associated with this BandCombineOp object.

return
the matrix associated with this BandCombineOp object.

        float res[][] = new float[mxHeight][mxWidth];

        for (int i = 0; i < mxHeight; i++) {
            System.arraycopy(matrix[i], 0, res[i], 0, mxWidth);
        }

        return res;
    
public final java.awt.geom.Point2DgetPoint2D(java.awt.geom.Point2D srcPoint, java.awt.geom.Point2D dstPoint)

        if (dstPoint == null) {
            dstPoint = new Point2D.Float();
        }

        dstPoint.setLocation(srcPoint);
        return dstPoint;
    
public final java.awt.RenderingHintsgetRenderingHints()

        return this.rHints;
    
private final native intippColorTwist(java.lang.Object srcData, int srcWidth, int srcHeight, int srcStride, java.lang.Object dstData, int dstWidth, int dstHeight, int dstStride, float[] ippMatrix, int type, int[] offsets, boolean inPlace)
Ipp color twist.

param
srcData the src data.
param
srcWidth the src width.
param
srcHeight the src height.
param
srcStride the src stride.
param
dstData the dst data.
param
dstWidth the dst width.
param
dstHeight the dst height.
param
dstStride the dst stride.
param
ippMatrix the ipp matrix.
param
type the type.
param
offsets the offsets.
param
inPlace the in place.
return
the int.

private intippFilter(java.awt.image.Raster src, java.awt.image.WritableRaster dst)
Ipp filter.

param
src the src.
param
dst the dst.
return
the int.

        boolean invertChannels;
        boolean inPlace = (src == dst);
        int type;
        int srcStride, dstStride;
        int offsets[] = null;

        int srcBands = src.getNumBands();
        int dstBands = dst.getNumBands();

        if (dstBands != 3
                || (srcBands != 3 && !(srcBands == 4 && matrix[0][3] == 0 && matrix[1][3] == 0 && matrix[2][3] == 0))) {
            return slowFilter(src, dst);
        }

        SampleModel srcSM = src.getSampleModel();
        SampleModel dstSM = dst.getSampleModel();

        if (srcSM instanceof SinglePixelPackedSampleModel
                && dstSM instanceof SinglePixelPackedSampleModel) {
            // Check SinglePixelPackedSampleModel
            SinglePixelPackedSampleModel sppsm1 = (SinglePixelPackedSampleModel)srcSM;
            SinglePixelPackedSampleModel sppsm2 = (SinglePixelPackedSampleModel)dstSM;

            if (sppsm1.getDataType() != DataBuffer.TYPE_INT
                    || sppsm2.getDataType() != DataBuffer.TYPE_INT) {
                return slowFilter(src, dst);
            }

            // Check sample models
            if (!Arrays.equals(sppsm2.getBitOffsets(), offsets3c)
                    || !Arrays.equals(sppsm2.getBitMasks(), masks3c)) {
                return slowFilter(src, dst);
            }

            if (srcBands == 3) {
                if (!Arrays.equals(sppsm1.getBitOffsets(), offsets3c)
                        || !Arrays.equals(sppsm1.getBitMasks(), masks3c)) {
                    return slowFilter(src, dst);
                }
            } else if (srcBands == 4) {
                if (!Arrays.equals(sppsm1.getBitOffsets(), offsets4ac)
                        || !Arrays.equals(sppsm1.getBitMasks(), masks4ac)) {
                    return slowFilter(src, dst);
                }
            }

            type = TYPE_BYTE4AC;
            invertChannels = true;

            srcStride = sppsm1.getScanlineStride() * 4;
            dstStride = sppsm2.getScanlineStride() * 4;
        } else if (srcSM instanceof PixelInterleavedSampleModel
                && dstSM instanceof PixelInterleavedSampleModel) {
            if (srcBands != 3) {
                return slowFilter(src, dst);
            }

            int srcDataType = srcSM.getDataType();

            switch (srcDataType) {
                case DataBuffer.TYPE_BYTE:
                    type = TYPE_BYTE3C;
                    break;
                case DataBuffer.TYPE_USHORT:
                    type = TYPE_USHORT3C;
                    break;
                case DataBuffer.TYPE_SHORT:
                    type = TYPE_SHORT3C;
                    break;
                default:
                    return slowFilter(src, dst);
            }

            // Check PixelInterleavedSampleModel
            PixelInterleavedSampleModel pism1 = (PixelInterleavedSampleModel)srcSM;
            PixelInterleavedSampleModel pism2 = (PixelInterleavedSampleModel)dstSM;

            if (srcDataType != pism2.getDataType() || pism1.getPixelStride() != 3
                    || pism2.getPixelStride() != 3
                    || !Arrays.equals(pism1.getBandOffsets(), pism2.getBandOffsets())) {
                return slowFilter(src, dst);
            }

            if (Arrays.equals(pism1.getBandOffsets(), piInvOffsets)) {
                invertChannels = true;
            } else if (Arrays.equals(pism1.getBandOffsets(), piOffsets)) {
                invertChannels = false;
            } else {
                return slowFilter(src, dst);
            }

            int dataTypeSize = DataBuffer.getDataTypeSize(srcDataType) / 8;

            srcStride = pism1.getScanlineStride() * dataTypeSize;
            dstStride = pism2.getScanlineStride() * dataTypeSize;
        } else { // XXX - todo - IPP allows support for planar data also
            return slowFilter(src, dst);
        }

        // Fill offsets if there's a child raster
        if (src.getParent() != null || dst.getParent() != null) {
            if (src.getSampleModelTranslateX() != 0 || src.getSampleModelTranslateY() != 0
                    || dst.getSampleModelTranslateX() != 0 || dst.getSampleModelTranslateY() != 0) {
                offsets = new int[4];
                offsets[0] = -src.getSampleModelTranslateX() + src.getMinX();
                offsets[1] = -src.getSampleModelTranslateY() + src.getMinY();
                offsets[2] = -dst.getSampleModelTranslateX() + dst.getMinX();
                offsets[3] = -dst.getSampleModelTranslateY() + dst.getMinY();
            }
        }

        Object srcData, dstData;
        AwtImageBackdoorAccessor dbAccess = AwtImageBackdoorAccessor.getInstance();
        try {
            srcData = dbAccess.getData(src.getDataBuffer());
            dstData = dbAccess.getData(dst.getDataBuffer());
        } catch (IllegalArgumentException e) {
            return -1; // Unknown data buffer type
        }

        float ippMatrix[] = new float[12];

        if (invertChannels) {
            // IPP treats big endian integers like BGR, so we have to
            // swap columns 1 and 3 and rows 1 and 3
            for (int i = 0; i < mxHeight; i++) {
                ippMatrix[i * 4] = matrix[2 - i][2];
                ippMatrix[i * 4 + 1] = matrix[2 - i][1];
                ippMatrix[i * 4 + 2] = matrix[2 - i][0];

                if (mxWidth == 4) {
                    ippMatrix[i * 4 + 3] = matrix[2 - i][3];
                } else if (mxWidth == 5) {
                    ippMatrix[i * 4 + 3] = matrix[2 - i][4];
                }
            }
        } else {
            for (int i = 0; i < mxHeight; i++) {
                ippMatrix[i * 4] = matrix[i][0];
                ippMatrix[i * 4 + 1] = matrix[i][1];
                ippMatrix[i * 4 + 2] = matrix[i][2];

                if (mxWidth == 4) {
                    ippMatrix[i * 4 + 3] = matrix[i][3];
                } else if (mxWidth == 5) {
                    ippMatrix[i * 4 + 3] = matrix[i][4];
                }
            }
        }

        return ippColorTwist(srcData, src.getWidth(), src.getHeight(), srcStride, dstData, dst
                .getWidth(), dst.getHeight(), dstStride, ippMatrix, type, offsets, inPlace);
    
private final native intsimpleCombineBands(java.lang.Object srcData, int srcWidth, int srcHeight, int srcStride, int srcChannels, java.lang.Object dstData, int dstStride, int dstChannels, float[] m, int[] offsets)
Simple combine bands.

param
srcData the src data.
param
srcWidth the src width.
param
srcHeight the src height.
param
srcStride the src stride.
param
srcChannels the src channels.
param
dstData the dst data.
param
dstStride the dst stride.
param
dstChannels the dst channels.
param
m the m.
param
offsets the offsets.
return
the int.

private final intslowFilter(java.awt.image.Raster src, java.awt.image.WritableRaster dst)
Slow filter.

param
src the src.
param
dst the dst.
return
the int.

        int res = 0;

        SampleModelInfo srcInfo, dstInfo;
        int offsets[] = null;

        srcInfo = checkSampleModel(src.getSampleModel());
        dstInfo = checkSampleModel(dst.getSampleModel());
        if (srcInfo == null || dstInfo == null) {
            return verySlowFilter(src, dst);
        }

        // Fill offsets if there's a child raster
        if (src.getParent() != null || dst.getParent() != null) {
            if (src.getSampleModelTranslateX() != 0 || src.getSampleModelTranslateY() != 0
                    || dst.getSampleModelTranslateX() != 0 || dst.getSampleModelTranslateY() != 0) {
                offsets = new int[4];
                offsets[0] = -src.getSampleModelTranslateX() + src.getMinX();
                offsets[1] = -src.getSampleModelTranslateY() + src.getMinY();
                offsets[2] = -dst.getSampleModelTranslateX() + dst.getMinX();
                offsets[3] = -dst.getSampleModelTranslateY() + dst.getMinY();
            }
        }

        int rmxWidth = (srcInfo.channels + 1); // width of the reordered matrix
        float reorderedMatrix[] = new float[rmxWidth * dstInfo.channels];
        for (int j = 0; j < dstInfo.channels; j++) {
            if (j >= dstInfo.channelsOrder.length) {
                continue;
            }

            for (int i = 0; i < srcInfo.channels; i++) {
                if (i >= srcInfo.channelsOrder.length) {
                    break;
                }

                reorderedMatrix[dstInfo.channelsOrder[j] * rmxWidth + srcInfo.channelsOrder[i]] = matrix[j][i];
            }
            if (mxWidth == rmxWidth) {
                reorderedMatrix[(dstInfo.channelsOrder[j] + 1) * rmxWidth - 1] = matrix[j][mxWidth - 1];
            }
        }

        Object srcData, dstData;
        AwtImageBackdoorAccessor dbAccess = AwtImageBackdoorAccessor.getInstance();
        try {
            srcData = dbAccess.getData(src.getDataBuffer());
            dstData = dbAccess.getData(dst.getDataBuffer());
        } catch (IllegalArgumentException e) {
            return -1; // Unknown data buffer type
        }

        simpleCombineBands(srcData, src.getWidth(), src.getHeight(), srcInfo.stride,
                srcInfo.channels, dstData, dstInfo.stride, dstInfo.channels, reorderedMatrix,
                offsets);

        return res;
    
private intverySlowFilter(java.awt.image.Raster src, java.awt.image.WritableRaster dst)
Very slow filter.

param
src the src.
param
dst the dst.
return
the int.

        int numBands = src.getNumBands();

        int srcMinX = src.getMinX();
        int srcY = src.getMinY();

        int dstMinX = dst.getMinX();
        int dstY = dst.getMinY();

        int dX = src.getWidth();// < dst.getWidth() ? src.getWidth() :
        // dst.getWidth();
        int dY = src.getHeight();// < dst.getHeight() ? src.getHeight() :
        // dst.getHeight();

        float sample;
        int srcPixels[] = new int[numBands * dX * dY];
        int dstPixels[] = new int[mxHeight * dX * dY];

        srcPixels = src.getPixels(srcMinX, srcY, dX, dY, srcPixels);

        if (numBands == mxWidth) {
            for (int i = 0, j = 0; i < srcPixels.length; i += numBands) {
                for (int dstB = 0; dstB < mxHeight; dstB++) {
                    sample = 0f;
                    for (int srcB = 0; srcB < numBands; srcB++) {
                        sample += matrix[dstB][srcB] * srcPixels[i + srcB];
                    }
                    dstPixels[j++] = (int)sample;
                }
            }
        } else {
            for (int i = 0, j = 0; i < srcPixels.length; i += numBands) {
                for (int dstB = 0; dstB < mxHeight; dstB++) {
                    sample = 0f;
                    for (int srcB = 0; srcB < numBands; srcB++) {
                        sample += matrix[dstB][srcB] * srcPixels[i + srcB];
                    }
                    dstPixels[j++] = (int)(sample + matrix[dstB][numBands]);
                }
            }
        }

        dst.setPixels(dstMinX, dstY, dX, dY, dstPixels);

        return 0;