0001: /*
0002: * $RCSfile: MosaicOpImage.java,v $
0003: *
0004: * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * Use is subject to license terms.
0007: *
0008: * $Revision: 1.2 $
0009: * $Date: 2005/02/23 21:02:26 $
0010: * $State: Exp $
0011: */package com.sun.media.jai.opimage;
0012:
0013: import java.awt.Point;
0014: import java.awt.Rectangle;
0015: import java.awt.image.ColorModel;
0016: import java.awt.image.DataBuffer;
0017: import java.awt.image.Raster;
0018: import java.awt.image.RenderedImage;
0019: import java.awt.image.SampleModel;
0020: import java.awt.image.WritableRaster;
0021: import java.util.ArrayList;
0022: import java.util.Arrays;
0023: import java.util.Map;
0024: import java.util.Vector;
0025: import javax.media.jai.BorderExtender;
0026: import javax.media.jai.BorderExtenderConstant;
0027: import javax.media.jai.ImageLayout;
0028: import javax.media.jai.JAI;
0029: import javax.media.jai.OpImage;
0030: import javax.media.jai.PlanarImage;
0031: import javax.media.jai.RasterAccessor;
0032: import javax.media.jai.RasterFormatTag;
0033: import javax.media.jai.ROI;
0034: import javax.media.jai.operator.MosaicType;
0035: import javax.media.jai.operator.MosaicDescriptor;
0036: import com.sun.media.jai.util.ImageUtil;
0037:
0038: public class MosaicOpImage extends OpImage {
0039: private static final int WEIGHT_TYPE_ALPHA = 1;
0040: private static final int WEIGHT_TYPE_ROI = 2;
0041: private static final int WEIGHT_TYPE_THRESHOLD = 3;
0042:
0043: protected MosaicType mosaicType;
0044: protected PlanarImage[] sourceAlpha;
0045: protected ROI[] sourceROI;
0046: protected double[][] sourceThreshold;
0047: protected double[] backgroundValues;
0048:
0049: protected int numBands;
0050:
0051: /** Integral background value. */
0052: protected int[] background;
0053:
0054: /** Integral thresholds. */
0055: protected int[][] threshold;
0056:
0057: protected boolean isAlphaBitmask = false;
0058:
0059: private BorderExtender sourceExtender;
0060: private BorderExtender zeroExtender;
0061: private PlanarImage[] roiImage;
0062:
0063: private static final ImageLayout getLayout(Vector sources,
0064: ImageLayout layout) {
0065:
0066: // Contingent variables.
0067: RenderedImage source0 = null;
0068: SampleModel targetSM = null;
0069: ColorModel targetCM = null;
0070:
0071: // Get source count (might be zero).
0072: int numSources = sources.size();
0073:
0074: if (numSources > 0) {
0075: // Get SampleModel and ColorModel from first source.
0076: source0 = (RenderedImage) sources.get(0);
0077: targetSM = source0.getSampleModel();
0078: targetCM = source0.getColorModel();
0079: } else if (layout != null
0080: && layout.isValid(ImageLayout.WIDTH_MASK
0081: | ImageLayout.HEIGHT_MASK
0082: | ImageLayout.SAMPLE_MODEL_MASK)) {
0083: // Get SampleModel and ColorModel from layout.
0084: targetSM = layout.getSampleModel(null);
0085: if (targetSM == null) {
0086: throw new IllegalArgumentException(JaiI18N
0087: .getString("MosaicOpImage7"));
0088: }
0089: } else {
0090: throw new IllegalArgumentException(JaiI18N
0091: .getString("MosaicOpImage8"));
0092: }
0093:
0094: // Get data type, band count, and sample depth.
0095: int dataType = targetSM.getDataType();
0096: int numBands = targetSM.getNumBands();
0097: int sampleSize = targetSM.getSampleSize(0);
0098:
0099: // Sample size must equal that of first band.
0100: for (int i = 1; i < numBands; i++) {
0101: if (targetSM.getSampleSize(i) != sampleSize) {
0102: throw new IllegalArgumentException(JaiI18N
0103: .getString("MosaicOpImage1"));
0104: }
0105: }
0106:
0107: // Return a clone of ImageLayout passed in if no sources.
0108: // The input ImageLayout was checked for null above.
0109: if (numSources < 1) {
0110: return (ImageLayout) layout.clone();
0111: }
0112:
0113: // Check the other sources against the first.
0114: for (int i = 1; i < numSources; i++) {
0115: RenderedImage source = (RenderedImage) sources.get(i);
0116: SampleModel sourceSM = source.getSampleModel();
0117:
0118: // Data type and band count must be equal.
0119: if (sourceSM.getDataType() != dataType) {
0120: throw new IllegalArgumentException(JaiI18N
0121: .getString("MosaicOpImage2"));
0122: } else if (sourceSM.getNumBands() != numBands) {
0123: throw new IllegalArgumentException(JaiI18N
0124: .getString("MosaicOpImage3"));
0125: }
0126:
0127: // Sample size must be equal.
0128: for (int j = 0; j < numBands; j++) {
0129: if (sourceSM.getSampleSize(j) != sampleSize) {
0130: throw new IllegalArgumentException(JaiI18N
0131: .getString("MosaicOpImage1"));
0132: }
0133: }
0134: }
0135:
0136: // Create a new layout or clone the one passed in.
0137: ImageLayout mosaicLayout = layout == null ? new ImageLayout()
0138: : (ImageLayout) layout.clone();
0139:
0140: // Determine the mosaic bounds.
0141: Rectangle mosaicBounds = new Rectangle();
0142: if (mosaicLayout.isValid(ImageLayout.MIN_X_MASK
0143: | ImageLayout.MIN_Y_MASK | ImageLayout.WIDTH_MASK
0144: | ImageLayout.HEIGHT_MASK)) {
0145: // Set the mosaic bounds to the value given in the layout.
0146: mosaicBounds.setBounds(mosaicLayout.getMinX(null),
0147: mosaicLayout.getMinY(null), mosaicLayout
0148: .getWidth(null), mosaicLayout
0149: .getHeight(null));
0150: } else if (numSources > 0) {
0151: // Set the mosaic bounds to the union of source bounds.
0152: mosaicBounds.setBounds(source0.getMinX(),
0153: source0.getMinY(), source0.getWidth(), source0
0154: .getHeight());
0155: for (int i = 1; i < numSources; i++) {
0156: RenderedImage source = (RenderedImage) sources.get(i);
0157: Rectangle sourceBounds = new Rectangle(
0158: source.getMinX(), source.getMinY(), source
0159: .getWidth(), source.getHeight());
0160: mosaicBounds = mosaicBounds.union(sourceBounds);
0161: }
0162: }
0163:
0164: // Set the mosaic bounds in the layout.
0165: mosaicLayout.setMinX(mosaicBounds.x);
0166: mosaicLayout.setMinY(mosaicBounds.y);
0167: mosaicLayout.setWidth(mosaicBounds.width);
0168: mosaicLayout.setHeight(mosaicBounds.height);
0169:
0170: // Check the SampleModel if defined.
0171: if (mosaicLayout.isValid(ImageLayout.SAMPLE_MODEL_MASK)) {
0172: // Get the SampleModel.
0173: SampleModel destSM = mosaicLayout.getSampleModel(null);
0174:
0175: // Unset SampleModel if differing band count or data type.
0176: boolean unsetSampleModel = destSM.getNumBands() != numBands
0177: || destSM.getDataType() != dataType;
0178:
0179: // Unset SampleModel if differing sample size.
0180: for (int i = 0; !unsetSampleModel && i < numBands; i++) {
0181: if (destSM.getSampleSize(i) != sampleSize) {
0182: unsetSampleModel = true;
0183: }
0184: }
0185:
0186: // Unset SampleModel if needed.
0187: if (unsetSampleModel) {
0188: mosaicLayout.unsetValid(ImageLayout.SAMPLE_MODEL_MASK);
0189: }
0190: }
0191:
0192: return mosaicLayout;
0193: }
0194:
0195: public MosaicOpImage(Vector sources, ImageLayout layout,
0196: Map config, MosaicType mosaicType,
0197: PlanarImage[] sourceAlpha, ROI[] sourceROI,
0198: double[][] sourceThreshold, double[] backgroundValues) {
0199: super (sources, getLayout(sources, layout), config, true);
0200:
0201: // Set the band count.
0202: this .numBands = sampleModel.getNumBands();
0203:
0204: // Set the source count.
0205: int numSources = getNumSources();
0206:
0207: // Set the mosaic type.
0208: this .mosaicType = mosaicType;
0209:
0210: // Save the alpha array.
0211: this .sourceAlpha = null;
0212: if (sourceAlpha != null) {
0213: // Check alpha images.
0214: for (int i = 0; i < sourceAlpha.length; i++) {
0215: if (sourceAlpha[i] != null) {
0216: SampleModel alphaSM = sourceAlpha[i]
0217: .getSampleModel();
0218:
0219: if (alphaSM.getNumBands() != 1) {
0220: throw new IllegalArgumentException(JaiI18N
0221: .getString("MosaicOpImage4"));
0222: } else if (alphaSM.getDataType() != sampleModel
0223: .getDataType()) {
0224: throw new IllegalArgumentException(JaiI18N
0225: .getString("MosaicOpImage5"));
0226: } else if (alphaSM.getSampleSize(0) != sampleModel
0227: .getSampleSize(0)) {
0228: throw new IllegalArgumentException(JaiI18N
0229: .getString("MosaicOpImage6"));
0230: }
0231: }
0232: }
0233:
0234: this .sourceAlpha = new PlanarImage[numSources];
0235: System.arraycopy(sourceAlpha, 0, this .sourceAlpha, 0, Math
0236: .min(sourceAlpha.length, numSources));
0237: }
0238:
0239: // Save the ROI array.
0240: this .sourceROI = null;
0241: if (sourceROI != null) {
0242: this .sourceROI = new ROI[numSources];
0243: System.arraycopy(sourceROI, 0, this .sourceROI, 0, Math.min(
0244: sourceROI.length, numSources));
0245: }
0246:
0247: // isAlphaBitmask is true if and only if type is blend and an
0248: // alpha image is supplied for each source.
0249: this .isAlphaBitmask = !(mosaicType == MosaicDescriptor.MOSAIC_TYPE_BLEND
0250: && sourceAlpha != null && !(sourceAlpha.length < numSources));
0251: if (!this .isAlphaBitmask) {
0252: for (int i = 0; i < numSources; i++) {
0253: if (sourceAlpha[i] == null) {
0254: this .isAlphaBitmask = true;
0255: break;
0256: }
0257: }
0258: }
0259:
0260: // Copy the threshold values according to the specification.
0261: this .sourceThreshold = new double[numSources][numBands];
0262:
0263: // Ensure the parameter is non-null and has one value.
0264: if (sourceThreshold == null) {
0265: sourceThreshold = new double[][] { { 1.0 } };
0266: }
0267: for (int i = 0; i < numSources; i++) {
0268: // If there's an array for this source, use it.
0269: if (i < sourceThreshold.length
0270: && sourceThreshold[i] != null) {
0271: if (sourceThreshold[i].length < numBands) {
0272: // If the array is less than numBands, fill with element 0.
0273: Arrays.fill(this .sourceThreshold[i],
0274: sourceThreshold[i][0]);
0275: } else {
0276: // Copy the whole array.
0277: System.arraycopy(sourceThreshold[i], 0,
0278: this .sourceThreshold[i], 0, numBands);
0279: }
0280: } else {
0281: // Beyond the array or a null element: use the zeroth array.
0282: this .sourceThreshold[i] = this .sourceThreshold[0];
0283: }
0284: }
0285:
0286: // Initialize the integral thresholds.
0287: this .threshold = new int[numSources][numBands];
0288: for (int i = 0; i < numSources; i++) {
0289: for (int j = 0; j < numBands; j++) {
0290: // Truncate as the specified comparison is ">=".
0291: this .threshold[i][j] = (int) this .sourceThreshold[i][j];
0292: }
0293: }
0294:
0295: // Copy the background values per the specification.
0296: this .backgroundValues = new double[numBands];
0297: if (backgroundValues == null) {
0298: backgroundValues = new double[] { 0.0 };
0299: }
0300: if (backgroundValues.length < numBands) {
0301: Arrays.fill(this .backgroundValues, backgroundValues[0]);
0302: } else {
0303: System.arraycopy(backgroundValues, 0,
0304: this .backgroundValues, 0, numBands);
0305: }
0306:
0307: // Clamp the floating point values for the integral cases.
0308: this .background = new int[this .backgroundValues.length];
0309: int dataType = sampleModel.getDataType();
0310: for (int i = 0; i < this .background.length; i++) {
0311: switch (dataType) {
0312: case DataBuffer.TYPE_BYTE:
0313: this .background[i] = ImageUtil
0314: .clampRoundByte(this .backgroundValues[i]);
0315: break;
0316: case DataBuffer.TYPE_USHORT:
0317: this .background[i] = ImageUtil
0318: .clampRoundUShort(this .backgroundValues[i]);
0319: break;
0320: case DataBuffer.TYPE_SHORT:
0321: this .background[i] = ImageUtil
0322: .clampRoundShort(this .backgroundValues[i]);
0323: break;
0324: case DataBuffer.TYPE_INT:
0325: this .background[i] = ImageUtil
0326: .clampRoundInt(this .backgroundValues[i]);
0327: break;
0328: default:
0329: }
0330: }
0331:
0332: // Determine constant value for source border extension.
0333: double sourceExtensionConstant;
0334: switch (dataType) {
0335: case DataBuffer.TYPE_BYTE:
0336: sourceExtensionConstant = 0.0;
0337: break;
0338: case DataBuffer.TYPE_USHORT:
0339: sourceExtensionConstant = 0.0;
0340: break;
0341: case DataBuffer.TYPE_SHORT:
0342: sourceExtensionConstant = Short.MIN_VALUE;
0343: break;
0344: case DataBuffer.TYPE_INT:
0345: sourceExtensionConstant = Integer.MIN_VALUE;
0346: break;
0347: case DataBuffer.TYPE_FLOAT:
0348: sourceExtensionConstant = -Float.MAX_VALUE;
0349: break;
0350: case DataBuffer.TYPE_DOUBLE:
0351: default:
0352: sourceExtensionConstant = -Double.MAX_VALUE;
0353: }
0354:
0355: // Extend the sources filling with the minimum possible value
0356: // on account of the threshold technique.
0357: this .sourceExtender = sourceExtensionConstant == 0.0 ? BorderExtender
0358: .createInstance(BorderExtender.BORDER_ZERO)
0359: : new BorderExtenderConstant(
0360: new double[] { sourceExtensionConstant });
0361:
0362: // Extends alpha or ROI data with zeros.
0363: if (sourceAlpha != null || sourceROI != null) {
0364: this .zeroExtender = BorderExtender
0365: .createInstance(BorderExtender.BORDER_ZERO);
0366: }
0367:
0368: // Get the ROI images.
0369: if (sourceROI != null) {
0370: roiImage = new PlanarImage[numSources];
0371: for (int i = 0; i < sourceROI.length; i++) {
0372: if (sourceROI[i] != null) {
0373: roiImage[i] = sourceROI[i].getAsImage();
0374: }
0375: }
0376: }
0377: }
0378:
0379: public Rectangle mapDestRect(Rectangle destRect, int sourceIndex) {
0380: if (destRect == null) {
0381: throw new IllegalArgumentException(JaiI18N
0382: .getString("Generic0"));
0383: }
0384:
0385: if (sourceIndex < 0 || sourceIndex >= getNumSources()) {
0386: throw new IllegalArgumentException(JaiI18N
0387: .getString("Generic1"));
0388: }
0389:
0390: return destRect.intersection(getSourceImage(sourceIndex)
0391: .getBounds());
0392: }
0393:
0394: public Rectangle mapSourceRect(Rectangle sourceRect, int sourceIndex) {
0395: if (sourceRect == null) {
0396: throw new IllegalArgumentException(JaiI18N
0397: .getString("Generic0"));
0398: }
0399:
0400: if (sourceIndex < 0 || sourceIndex >= getNumSources()) {
0401: throw new IllegalArgumentException(JaiI18N
0402: .getString("Generic1"));
0403: }
0404:
0405: return sourceRect.intersection(getBounds());
0406: }
0407:
0408: public Raster computeTile(int tileX, int tileY) {
0409: // Create a new Raster.
0410: WritableRaster dest = createWritableRaster(sampleModel,
0411: new Point(tileXToX(tileX), tileYToY(tileY)));
0412:
0413: // Determine the active area; tile intersects with image's bounds.
0414: Rectangle destRect = getTileRect(tileX, tileY);
0415:
0416: int numSources = getNumSources();
0417:
0418: Raster[] rasterSources = new Raster[numSources];
0419: Raster[] alpha = sourceAlpha != null ? new Raster[numSources]
0420: : null;
0421: Raster[] roi = sourceROI != null ? new Raster[numSources]
0422: : null;
0423:
0424: // Cobble areas
0425: for (int i = 0; i < numSources; i++) {
0426: PlanarImage source = getSourceImage(i);
0427: Rectangle srcRect = mapDestRect(destRect, i);
0428:
0429: // If srcRect is empty, set the Raster for this source to
0430: // null; otherwise pass srcRect to getData(). If srcRect
0431: // is null, getData() will return a Raster containing the
0432: // data of the entire source image.
0433: rasterSources[i] = srcRect != null && srcRect.isEmpty() ? null
0434: : source.getExtendedData(destRect, sourceExtender);
0435:
0436: if (rasterSources[i] != null) {
0437: if (sourceAlpha != null && sourceAlpha[i] != null) {
0438: alpha[i] = sourceAlpha[i].getExtendedData(destRect,
0439: zeroExtender);
0440: }
0441:
0442: if (sourceROI != null && sourceROI[i] != null) {
0443: roi[i] = roiImage[i].getExtendedData(destRect,
0444: zeroExtender);
0445: }
0446: }
0447: }
0448:
0449: computeRect(rasterSources, dest, destRect, alpha, roi);
0450:
0451: for (int i = 0; i < numSources; i++) {
0452: Raster sourceData = rasterSources[i];
0453: if (sourceData != null) {
0454: PlanarImage source = getSourceImage(i);
0455:
0456: // Recycle the source tile
0457: if (source
0458: .overlapsMultipleTiles(sourceData.getBounds())) {
0459: recycleTile(sourceData);
0460: }
0461: }
0462: }
0463:
0464: return dest;
0465: }
0466:
0467: protected void computeRect(Raster[] sources, WritableRaster dest,
0468: Rectangle destRect) {
0469: computeRect(sources, dest, destRect, null, null);
0470: }
0471:
0472: protected void computeRect(Raster[] sources, WritableRaster dest,
0473: Rectangle destRect, Raster[] alphaRaster, Raster[] roiRaster) {
0474: // Save the source count.
0475: int numSources = sources.length;
0476:
0477: // Put all non-null sources in a list.
0478: ArrayList sourceList = new ArrayList(numSources);
0479: for (int i = 0; i < numSources; i++) {
0480: if (sources[i] != null) {
0481: sourceList.add(sources[i]);
0482: }
0483: }
0484:
0485: // Clear the background and return if no sources.
0486: int numNonNullSources = sourceList.size();
0487: if (numNonNullSources == 0) {
0488: ImageUtil.fillBackground(dest, destRect, backgroundValues);
0489: return;
0490: }
0491:
0492: // Determine the format tag id.
0493: SampleModel[] sourceSM = new SampleModel[numNonNullSources];
0494: for (int i = 0; i < numNonNullSources; i++) {
0495: sourceSM[i] = ((Raster) sourceList.get(i)).getSampleModel();
0496: }
0497: int formatTagID = RasterAccessor.findCompatibleTag(sourceSM,
0498: dest.getSampleModel());
0499:
0500: // Create source accessors.
0501: RasterAccessor[] s = new RasterAccessor[numSources];
0502: for (int i = 0; i < numSources; i++) {
0503: if (sources[i] != null) {
0504: RasterFormatTag formatTag = new RasterFormatTag(
0505: sources[i].getSampleModel(), formatTagID);
0506: s[i] = new RasterAccessor(sources[i], destRect,
0507: formatTag, null);
0508: }
0509: }
0510:
0511: // Create dest accessor.
0512: RasterAccessor d = new RasterAccessor(
0513: dest,
0514: destRect,
0515: new RasterFormatTag(dest.getSampleModel(), formatTagID),
0516: null);
0517:
0518: // Create the alpha accessors.
0519: RasterAccessor[] a = new RasterAccessor[numSources];
0520: if (alphaRaster != null) {
0521: for (int i = 0; i < numSources; i++) {
0522: if (alphaRaster[i] != null) {
0523: SampleModel alphaSM = alphaRaster[i]
0524: .getSampleModel();
0525: int alphaFormatTagID = RasterAccessor
0526: .findCompatibleTag(null, alphaSM);
0527: RasterFormatTag alphaFormatTag = new RasterFormatTag(
0528: alphaSM, alphaFormatTagID);
0529: a[i] = new RasterAccessor(alphaRaster[i], destRect,
0530: alphaFormatTag, sourceAlpha[i]
0531: .getColorModel());
0532: }
0533: }
0534: }
0535:
0536: // Branch to data type-specific method.
0537: switch (d.getDataType()) {
0538: case DataBuffer.TYPE_BYTE:
0539: computeRectByte(s, d, a, roiRaster);
0540: break;
0541: case DataBuffer.TYPE_USHORT:
0542: computeRectUShort(s, d, a, roiRaster);
0543: break;
0544: case DataBuffer.TYPE_SHORT:
0545: computeRectShort(s, d, a, roiRaster);
0546: break;
0547: case DataBuffer.TYPE_INT:
0548: computeRectInt(s, d, a, roiRaster);
0549: break;
0550: case DataBuffer.TYPE_FLOAT:
0551: computeRectFloat(s, d, a, roiRaster);
0552: break;
0553: case DataBuffer.TYPE_DOUBLE:
0554: computeRectDouble(s, d, a, roiRaster);
0555: break;
0556: }
0557:
0558: d.copyDataToRaster();
0559: }
0560:
0561: private void computeRectByte(RasterAccessor[] src,
0562: RasterAccessor dst, RasterAccessor[] alfa, Raster[] roi) {
0563: // Save the source count.
0564: int numSources = src.length;
0565:
0566: // Allocate stride, offset, and data arrays for sources.
0567: int[] srcLineStride = new int[numSources];
0568: int[] srcPixelStride = new int[numSources];
0569: int[][] srcBandOffsets = new int[numSources][];
0570: byte[][][] srcData = new byte[numSources][][];
0571:
0572: // Initialize stride, offset, and data arrays for sources.
0573: for (int i = 0; i < numSources; i++) {
0574: if (src[i] != null) {
0575: srcLineStride[i] = src[i].getScanlineStride();
0576: srcPixelStride[i] = src[i].getPixelStride();
0577: srcBandOffsets[i] = src[i].getBandOffsets();
0578: srcData[i] = src[i].getByteDataArrays();
0579: }
0580: }
0581:
0582: // Initialize destination variables.
0583: int dstMinX = dst.getX();
0584: int dstMinY = dst.getY();
0585: int dstWidth = dst.getWidth();
0586: int dstHeight = dst.getHeight();
0587: int dstMaxX = dstMinX + dstWidth; // x max exclusive
0588: int dstMaxY = dstMinY + dstHeight; // y max exclusive
0589: int dstBands = dst.getNumBands();
0590: int dstLineStride = dst.getScanlineStride();
0591: int dstPixelStride = dst.getPixelStride();
0592: int[] dstBandOffsets = dst.getBandOffsets();
0593: byte[][] dstData = dst.getByteDataArrays();
0594:
0595: // Check for alpha.
0596: boolean hasAlpha = false;
0597: for (int i = 0; i < numSources; i++) {
0598: if (alfa[i] != null) {
0599: hasAlpha = true;
0600: break;
0601: }
0602: }
0603:
0604: // Declare alpha channel arrays.
0605: int[] alfaLineStride = null;
0606: int[] alfaPixelStride = null;
0607: int[][] alfaBandOffsets = null;
0608: byte[][][] alfaData = null;
0609:
0610: if (hasAlpha) {
0611: // Allocate stride, offset, and data arrays for alpha channels.
0612: alfaLineStride = new int[numSources];
0613: alfaPixelStride = new int[numSources];
0614: alfaBandOffsets = new int[numSources][];
0615: alfaData = new byte[numSources][][];
0616:
0617: // Initialize stride, offset, and data arrays for alpha channels.
0618: for (int i = 0; i < numSources; i++) {
0619: if (alfa[i] != null) {
0620: alfaLineStride[i] = alfa[i].getScanlineStride();
0621: alfaPixelStride[i] = alfa[i].getPixelStride();
0622: alfaBandOffsets[i] = alfa[i].getBandOffsets();
0623: alfaData[i] = alfa[i].getByteDataArrays();
0624: }
0625: }
0626: }
0627:
0628: // Initialize weight type arrays.
0629: int[] weightTypes = new int[numSources];
0630: for (int i = 0; i < numSources; i++) {
0631: weightTypes[i] = WEIGHT_TYPE_THRESHOLD;
0632: if (alfa[i] != null) {
0633: weightTypes[i] = WEIGHT_TYPE_ALPHA;
0634: } else if (sourceROI != null && sourceROI[i] != null) {
0635: weightTypes[i] = WEIGHT_TYPE_ROI;
0636: }
0637: }
0638:
0639: // Set up source offset and data variabls.
0640: int[] sLineOffsets = new int[numSources];
0641: int[] sPixelOffsets = new int[numSources];
0642: byte[][] sBandData = new byte[numSources][];
0643:
0644: // Set up alpha offset and data variabls.
0645: int[] aLineOffsets = null;
0646: int[] aPixelOffsets = null;
0647: byte[][] aBandData = null;
0648: if (hasAlpha) {
0649: aLineOffsets = new int[numSources];
0650: aPixelOffsets = new int[numSources];
0651: aBandData = new byte[numSources][];
0652: }
0653:
0654: for (int b = 0; b < dstBands; b++) {
0655: // Initialize source and alpha band array and line offsets.
0656: for (int s = 0; s < numSources; s++) {
0657: if (src[s] != null) {
0658: sBandData[s] = srcData[s][b];
0659: sLineOffsets[s] = srcBandOffsets[s][b];
0660: }
0661: if (weightTypes[s] == WEIGHT_TYPE_ALPHA) {
0662: aBandData[s] = alfaData[s][0];
0663: aLineOffsets[s] = alfaBandOffsets[s][0];
0664: }
0665: }
0666:
0667: // Initialize destination band array and line offsets.
0668: byte[] dBandData = dstData[b];
0669: int dLineOffset = dstBandOffsets[b];
0670:
0671: if (mosaicType == MosaicDescriptor.MOSAIC_TYPE_OVERLAY) {
0672: for (int dstY = dstMinY; dstY < dstMaxY; dstY++) {
0673: // Initialize source and alpha pixel offsets and
0674: // update line offsets.
0675: for (int s = 0; s < numSources; s++) {
0676: if (src[s] != null) {
0677: sPixelOffsets[s] = sLineOffsets[s];
0678: sLineOffsets[s] += srcLineStride[s];
0679: }
0680: if (alfa[s] != null) {
0681: aPixelOffsets[s] = aLineOffsets[s];
0682: aLineOffsets[s] += alfaLineStride[s];
0683: }
0684: }
0685:
0686: // Initialize destination pixel offset and update
0687: // line offset.
0688: int dPixelOffset = dLineOffset;
0689: dLineOffset += dstLineStride;
0690:
0691: for (int dstX = dstMinX; dstX < dstMaxX; dstX++) {
0692:
0693: // Unset destination update flag.
0694: boolean setDestValue = false;
0695:
0696: // Loop over source until a non-zero weight is
0697: // encountered.
0698: for (int s = 0; s < numSources; s++) {
0699: if (src[s] == null)
0700: continue;
0701:
0702: byte sourceValue = sBandData[s][sPixelOffsets[s]];
0703: sPixelOffsets[s] += srcPixelStride[s];
0704:
0705: switch (weightTypes[s]) {
0706: case WEIGHT_TYPE_ALPHA:
0707: setDestValue = aBandData[s][aPixelOffsets[s]] != 0;
0708: aPixelOffsets[s] += alfaPixelStride[s];
0709: break;
0710: case WEIGHT_TYPE_ROI:
0711: setDestValue = roi[s].getSample(dstX,
0712: dstY, 0) > 0;
0713: break;
0714: default: // WEIGHT_TYPE_THRESHOLD
0715: setDestValue = (sourceValue & 0xff) >= sourceThreshold[s][b];
0716: }
0717:
0718: // Set the destination value if a non-zero
0719: // weight was found.
0720: if (setDestValue) {
0721: dBandData[dPixelOffset] = sourceValue;
0722:
0723: // Increment offset of subsequent sources.
0724: for (int k = s + 1; k < numSources; k++) {
0725: if (src[k] != null) {
0726: sPixelOffsets[k] += srcPixelStride[k];
0727: }
0728: if (alfa[k] != null) {
0729: aPixelOffsets[k] += alfaPixelStride[k];
0730: }
0731: }
0732: break;
0733: }
0734: }
0735:
0736: // Set the destination value to the background if
0737: // no value was set.
0738: if (!setDestValue) {
0739: dBandData[dPixelOffset] = (byte) background[b];
0740: }
0741:
0742: dPixelOffset += dstPixelStride;
0743: }
0744: }
0745: } else { // mosaicType == MosaicDescriptor.MOSAIC_TYPE_BLEND
0746: for (int dstY = dstMinY; dstY < dstMaxY; dstY++) {
0747: // Initialize source and alpha pixel offsets and
0748: // update line offsets.
0749: for (int s = 0; s < numSources; s++) {
0750: if (src[s] != null) {
0751: sPixelOffsets[s] = sLineOffsets[s];
0752: sLineOffsets[s] += srcLineStride[s];
0753: }
0754: if (weightTypes[s] == WEIGHT_TYPE_ALPHA) {
0755: aPixelOffsets[s] = aLineOffsets[s];
0756: aLineOffsets[s] += alfaLineStride[s];
0757: }
0758: }
0759:
0760: // Initialize destination pixel offset and update
0761: // line offset.
0762: int dPixelOffset = dLineOffset;
0763: dLineOffset += dstLineStride;
0764:
0765: for (int dstX = dstMinX; dstX < dstMaxX; dstX++) {
0766:
0767: // Clear values for blending ratio.
0768: float numerator = 0.0F;
0769: float denominator = 0.0F;
0770:
0771: // Accumulate into numerator and denominator.
0772: for (int s = 0; s < numSources; s++) {
0773: if (src[s] == null)
0774: continue;
0775:
0776: byte sourceValue = sBandData[s][sPixelOffsets[s]];
0777: sPixelOffsets[s] += srcPixelStride[s];
0778:
0779: float weight = 0.0F;
0780: switch (weightTypes[s]) {
0781: case WEIGHT_TYPE_ALPHA:
0782: weight = (aBandData[s][aPixelOffsets[s]] & 0xff);
0783: if (weight > 0.0F && isAlphaBitmask) {
0784: weight = 1.0F;
0785: } else {
0786: weight /= 255.0F;
0787: }
0788: aPixelOffsets[s] += alfaPixelStride[s];
0789: break;
0790: case WEIGHT_TYPE_ROI:
0791: weight = roi[s]
0792: .getSample(dstX, dstY, 0) > 0 ? 1.0F
0793: : 0.0F;
0794: break;
0795: default: // WEIGHT_TYPE_THRESHOLD
0796: weight = (sourceValue & 0xff) >= sourceThreshold[s][b] ? 1.0F
0797: : 0.0F;
0798: }
0799:
0800: // Update numerator and denominator.
0801: numerator += (weight * (sourceValue & 0xff));
0802: denominator += weight;
0803: }
0804:
0805: // Clear the background if all weights were zero,
0806: // otherwise blend the values.
0807: if (denominator == 0.0) {
0808: dBandData[dPixelOffset] = (byte) background[b];
0809: } else {
0810: dBandData[dPixelOffset] = ImageUtil
0811: .clampRoundByte(numerator
0812: / denominator);
0813: }
0814:
0815: dPixelOffset += dstPixelStride;
0816: }
0817: }
0818: }
0819: }
0820: }
0821:
0822: private void computeRectUShort(RasterAccessor[] src,
0823: RasterAccessor dst, RasterAccessor[] alfa, Raster[] roi) {
0824: // Save the source count.
0825: int numSources = src.length;
0826:
0827: // Allocate stride, offset, and data arrays for sources.
0828: int[] srcLineStride = new int[numSources];
0829: int[] srcPixelStride = new int[numSources];
0830: int[][] srcBandOffsets = new int[numSources][];
0831: short[][][] srcData = new short[numSources][][];
0832:
0833: // Initialize stride, offset, and data arrays for sources.
0834: for (int i = 0; i < numSources; i++) {
0835: if (src[i] != null) {
0836: srcLineStride[i] = src[i].getScanlineStride();
0837: srcPixelStride[i] = src[i].getPixelStride();
0838: srcBandOffsets[i] = src[i].getBandOffsets();
0839: srcData[i] = src[i].getShortDataArrays();
0840: }
0841: }
0842:
0843: // Initialize destination variables.
0844: int dstMinX = dst.getX();
0845: int dstMinY = dst.getY();
0846: int dstWidth = dst.getWidth();
0847: int dstHeight = dst.getHeight();
0848: int dstMaxX = dstMinX + dstWidth; // x max exclusive
0849: int dstMaxY = dstMinY + dstHeight; // y max exclusive
0850: int dstBands = dst.getNumBands();
0851: int dstLineStride = dst.getScanlineStride();
0852: int dstPixelStride = dst.getPixelStride();
0853: int[] dstBandOffsets = dst.getBandOffsets();
0854: short[][] dstData = dst.getShortDataArrays();
0855:
0856: // Check for alpha.
0857: boolean hasAlpha = false;
0858: for (int i = 0; i < numSources; i++) {
0859: if (alfa[i] != null) {
0860: hasAlpha = true;
0861: break;
0862: }
0863: }
0864:
0865: // Declare alpha channel arrays.
0866: int[] alfaLineStride = null;
0867: int[] alfaPixelStride = null;
0868: int[][] alfaBandOffsets = null;
0869: short[][][] alfaData = null;
0870:
0871: if (hasAlpha) {
0872: // Allocate stride, offset, and data arrays for alpha channels.
0873: alfaLineStride = new int[numSources];
0874: alfaPixelStride = new int[numSources];
0875: alfaBandOffsets = new int[numSources][];
0876: alfaData = new short[numSources][][];
0877:
0878: // Initialize stride, offset, and data arrays for alpha channels.
0879: for (int i = 0; i < numSources; i++) {
0880: if (alfa[i] != null) {
0881: alfaLineStride[i] = alfa[i].getScanlineStride();
0882: alfaPixelStride[i] = alfa[i].getPixelStride();
0883: alfaBandOffsets[i] = alfa[i].getBandOffsets();
0884: alfaData[i] = alfa[i].getShortDataArrays();
0885: }
0886: }
0887: }
0888:
0889: // Initialize weight type arrays.
0890: int[] weightTypes = new int[numSources];
0891: for (int i = 0; i < numSources; i++) {
0892: weightTypes[i] = WEIGHT_TYPE_THRESHOLD;
0893: if (alfa[i] != null) {
0894: weightTypes[i] = WEIGHT_TYPE_ALPHA;
0895: } else if (sourceROI != null && sourceROI[i] != null) {
0896: weightTypes[i] = WEIGHT_TYPE_ROI;
0897: }
0898: }
0899:
0900: // Set up source offset and data variabls.
0901: int[] sLineOffsets = new int[numSources];
0902: int[] sPixelOffsets = new int[numSources];
0903: short[][] sBandData = new short[numSources][];
0904:
0905: // Set up alpha offset and data variabls.
0906: int[] aLineOffsets = null;
0907: int[] aPixelOffsets = null;
0908: short[][] aBandData = null;
0909: if (hasAlpha) {
0910: aLineOffsets = new int[numSources];
0911: aPixelOffsets = new int[numSources];
0912: aBandData = new short[numSources][];
0913: }
0914:
0915: for (int b = 0; b < dstBands; b++) {
0916: // Initialize source and alpha band array and line offsets.
0917: for (int s = 0; s < numSources; s++) {
0918: if (src[s] != null) {
0919: sBandData[s] = srcData[s][b];
0920: sLineOffsets[s] = srcBandOffsets[s][b];
0921: }
0922: if (weightTypes[s] == WEIGHT_TYPE_ALPHA) {
0923: aBandData[s] = alfaData[s][0];
0924: aLineOffsets[s] = alfaBandOffsets[s][0];
0925: }
0926: }
0927:
0928: // Initialize destination band array and line offsets.
0929: short[] dBandData = dstData[b];
0930: int dLineOffset = dstBandOffsets[b];
0931:
0932: if (mosaicType == MosaicDescriptor.MOSAIC_TYPE_OVERLAY) {
0933: for (int dstY = dstMinY; dstY < dstMaxY; dstY++) {
0934: // Initialize source and alpha pixel offsets and
0935: // update line offsets.
0936: for (int s = 0; s < numSources; s++) {
0937: if (src[s] != null) {
0938: sPixelOffsets[s] = sLineOffsets[s];
0939: sLineOffsets[s] += srcLineStride[s];
0940: }
0941: if (alfa[s] != null) {
0942: aPixelOffsets[s] = aLineOffsets[s];
0943: aLineOffsets[s] += alfaLineStride[s];
0944: }
0945: }
0946:
0947: // Initialize destination pixel offset and update
0948: // line offset.
0949: int dPixelOffset = dLineOffset;
0950: dLineOffset += dstLineStride;
0951:
0952: for (int dstX = dstMinX; dstX < dstMaxX; dstX++) {
0953:
0954: // Unset destination update flag.
0955: boolean setDestValue = false;
0956:
0957: // Loop over source until a non-zero weight is
0958: // encountered.
0959: for (int s = 0; s < numSources; s++) {
0960: if (src[s] == null)
0961: continue;
0962:
0963: short sourceValue = sBandData[s][sPixelOffsets[s]];
0964: sPixelOffsets[s] += srcPixelStride[s];
0965:
0966: switch (weightTypes[s]) {
0967: case WEIGHT_TYPE_ALPHA:
0968: setDestValue = aBandData[s][aPixelOffsets[s]] != 0;
0969: aPixelOffsets[s] += alfaPixelStride[s];
0970: break;
0971: case WEIGHT_TYPE_ROI:
0972: setDestValue = roi[s].getSample(dstX,
0973: dstY, 0) > 0;
0974: break;
0975: default: // WEIGHT_TYPE_THRESHOLD
0976: setDestValue = (sourceValue & 0xffff) >= sourceThreshold[s][b];
0977: }
0978:
0979: // Set the destination value if a non-zero
0980: // weight was found.
0981: if (setDestValue) {
0982: dBandData[dPixelOffset] = sourceValue;
0983:
0984: // Increment offset of subsequent sources.
0985: for (int k = s + 1; k < numSources; k++) {
0986: if (src[k] != null) {
0987: sPixelOffsets[k] += srcPixelStride[k];
0988: }
0989: if (alfa[k] != null) {
0990: aPixelOffsets[k] += alfaPixelStride[k];
0991: }
0992: }
0993: break;
0994: }
0995: }
0996:
0997: // Set the destination value to the background if
0998: // no value was set.
0999: if (!setDestValue) {
1000: dBandData[dPixelOffset] = (short) background[b];
1001: }
1002:
1003: dPixelOffset += dstPixelStride;
1004: }
1005: }
1006: } else { // mosaicType == MosaicDescriptor.MOSAIC_TYPE_BLEND
1007: for (int dstY = dstMinY; dstY < dstMaxY; dstY++) {
1008: // Initialize source and alpha pixel offsets and
1009: // update line offsets.
1010: for (int s = 0; s < numSources; s++) {
1011: if (src[s] != null) {
1012: sPixelOffsets[s] = sLineOffsets[s];
1013: sLineOffsets[s] += srcLineStride[s];
1014: }
1015: if (weightTypes[s] == WEIGHT_TYPE_ALPHA) {
1016: aPixelOffsets[s] = aLineOffsets[s];
1017: aLineOffsets[s] += alfaLineStride[s];
1018: }
1019: }
1020:
1021: // Initialize destination pixel offset and update
1022: // line offset.
1023: int dPixelOffset = dLineOffset;
1024: dLineOffset += dstLineStride;
1025:
1026: for (int dstX = dstMinX; dstX < dstMaxX; dstX++) {
1027:
1028: // Clear values for blending ratio.
1029: float numerator = 0.0F;
1030: float denominator = 0.0F;
1031:
1032: // Accumulate into numerator and denominator.
1033: for (int s = 0; s < numSources; s++) {
1034: if (src[s] == null)
1035: continue;
1036:
1037: short sourceValue = sBandData[s][sPixelOffsets[s]];
1038: sPixelOffsets[s] += srcPixelStride[s];
1039:
1040: float weight = 0.0F;
1041: switch (weightTypes[s]) {
1042: case WEIGHT_TYPE_ALPHA:
1043: weight = (aBandData[s][aPixelOffsets[s]] & 0xffff);
1044: if (weight > 0.0F && isAlphaBitmask) {
1045: weight = 1.0F;
1046: } else {
1047: weight /= 65535.0F;
1048: }
1049: aPixelOffsets[s] += alfaPixelStride[s];
1050: break;
1051: case WEIGHT_TYPE_ROI:
1052: weight = roi[s]
1053: .getSample(dstX, dstY, 0) > 0 ? 1.0F
1054: : 0.0F;
1055: break;
1056: default: // WEIGHT_TYPE_THRESHOLD
1057: weight = (sourceValue & 0xffff) >= sourceThreshold[s][b] ? 1.0F
1058: : 0.0F;
1059: }
1060:
1061: // Update numerator and denominator.
1062: numerator += (weight * (sourceValue & 0xffff));
1063: denominator += weight;
1064: }
1065:
1066: // Clear the background if all weights were zero,
1067: // otherwise blend the values.
1068: if (denominator == 0.0) {
1069: dBandData[dPixelOffset] = (short) background[b];
1070: } else {
1071: dBandData[dPixelOffset] = ImageUtil
1072: .clampRoundUShort(numerator
1073: / denominator);
1074: }
1075:
1076: dPixelOffset += dstPixelStride;
1077: }
1078: }
1079: }
1080: }
1081: }
1082:
1083: private void computeRectShort(RasterAccessor[] src,
1084: RasterAccessor dst, RasterAccessor[] alfa, Raster[] roi) {
1085: // Save the source count.
1086: int numSources = src.length;
1087:
1088: // Allocate stride, offset, and data arrays for sources.
1089: int[] srcLineStride = new int[numSources];
1090: int[] srcPixelStride = new int[numSources];
1091: int[][] srcBandOffsets = new int[numSources][];
1092: short[][][] srcData = new short[numSources][][];
1093:
1094: // Initialize stride, offset, and data arrays for sources.
1095: for (int i = 0; i < numSources; i++) {
1096: if (src[i] != null) {
1097: srcLineStride[i] = src[i].getScanlineStride();
1098: srcPixelStride[i] = src[i].getPixelStride();
1099: srcBandOffsets[i] = src[i].getBandOffsets();
1100: srcData[i] = src[i].getShortDataArrays();
1101: }
1102: }
1103:
1104: // Initialize destination variables.
1105: int dstMinX = dst.getX();
1106: int dstMinY = dst.getY();
1107: int dstWidth = dst.getWidth();
1108: int dstHeight = dst.getHeight();
1109: int dstMaxX = dstMinX + dstWidth; // x max exclusive
1110: int dstMaxY = dstMinY + dstHeight; // y max exclusive
1111: int dstBands = dst.getNumBands();
1112: int dstLineStride = dst.getScanlineStride();
1113: int dstPixelStride = dst.getPixelStride();
1114: int[] dstBandOffsets = dst.getBandOffsets();
1115: short[][] dstData = dst.getShortDataArrays();
1116:
1117: // Check for alpha.
1118: boolean hasAlpha = false;
1119: for (int i = 0; i < numSources; i++) {
1120: if (alfa[i] != null) {
1121: hasAlpha = true;
1122: break;
1123: }
1124: }
1125:
1126: // Declare alpha channel arrays.
1127: int[] alfaLineStride = null;
1128: int[] alfaPixelStride = null;
1129: int[][] alfaBandOffsets = null;
1130: short[][][] alfaData = null;
1131:
1132: if (hasAlpha) {
1133: // Allocate stride, offset, and data arrays for alpha channels.
1134: alfaLineStride = new int[numSources];
1135: alfaPixelStride = new int[numSources];
1136: alfaBandOffsets = new int[numSources][];
1137: alfaData = new short[numSources][][];
1138:
1139: // Initialize stride, offset, and data arrays for alpha channels.
1140: for (int i = 0; i < numSources; i++) {
1141: if (alfa[i] != null) {
1142: alfaLineStride[i] = alfa[i].getScanlineStride();
1143: alfaPixelStride[i] = alfa[i].getPixelStride();
1144: alfaBandOffsets[i] = alfa[i].getBandOffsets();
1145: alfaData[i] = alfa[i].getShortDataArrays();
1146: }
1147: }
1148: }
1149:
1150: // Initialize weight type arrays.
1151: int[] weightTypes = new int[numSources];
1152: for (int i = 0; i < numSources; i++) {
1153: weightTypes[i] = WEIGHT_TYPE_THRESHOLD;
1154: if (alfa[i] != null) {
1155: weightTypes[i] = WEIGHT_TYPE_ALPHA;
1156: } else if (sourceROI != null && sourceROI[i] != null) {
1157: weightTypes[i] = WEIGHT_TYPE_ROI;
1158: }
1159: }
1160:
1161: // Set up source offset and data variabls.
1162: int[] sLineOffsets = new int[numSources];
1163: int[] sPixelOffsets = new int[numSources];
1164: short[][] sBandData = new short[numSources][];
1165:
1166: // Set up alpha offset and data variabls.
1167: int[] aLineOffsets = null;
1168: int[] aPixelOffsets = null;
1169: short[][] aBandData = null;
1170: if (hasAlpha) {
1171: aLineOffsets = new int[numSources];
1172: aPixelOffsets = new int[numSources];
1173: aBandData = new short[numSources][];
1174: }
1175:
1176: for (int b = 0; b < dstBands; b++) {
1177: // Initialize source and alpha band array and line offsets.
1178: for (int s = 0; s < numSources; s++) {
1179: if (src[s] != null) {
1180: sBandData[s] = srcData[s][b];
1181: sLineOffsets[s] = srcBandOffsets[s][b];
1182: }
1183: if (weightTypes[s] == WEIGHT_TYPE_ALPHA) {
1184: aBandData[s] = alfaData[s][0];
1185: aLineOffsets[s] = alfaBandOffsets[s][0];
1186: }
1187: }
1188:
1189: // Initialize destination band array and line offsets.
1190: short[] dBandData = dstData[b];
1191: int dLineOffset = dstBandOffsets[b];
1192:
1193: if (mosaicType == MosaicDescriptor.MOSAIC_TYPE_OVERLAY) {
1194: for (int dstY = dstMinY; dstY < dstMaxY; dstY++) {
1195: // Initialize source and alpha pixel offsets and
1196: // update line offsets.
1197: for (int s = 0; s < numSources; s++) {
1198: if (src[s] != null) {
1199: sPixelOffsets[s] = sLineOffsets[s];
1200: sLineOffsets[s] += srcLineStride[s];
1201: }
1202: if (alfa[s] != null) {
1203: aPixelOffsets[s] = aLineOffsets[s];
1204: aLineOffsets[s] += alfaLineStride[s];
1205: }
1206: }
1207:
1208: // Initialize destination pixel offset and update
1209: // line offset.
1210: int dPixelOffset = dLineOffset;
1211: dLineOffset += dstLineStride;
1212:
1213: for (int dstX = dstMinX; dstX < dstMaxX; dstX++) {
1214:
1215: // Unset destination update flag.
1216: boolean setDestValue = false;
1217:
1218: // Loop over source until a non-zero weight is
1219: // encountered.
1220: for (int s = 0; s < numSources; s++) {
1221: if (src[s] == null)
1222: continue;
1223:
1224: short sourceValue = sBandData[s][sPixelOffsets[s]];
1225: sPixelOffsets[s] += srcPixelStride[s];
1226:
1227: switch (weightTypes[s]) {
1228: case WEIGHT_TYPE_ALPHA:
1229: setDestValue = aBandData[s][aPixelOffsets[s]] != 0;
1230: aPixelOffsets[s] += alfaPixelStride[s];
1231: break;
1232: case WEIGHT_TYPE_ROI:
1233: setDestValue = roi[s].getSample(dstX,
1234: dstY, 0) > 0;
1235: break;
1236: default: // WEIGHT_TYPE_THRESHOLD
1237: setDestValue = sourceValue >= sourceThreshold[s][b];
1238: }
1239:
1240: // Set the destination value if a non-zero
1241: // weight was found.
1242: if (setDestValue) {
1243: dBandData[dPixelOffset] = sourceValue;
1244:
1245: // Increment offset of subsequent sources.
1246: for (int k = s + 1; k < numSources; k++) {
1247: if (src[k] != null) {
1248: sPixelOffsets[k] += srcPixelStride[k];
1249: }
1250: if (alfa[k] != null) {
1251: aPixelOffsets[k] += alfaPixelStride[k];
1252: }
1253: }
1254: break;
1255: }
1256: }
1257:
1258: // Set the destination value to the background if
1259: // no value was set.
1260: if (!setDestValue) {
1261: dBandData[dPixelOffset] = (short) background[b];
1262: }
1263:
1264: dPixelOffset += dstPixelStride;
1265: }
1266: }
1267: } else { // mosaicType == MosaicDescriptor.MOSAIC_TYPE_BLEND
1268: for (int dstY = dstMinY; dstY < dstMaxY; dstY++) {
1269: // Initialize source and alpha pixel offsets and
1270: // update line offsets.
1271: for (int s = 0; s < numSources; s++) {
1272: if (src[s] != null) {
1273: sPixelOffsets[s] = sLineOffsets[s];
1274: sLineOffsets[s] += srcLineStride[s];
1275: }
1276: if (weightTypes[s] == WEIGHT_TYPE_ALPHA) {
1277: aPixelOffsets[s] = aLineOffsets[s];
1278: aLineOffsets[s] += alfaLineStride[s];
1279: }
1280: }
1281:
1282: // Initialize destination pixel offset and update
1283: // line offset.
1284: int dPixelOffset = dLineOffset;
1285: dLineOffset += dstLineStride;
1286:
1287: for (int dstX = dstMinX; dstX < dstMaxX; dstX++) {
1288:
1289: // Clear values for blending ratio.
1290: float numerator = 0.0F;
1291: float denominator = 0.0F;
1292:
1293: // Accumulate into numerator and denominator.
1294: for (int s = 0; s < numSources; s++) {
1295: if (src[s] == null)
1296: continue;
1297:
1298: short sourceValue = sBandData[s][sPixelOffsets[s]];
1299: sPixelOffsets[s] += srcPixelStride[s];
1300:
1301: float weight = 0.0F;
1302: switch (weightTypes[s]) {
1303: case WEIGHT_TYPE_ALPHA:
1304: weight = aBandData[s][aPixelOffsets[s]];
1305: if (weight > 0.0F && isAlphaBitmask) {
1306: weight = 1.0F;
1307: } else {
1308: weight /= (float) Short.MAX_VALUE;
1309: }
1310: aPixelOffsets[s] += alfaPixelStride[s];
1311: break;
1312: case WEIGHT_TYPE_ROI:
1313: weight = roi[s]
1314: .getSample(dstX, dstY, 0) > 0 ? 1.0F
1315: : 0.0F;
1316: break;
1317: default: // WEIGHT_TYPE_THRESHOLD
1318: weight = sourceValue >= sourceThreshold[s][b] ? 1.0F
1319: : 0.0F;
1320: }
1321:
1322: // Update numerator and denominator.
1323: numerator += weight * sourceValue;
1324: denominator += weight;
1325: }
1326:
1327: // Clear the background if all weights were zero,
1328: // otherwise blend the values.
1329: if (denominator == 0.0) {
1330: dBandData[dPixelOffset] = (short) background[b];
1331: } else {
1332: dBandData[dPixelOffset] = ImageUtil
1333: .clampRoundShort(numerator
1334: / denominator);
1335: }
1336:
1337: dPixelOffset += dstPixelStride;
1338: }
1339: }
1340: }
1341: }
1342: }
1343:
1344: private void computeRectInt(RasterAccessor[] src,
1345: RasterAccessor dst, RasterAccessor[] alfa, Raster[] roi) {
1346: // Save the source count.
1347: int numSources = src.length;
1348:
1349: // Allocate stride, offset, and data arrays for sources.
1350: int[] srcLineStride = new int[numSources];
1351: int[] srcPixelStride = new int[numSources];
1352: int[][] srcBandOffsets = new int[numSources][];
1353: int[][][] srcData = new int[numSources][][];
1354:
1355: // Initialize stride, offset, and data arrays for sources.
1356: for (int i = 0; i < numSources; i++) {
1357: if (src[i] != null) {
1358: srcLineStride[i] = src[i].getScanlineStride();
1359: srcPixelStride[i] = src[i].getPixelStride();
1360: srcBandOffsets[i] = src[i].getBandOffsets();
1361: srcData[i] = src[i].getIntDataArrays();
1362: }
1363: }
1364:
1365: // Initialize destination variables.
1366: int dstMinX = dst.getX();
1367: int dstMinY = dst.getY();
1368: int dstWidth = dst.getWidth();
1369: int dstHeight = dst.getHeight();
1370: int dstMaxX = dstMinX + dstWidth; // x max exclusive
1371: int dstMaxY = dstMinY + dstHeight; // y max exclusive
1372: int dstBands = dst.getNumBands();
1373: int dstLineStride = dst.getScanlineStride();
1374: int dstPixelStride = dst.getPixelStride();
1375: int[] dstBandOffsets = dst.getBandOffsets();
1376: int[][] dstData = dst.getIntDataArrays();
1377:
1378: // Check for alpha.
1379: boolean hasAlpha = false;
1380: for (int i = 0; i < numSources; i++) {
1381: if (alfa[i] != null) {
1382: hasAlpha = true;
1383: break;
1384: }
1385: }
1386:
1387: // Declare alpha channel arrays.
1388: int[] alfaLineStride = null;
1389: int[] alfaPixelStride = null;
1390: int[][] alfaBandOffsets = null;
1391: int[][][] alfaData = null;
1392:
1393: if (hasAlpha) {
1394: // Allocate stride, offset, and data arrays for alpha channels.
1395: alfaLineStride = new int[numSources];
1396: alfaPixelStride = new int[numSources];
1397: alfaBandOffsets = new int[numSources][];
1398: alfaData = new int[numSources][][];
1399:
1400: // Initialize stride, offset, and data arrays for alpha channels.
1401: for (int i = 0; i < numSources; i++) {
1402: if (alfa[i] != null) {
1403: alfaLineStride[i] = alfa[i].getScanlineStride();
1404: alfaPixelStride[i] = alfa[i].getPixelStride();
1405: alfaBandOffsets[i] = alfa[i].getBandOffsets();
1406: alfaData[i] = alfa[i].getIntDataArrays();
1407: }
1408: }
1409: }
1410:
1411: // Initialize weight type arrays.
1412: int[] weightTypes = new int[numSources];
1413: for (int i = 0; i < numSources; i++) {
1414: weightTypes[i] = WEIGHT_TYPE_THRESHOLD;
1415: if (alfa[i] != null) {
1416: weightTypes[i] = WEIGHT_TYPE_ALPHA;
1417: } else if (sourceROI != null && sourceROI[i] != null) {
1418: weightTypes[i] = WEIGHT_TYPE_ROI;
1419: }
1420: }
1421:
1422: // Set up source offset and data variabls.
1423: int[] sLineOffsets = new int[numSources];
1424: int[] sPixelOffsets = new int[numSources];
1425: int[][] sBandData = new int[numSources][];
1426:
1427: // Set up alpha offset and data variabls.
1428: int[] aLineOffsets = null;
1429: int[] aPixelOffsets = null;
1430: int[][] aBandData = null;
1431: if (hasAlpha) {
1432: aLineOffsets = new int[numSources];
1433: aPixelOffsets = new int[numSources];
1434: aBandData = new int[numSources][];
1435: }
1436:
1437: for (int b = 0; b < dstBands; b++) {
1438: // Initialize source and alpha band array and line offsets.
1439: for (int s = 0; s < numSources; s++) {
1440: if (src[s] != null) {
1441: sBandData[s] = srcData[s][b];
1442: sLineOffsets[s] = srcBandOffsets[s][b];
1443: }
1444: if (weightTypes[s] == WEIGHT_TYPE_ALPHA) {
1445: aBandData[s] = alfaData[s][0];
1446: aLineOffsets[s] = alfaBandOffsets[s][0];
1447: }
1448: }
1449:
1450: // Initialize destination band array and line offsets.
1451: int[] dBandData = dstData[b];
1452: int dLineOffset = dstBandOffsets[b];
1453:
1454: if (mosaicType == MosaicDescriptor.MOSAIC_TYPE_OVERLAY) {
1455: for (int dstY = dstMinY; dstY < dstMaxY; dstY++) {
1456: // Initialize source and alpha pixel offsets and
1457: // update line offsets.
1458: for (int s = 0; s < numSources; s++) {
1459: if (src[s] != null) {
1460: sPixelOffsets[s] = sLineOffsets[s];
1461: sLineOffsets[s] += srcLineStride[s];
1462: }
1463: if (alfa[s] != null) {
1464: aPixelOffsets[s] = aLineOffsets[s];
1465: aLineOffsets[s] += alfaLineStride[s];
1466: }
1467: }
1468:
1469: // Initialize destination pixel offset and update
1470: // line offset.
1471: int dPixelOffset = dLineOffset;
1472: dLineOffset += dstLineStride;
1473:
1474: for (int dstX = dstMinX; dstX < dstMaxX; dstX++) {
1475:
1476: // Unset destination update flag.
1477: boolean setDestValue = false;
1478:
1479: // Loop over source until a non-zero weight is
1480: // encountered.
1481: for (int s = 0; s < numSources; s++) {
1482: if (src[s] == null)
1483: continue;
1484:
1485: int sourceValue = sBandData[s][sPixelOffsets[s]];
1486: sPixelOffsets[s] += srcPixelStride[s];
1487:
1488: switch (weightTypes[s]) {
1489: case WEIGHT_TYPE_ALPHA:
1490: setDestValue = aBandData[s][aPixelOffsets[s]] != 0;
1491: aPixelOffsets[s] += alfaPixelStride[s];
1492: break;
1493: case WEIGHT_TYPE_ROI:
1494: setDestValue = roi[s].getSample(dstX,
1495: dstY, 0) > 0;
1496: break;
1497: default: // WEIGHT_TYPE_THRESHOLD
1498: setDestValue = sourceValue >= sourceThreshold[s][b];
1499: }
1500:
1501: // Set the destination value if a non-zero
1502: // weight was found.
1503: if (setDestValue) {
1504: dBandData[dPixelOffset] = sourceValue;
1505:
1506: // Increment offset of subsequent sources.
1507: for (int k = s + 1; k < numSources; k++) {
1508: if (src[k] != null) {
1509: sPixelOffsets[k] += srcPixelStride[k];
1510: }
1511: if (alfa[k] != null) {
1512: aPixelOffsets[k] += alfaPixelStride[k];
1513: }
1514: }
1515: break;
1516: }
1517: }
1518:
1519: // Set the destination value to the background if
1520: // no value was set.
1521: if (!setDestValue) {
1522: dBandData[dPixelOffset] = (int) background[b];
1523: }
1524:
1525: dPixelOffset += dstPixelStride;
1526: }
1527: }
1528: } else { // mosaicType == MosaicDescriptor.MOSAIC_TYPE_BLEND
1529: for (int dstY = dstMinY; dstY < dstMaxY; dstY++) {
1530: // Initialize source and alpha pixel offsets and
1531: // update line offsets.
1532: for (int s = 0; s < numSources; s++) {
1533: if (src[s] != null) {
1534: sPixelOffsets[s] = sLineOffsets[s];
1535: sLineOffsets[s] += srcLineStride[s];
1536: }
1537: if (weightTypes[s] == WEIGHT_TYPE_ALPHA) {
1538: aPixelOffsets[s] = aLineOffsets[s];
1539: aLineOffsets[s] += alfaLineStride[s];
1540: }
1541: }
1542:
1543: // Initialize destination pixel offset and update
1544: // line offset.
1545: int dPixelOffset = dLineOffset;
1546: dLineOffset += dstLineStride;
1547:
1548: for (int dstX = dstMinX; dstX < dstMaxX; dstX++) {
1549:
1550: // Clear values for blending ratio.
1551: double numerator = 0.0;
1552: double denominator = 0.0;
1553:
1554: // Accumulate into numerator and denominator.
1555: for (int s = 0; s < numSources; s++) {
1556: if (src[s] == null)
1557: continue;
1558:
1559: int sourceValue = sBandData[s][sPixelOffsets[s]];
1560: sPixelOffsets[s] += srcPixelStride[s];
1561:
1562: double weight = 0.0;
1563: switch (weightTypes[s]) {
1564: case WEIGHT_TYPE_ALPHA:
1565: weight = aBandData[s][aPixelOffsets[s]];
1566: if (weight > 0.0F && isAlphaBitmask) {
1567: weight = 1.0F;
1568: } else {
1569: weight /= Integer.MAX_VALUE;
1570: }
1571: aPixelOffsets[s] += alfaPixelStride[s];
1572: break;
1573: case WEIGHT_TYPE_ROI:
1574: weight = roi[s]
1575: .getSample(dstX, dstY, 0) > 0 ? 1.0F
1576: : 0.0F;
1577: break;
1578: default: // WEIGHT_TYPE_THRESHOLD
1579: weight = sourceValue >= sourceThreshold[s][b] ? 1.0F
1580: : 0.0F;
1581: }
1582:
1583: // Update numerator and denominator.
1584: numerator += weight * sourceValue;
1585: denominator += weight;
1586: }
1587:
1588: // Clear the background if all weights were zero,
1589: // otherwise blend the values.
1590: if (denominator == 0.0) {
1591: dBandData[dPixelOffset] = (int) background[b];
1592: } else {
1593: dBandData[dPixelOffset] = ImageUtil
1594: .clampRoundInt(numerator
1595: / denominator);
1596: }
1597:
1598: dPixelOffset += dstPixelStride;
1599: }
1600: }
1601: }
1602: }
1603: }
1604:
1605: private void computeRectFloat(RasterAccessor[] src,
1606: RasterAccessor dst, RasterAccessor[] alfa, Raster[] roi) {
1607: // Save the source count.
1608: int numSources = src.length;
1609:
1610: // Allocate stride, offset, and data arrays for sources.
1611: int[] srcLineStride = new int[numSources];
1612: int[] srcPixelStride = new int[numSources];
1613: int[][] srcBandOffsets = new int[numSources][];
1614: float[][][] srcData = new float[numSources][][];
1615:
1616: // Initialize stride, offset, and data arrays for sources.
1617: for (int i = 0; i < numSources; i++) {
1618: if (src[i] != null) {
1619: srcLineStride[i] = src[i].getScanlineStride();
1620: srcPixelStride[i] = src[i].getPixelStride();
1621: srcBandOffsets[i] = src[i].getBandOffsets();
1622: srcData[i] = src[i].getFloatDataArrays();
1623: }
1624: }
1625:
1626: // Initialize destination variables.
1627: int dstMinX = dst.getX();
1628: int dstMinY = dst.getY();
1629: int dstWidth = dst.getWidth();
1630: int dstHeight = dst.getHeight();
1631: int dstMaxX = dstMinX + dstWidth; // x max exclusive
1632: int dstMaxY = dstMinY + dstHeight; // y max exclusive
1633: int dstBands = dst.getNumBands();
1634: int dstLineStride = dst.getScanlineStride();
1635: int dstPixelStride = dst.getPixelStride();
1636: int[] dstBandOffsets = dst.getBandOffsets();
1637: float[][] dstData = dst.getFloatDataArrays();
1638:
1639: // Check for alpha.
1640: boolean hasAlpha = false;
1641: for (int i = 0; i < numSources; i++) {
1642: if (alfa[i] != null) {
1643: hasAlpha = true;
1644: break;
1645: }
1646: }
1647:
1648: // Declare alpha channel arrays.
1649: int[] alfaLineStride = null;
1650: int[] alfaPixelStride = null;
1651: int[][] alfaBandOffsets = null;
1652: float[][][] alfaData = null;
1653:
1654: if (hasAlpha) {
1655: // Allocate stride, offset, and data arrays for alpha channels.
1656: alfaLineStride = new int[numSources];
1657: alfaPixelStride = new int[numSources];
1658: alfaBandOffsets = new int[numSources][];
1659: alfaData = new float[numSources][][];
1660:
1661: // Initialize stride, offset, and data arrays for alpha channels.
1662: for (int i = 0; i < numSources; i++) {
1663: if (alfa[i] != null) {
1664: alfaLineStride[i] = alfa[i].getScanlineStride();
1665: alfaPixelStride[i] = alfa[i].getPixelStride();
1666: alfaBandOffsets[i] = alfa[i].getBandOffsets();
1667: alfaData[i] = alfa[i].getFloatDataArrays();
1668: }
1669: }
1670: }
1671:
1672: // Initialize weight type arrays.
1673: int[] weightTypes = new int[numSources];
1674: for (int i = 0; i < numSources; i++) {
1675: weightTypes[i] = WEIGHT_TYPE_THRESHOLD;
1676: if (alfa[i] != null) {
1677: weightTypes[i] = WEIGHT_TYPE_ALPHA;
1678: } else if (sourceROI != null && sourceROI[i] != null) {
1679: weightTypes[i] = WEIGHT_TYPE_ROI;
1680: }
1681: }
1682:
1683: // Set up source offset and data variabls.
1684: int[] sLineOffsets = new int[numSources];
1685: int[] sPixelOffsets = new int[numSources];
1686: float[][] sBandData = new float[numSources][];
1687:
1688: // Set up alpha offset and data variabls.
1689: int[] aLineOffsets = null;
1690: int[] aPixelOffsets = null;
1691: float[][] aBandData = null;
1692: if (hasAlpha) {
1693: aLineOffsets = new int[numSources];
1694: aPixelOffsets = new int[numSources];
1695: aBandData = new float[numSources][];
1696: }
1697:
1698: for (int b = 0; b < dstBands; b++) {
1699: // Initialize source and alpha band array and line offsets.
1700: for (int s = 0; s < numSources; s++) {
1701: if (src[s] != null) {
1702: sBandData[s] = srcData[s][b];
1703: sLineOffsets[s] = srcBandOffsets[s][b];
1704: }
1705: if (weightTypes[s] == WEIGHT_TYPE_ALPHA) {
1706: aBandData[s] = alfaData[s][0];
1707: aLineOffsets[s] = alfaBandOffsets[s][0];
1708: }
1709: }
1710:
1711: // Initialize destination band array and line offsets.
1712: float[] dBandData = dstData[b];
1713: int dLineOffset = dstBandOffsets[b];
1714:
1715: if (mosaicType == MosaicDescriptor.MOSAIC_TYPE_OVERLAY) {
1716: for (int dstY = dstMinY; dstY < dstMaxY; dstY++) {
1717: // Initialize source and alpha pixel offsets and
1718: // update line offsets.
1719: for (int s = 0; s < numSources; s++) {
1720: if (src[s] != null) {
1721: sPixelOffsets[s] = sLineOffsets[s];
1722: sLineOffsets[s] += srcLineStride[s];
1723: }
1724: if (alfa[s] != null) {
1725: aPixelOffsets[s] = aLineOffsets[s];
1726: aLineOffsets[s] += alfaLineStride[s];
1727: }
1728: }
1729:
1730: // Initialize destination pixel offset and update
1731: // line offset.
1732: int dPixelOffset = dLineOffset;
1733: dLineOffset += dstLineStride;
1734:
1735: for (int dstX = dstMinX; dstX < dstMaxX; dstX++) {
1736:
1737: // Unset destination update flag.
1738: boolean setDestValue = false;
1739:
1740: // Loop over source until a non-zero weight is
1741: // encountered.
1742: for (int s = 0; s < numSources; s++) {
1743: if (src[s] == null)
1744: continue;
1745:
1746: float sourceValue = sBandData[s][sPixelOffsets[s]];
1747: sPixelOffsets[s] += srcPixelStride[s];
1748:
1749: switch (weightTypes[s]) {
1750: case WEIGHT_TYPE_ALPHA:
1751: setDestValue = aBandData[s][aPixelOffsets[s]] != 0;
1752: aPixelOffsets[s] += alfaPixelStride[s];
1753: break;
1754: case WEIGHT_TYPE_ROI:
1755: setDestValue = roi[s].getSample(dstX,
1756: dstY, 0) > 0;
1757: break;
1758: default: // WEIGHT_TYPE_THRESHOLD
1759: setDestValue = sourceValue >= sourceThreshold[s][b];
1760: }
1761:
1762: // Set the destination value if a non-zero
1763: // weight was found.
1764: if (setDestValue) {
1765: dBandData[dPixelOffset] = sourceValue;
1766:
1767: // Increment offset of subsequent sources.
1768: for (int k = s + 1; k < numSources; k++) {
1769: if (src[k] != null) {
1770: sPixelOffsets[k] += srcPixelStride[k];
1771: }
1772: if (alfa[k] != null) {
1773: aPixelOffsets[k] += alfaPixelStride[k];
1774: }
1775: }
1776: break;
1777: }
1778: }
1779:
1780: // Set the destination value to the background if
1781: // no value was set.
1782: if (!setDestValue) {
1783: dBandData[dPixelOffset] = (float) backgroundValues[b];
1784: }
1785:
1786: dPixelOffset += dstPixelStride;
1787: }
1788: }
1789: } else { // mosaicType == MosaicDescriptor.MOSAIC_TYPE_BLEND
1790: for (int dstY = dstMinY; dstY < dstMaxY; dstY++) {
1791: // Initialize source and alpha pixel offsets and
1792: // update line offsets.
1793: for (int s = 0; s < numSources; s++) {
1794: if (src[s] != null) {
1795: sPixelOffsets[s] = sLineOffsets[s];
1796: sLineOffsets[s] += srcLineStride[s];
1797: }
1798: if (weightTypes[s] == WEIGHT_TYPE_ALPHA) {
1799: aPixelOffsets[s] = aLineOffsets[s];
1800: aLineOffsets[s] += alfaLineStride[s];
1801: }
1802: }
1803:
1804: // Initialize destination pixel offset and update
1805: // line offset.
1806: int dPixelOffset = dLineOffset;
1807: dLineOffset += dstLineStride;
1808:
1809: for (int dstX = dstMinX; dstX < dstMaxX; dstX++) {
1810:
1811: // Clear values for blending ratio.
1812: float numerator = 0.0F;
1813: float denominator = 0.0F;
1814:
1815: // Accumulate into numerator and denominator.
1816: for (int s = 0; s < numSources; s++) {
1817: if (src[s] == null)
1818: continue;
1819:
1820: float sourceValue = sBandData[s][sPixelOffsets[s]];
1821: sPixelOffsets[s] += srcPixelStride[s];
1822:
1823: float weight = 0.0F;
1824: switch (weightTypes[s]) {
1825: case WEIGHT_TYPE_ALPHA:
1826: weight = aBandData[s][aPixelOffsets[s]];
1827: if (weight > 0.0F && isAlphaBitmask) {
1828: weight = 1.0F;
1829: }
1830: aPixelOffsets[s] += alfaPixelStride[s];
1831: break;
1832: case WEIGHT_TYPE_ROI:
1833: weight = roi[s]
1834: .getSample(dstX, dstY, 0) > 0 ? 1.0F
1835: : 0.0F;
1836: break;
1837: default: // WEIGHT_TYPE_THRESHOLD
1838: weight = sourceValue >= sourceThreshold[s][b] ? 1.0F
1839: : 0.0F;
1840: }
1841:
1842: // Update numerator and denominator.
1843: numerator += weight * sourceValue;
1844: denominator += weight;
1845: }
1846:
1847: // Clear the background if all weights were zero,
1848: // otherwise blend the values.
1849: if (denominator == 0.0) {
1850: dBandData[dPixelOffset] = (float) backgroundValues[b];
1851: } else {
1852: dBandData[dPixelOffset] = numerator
1853: / denominator;
1854: }
1855:
1856: dPixelOffset += dstPixelStride;
1857: }
1858: }
1859: }
1860: }
1861: }
1862:
1863: private void computeRectDouble(RasterAccessor[] src,
1864: RasterAccessor dst, RasterAccessor[] alfa, Raster[] roi) {
1865: // Save the source count.
1866: int numSources = src.length;
1867:
1868: // Allocate stride, offset, and data arrays for sources.
1869: int[] srcLineStride = new int[numSources];
1870: int[] srcPixelStride = new int[numSources];
1871: int[][] srcBandOffsets = new int[numSources][];
1872: double[][][] srcData = new double[numSources][][];
1873:
1874: // Initialize stride, offset, and data arrays for sources.
1875: for (int i = 0; i < numSources; i++) {
1876: if (src[i] != null) {
1877: srcLineStride[i] = src[i].getScanlineStride();
1878: srcPixelStride[i] = src[i].getPixelStride();
1879: srcBandOffsets[i] = src[i].getBandOffsets();
1880: srcData[i] = src[i].getDoubleDataArrays();
1881: }
1882: }
1883:
1884: // Initialize destination variables.
1885: int dstMinX = dst.getX();
1886: int dstMinY = dst.getY();
1887: int dstWidth = dst.getWidth();
1888: int dstHeight = dst.getHeight();
1889: int dstMaxX = dstMinX + dstWidth; // x max exclusive
1890: int dstMaxY = dstMinY + dstHeight; // y max exclusive
1891: int dstBands = dst.getNumBands();
1892: int dstLineStride = dst.getScanlineStride();
1893: int dstPixelStride = dst.getPixelStride();
1894: int[] dstBandOffsets = dst.getBandOffsets();
1895: double[][] dstData = dst.getDoubleDataArrays();
1896:
1897: // Check for alpha.
1898: boolean hasAlpha = false;
1899: for (int i = 0; i < numSources; i++) {
1900: if (alfa[i] != null) {
1901: hasAlpha = true;
1902: break;
1903: }
1904: }
1905:
1906: // Declare alpha channel arrays.
1907: int[] alfaLineStride = null;
1908: int[] alfaPixelStride = null;
1909: int[][] alfaBandOffsets = null;
1910: double[][][] alfaData = null;
1911:
1912: if (hasAlpha) {
1913: // Allocate stride, offset, and data arrays for alpha channels.
1914: alfaLineStride = new int[numSources];
1915: alfaPixelStride = new int[numSources];
1916: alfaBandOffsets = new int[numSources][];
1917: alfaData = new double[numSources][][];
1918:
1919: // Initialize stride, offset, and data arrays for alpha channels.
1920: for (int i = 0; i < numSources; i++) {
1921: if (alfa[i] != null) {
1922: alfaLineStride[i] = alfa[i].getScanlineStride();
1923: alfaPixelStride[i] = alfa[i].getPixelStride();
1924: alfaBandOffsets[i] = alfa[i].getBandOffsets();
1925: alfaData[i] = alfa[i].getDoubleDataArrays();
1926: }
1927: }
1928: }
1929:
1930: // Initialize weight type arrays.
1931: int[] weightTypes = new int[numSources];
1932: for (int i = 0; i < numSources; i++) {
1933: weightTypes[i] = WEIGHT_TYPE_THRESHOLD;
1934: if (alfa[i] != null) {
1935: weightTypes[i] = WEIGHT_TYPE_ALPHA;
1936: } else if (sourceROI != null && sourceROI[i] != null) {
1937: weightTypes[i] = WEIGHT_TYPE_ROI;
1938: }
1939: }
1940:
1941: // Set up source offset and data variabls.
1942: int[] sLineOffsets = new int[numSources];
1943: int[] sPixelOffsets = new int[numSources];
1944: double[][] sBandData = new double[numSources][];
1945:
1946: // Set up alpha offset and data variabls.
1947: int[] aLineOffsets = null;
1948: int[] aPixelOffsets = null;
1949: double[][] aBandData = null;
1950: if (hasAlpha) {
1951: aLineOffsets = new int[numSources];
1952: aPixelOffsets = new int[numSources];
1953: aBandData = new double[numSources][];
1954: }
1955:
1956: for (int b = 0; b < dstBands; b++) {
1957: // Initialize source and alpha band array and line offsets.
1958: for (int s = 0; s < numSources; s++) {
1959: if (src[s] != null) {
1960: sBandData[s] = srcData[s][b];
1961: sLineOffsets[s] = srcBandOffsets[s][b];
1962: }
1963: if (weightTypes[s] == WEIGHT_TYPE_ALPHA) {
1964: aBandData[s] = alfaData[s][0];
1965: aLineOffsets[s] = alfaBandOffsets[s][0];
1966: }
1967: }
1968:
1969: // Initialize destination band array and line offsets.
1970: double[] dBandData = dstData[b];
1971: int dLineOffset = dstBandOffsets[b];
1972:
1973: if (mosaicType == MosaicDescriptor.MOSAIC_TYPE_OVERLAY) {
1974: for (int dstY = dstMinY; dstY < dstMaxY; dstY++) {
1975: // Initialize source and alpha pixel offsets and
1976: // update line offsets.
1977: for (int s = 0; s < numSources; s++) {
1978: if (src[s] != null) {
1979: sPixelOffsets[s] = sLineOffsets[s];
1980: sLineOffsets[s] += srcLineStride[s];
1981: }
1982: if (alfa[s] != null) {
1983: aPixelOffsets[s] = aLineOffsets[s];
1984: aLineOffsets[s] += alfaLineStride[s];
1985: }
1986: }
1987:
1988: // Initialize destination pixel offset and update
1989: // line offset.
1990: int dPixelOffset = dLineOffset;
1991: dLineOffset += dstLineStride;
1992:
1993: for (int dstX = dstMinX; dstX < dstMaxX; dstX++) {
1994:
1995: // Unset destination update flag.
1996: boolean setDestValue = false;
1997:
1998: // Loop over source until a non-zero weight is
1999: // encountered.
2000: for (int s = 0; s < numSources; s++) {
2001: if (src[s] == null)
2002: continue;
2003:
2004: double sourceValue = sBandData[s][sPixelOffsets[s]];
2005: sPixelOffsets[s] += srcPixelStride[s];
2006:
2007: switch (weightTypes[s]) {
2008: case WEIGHT_TYPE_ALPHA:
2009: setDestValue = aBandData[s][aPixelOffsets[s]] != 0;
2010: aPixelOffsets[s] += alfaPixelStride[s];
2011: break;
2012: case WEIGHT_TYPE_ROI:
2013: setDestValue = roi[s].getSample(dstX,
2014: dstY, 0) > 0;
2015: break;
2016: default: // WEIGHT_TYPE_THRESHOLD
2017: setDestValue = sourceValue >= sourceThreshold[s][b];
2018: }
2019:
2020: // Set the destination value if a non-zero
2021: // weight was found.
2022: if (setDestValue) {
2023: dBandData[dPixelOffset] = sourceValue;
2024:
2025: // Increment offset of subsequent sources.
2026: for (int k = s + 1; k < numSources; k++) {
2027: if (src[k] != null) {
2028: sPixelOffsets[k] += srcPixelStride[k];
2029: }
2030: if (alfa[k] != null) {
2031: aPixelOffsets[k] += alfaPixelStride[k];
2032: }
2033: }
2034: break;
2035: }
2036: }
2037:
2038: // Set the destination value to the background if
2039: // no value was set.
2040: if (!setDestValue) {
2041: dBandData[dPixelOffset] = backgroundValues[b];
2042: }
2043:
2044: dPixelOffset += dstPixelStride;
2045: }
2046: }
2047: } else { // mosaicType == MosaicDescriptor.MOSAIC_TYPE_BLEND
2048: for (int dstY = dstMinY; dstY < dstMaxY; dstY++) {
2049: // Initialize source and alpha pixel offsets and
2050: // update line offsets.
2051: for (int s = 0; s < numSources; s++) {
2052: if (src[s] != null) {
2053: sPixelOffsets[s] = sLineOffsets[s];
2054: sLineOffsets[s] += srcLineStride[s];
2055: }
2056: if (weightTypes[s] == WEIGHT_TYPE_ALPHA) {
2057: aPixelOffsets[s] = aLineOffsets[s];
2058: aLineOffsets[s] += alfaLineStride[s];
2059: }
2060: }
2061:
2062: // Initialize destination pixel offset and update
2063: // line offset.
2064: int dPixelOffset = dLineOffset;
2065: dLineOffset += dstLineStride;
2066:
2067: for (int dstX = dstMinX; dstX < dstMaxX; dstX++) {
2068:
2069: // Clear values for blending ratio.
2070: double numerator = 0.0F;
2071: double denominator = 0.0F;
2072:
2073: // Accumulate into numerator and denominator.
2074: for (int s = 0; s < numSources; s++) {
2075: if (src[s] == null)
2076: continue;
2077:
2078: double sourceValue = sBandData[s][sPixelOffsets[s]];
2079: sPixelOffsets[s] += srcPixelStride[s];
2080:
2081: double weight = 0.0F;
2082: switch (weightTypes[s]) {
2083: case WEIGHT_TYPE_ALPHA:
2084: weight = aBandData[s][aPixelOffsets[s]];
2085: if (weight > 0.0F && isAlphaBitmask) {
2086: weight = 1.0F;
2087: }
2088: aPixelOffsets[s] += alfaPixelStride[s];
2089: break;
2090: case WEIGHT_TYPE_ROI:
2091: weight = roi[s]
2092: .getSample(dstX, dstY, 0) > 0 ? 1.0F
2093: : 0.0F;
2094: break;
2095: default: // WEIGHT_TYPE_THRESHOLD
2096: weight = sourceValue >= sourceThreshold[s][b] ? 1.0F
2097: : 0.0F;
2098: }
2099:
2100: // Update numerator and denominator.
2101: numerator += weight * sourceValue;
2102: denominator += weight;
2103: }
2104:
2105: // Clear the background if all weights were zero,
2106: // otherwise blend the values.
2107: if (denominator == 0.0) {
2108: dBandData[dPixelOffset] = backgroundValues[b];
2109: } else {
2110: dBandData[dPixelOffset] = numerator
2111: / denominator;
2112: }
2113:
2114: dPixelOffset += dstPixelStride;
2115: }
2116: }
2117: }
2118: }
2119: }
2120: }
|