0001: /*
0002: * $RCSfile: CompositeOpImage.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/12/08 00:58:33 $
0010: * $State: Exp $
0011: */
0012: package com.sun.media.jai.opimage;
0013:
0014: import java.awt.Rectangle;
0015: import java.awt.image.ColorModel;
0016: import java.awt.image.IndexColorModel;
0017: import java.awt.image.DataBuffer;
0018: import java.awt.image.Raster;
0019: import java.awt.image.RenderedImage;
0020: import java.awt.image.SampleModel;
0021: import java.awt.image.WritableRaster;
0022: import java.util.Map;
0023: import javax.media.jai.ImageLayout;
0024: import javax.media.jai.OpImage;
0025: import javax.media.jai.PointOpImage;
0026: import javax.media.jai.RasterAccessor;
0027: import javax.media.jai.RasterFormatTag;
0028: import javax.media.jai.RasterFactory;
0029: import com.sun.media.jai.util.ImageUtil;
0030: import com.sun.media.jai.util.JDKWorkarounds;
0031:
0032: // import com.sun.media.jai.test.OpImageTester;
0033:
0034: /**
0035: * An <code>OpImage</code> implementing the "Composite" operation as
0036: * described in <code>javax.media.jai.operator.CompositeDescriptor</code>.
0037: *
0038: * <p>For two source images <code>src1</code> and <code>src2</code>,
0039: * this <code>OpImage</code> places the foreground <code>src1</code>
0040: * in front of the background <code>src2</code>. This is what commonly
0041: * known as the "over" composite.
0042: *
0043: * <p>The destination image contains both the alpha channel and the
0044: * color channels. The alpha channel index is determined by the parameter
0045: * <code>alphaFirst</code>: if true, alpha is the first channel; if false,
0046: * alpha is the last channel. The formulas used to calculate destination
0047: * alpha and color values are:
0048: * <pre>
0049: * dstAlpha = src1Alpha + src2Alpha * (1 - src1Alpha)
0050: * dstColor = src1Color + src2Color * (1 - src1Alpha)
0051: * </pre>
0052: * where alpha values are in fraction format, and color values are alpha
0053: * pre-multiplied.
0054: *
0055: * <p>The following assumptions are made:
0056: * <li>The source images, their alpha images, and the destination image all
0057: * have the same data type.</li>
0058: * <li>The two source images have the same number of bands and should only
0059: * contain the color channels.</li>
0060: * <li>The alpha images are of the same dimension as their cooresponding source
0061: * image and should be single-banded. If a multi-banded image is supplied, the
0062: * default band (band 0) is used.</li>
0063: * <li>If <code>alphaPremultiplied</code> is true, both the source and
0064: * destination images have alpha pre-multiplied, and vice versa.</li>
0065: * <li>The destination image must have at least one extra band than the two
0066: * sources, which represents the alpha channel. It may be user-specified
0067: * to be the first or the last band of the pixel data.</li>
0068: *
0069: * @see javax.media.jai.operator.CompositeDescriptor
0070: * @see CompositeCRIF
0071: *
0072: */
0073: final class CompositeOpImage extends PointOpImage {
0074:
0075: /** The alpha image that overrides the alpha for source1. */
0076: protected RenderedImage source1Alpha;
0077:
0078: /** The alpha image that overrides the alpha for source2. */
0079: protected RenderedImage source2Alpha;
0080:
0081: /** Indicates whether alpha has been premultiplied. */
0082: protected boolean alphaPremultiplied;
0083:
0084: /** The alpha and color band offset. */
0085: private int aOffset; // alpha channel offset
0086: private int cOffset; // color channels offset
0087:
0088: /** Maximum Value supported by the data type if it's integral types. */
0089: private byte maxValueByte;
0090: private short maxValueShort;
0091: private int maxValue;
0092: private float invMaxValue; // 1 / maxValue
0093:
0094: /**
0095: * Constructs an <code>CompositeOpImage</code>.
0096: *
0097: * @param source1 The foreground source image.
0098: * @param source2 The background source image.
0099: * @param layout The destination image layout.
0100: * @param source1Alpha The alpha image that overrides the
0101: * alpha for source1; may not be null.
0102: * @param source2Alpha The alpha image that overrides the alpha for
0103: * source2; may be null, in which case source2
0104: * is considered completely opaque.
0105: * @param alphaPremultiplied Indicates whether alpha has been
0106: * premultiplied to both sources.
0107: * @param alphaFirst If true, alpha is the first band (band 0) in
0108: * destination image; if false, alpha is the
0109: * last band.
0110: */
0111: public CompositeOpImage(RenderedImage source1,
0112: RenderedImage source2, Map config, ImageLayout layout,
0113: RenderedImage source1Alpha, RenderedImage source2Alpha,
0114: boolean alphaPremultiplied, boolean alphaFirst) {
0115: super (source1, source2, layout, config, true);
0116:
0117: this .source1Alpha = source1Alpha;
0118: this .source2Alpha = source2Alpha;
0119: this .alphaPremultiplied = alphaPremultiplied;
0120:
0121: SampleModel sm = source1.getSampleModel();
0122: ColorModel cm = source1.getColorModel();
0123: int dtype = sm.getTransferType();
0124: int bands;
0125: if (cm instanceof IndexColorModel) {
0126: bands = cm.getNumComponents();
0127: } else {
0128: bands = sm.getNumBands();
0129: }
0130: bands += 1; // one additional alpha channel
0131:
0132: if (sampleModel.getTransferType() != dtype
0133: || sampleModel.getNumBands() != bands) {
0134: /*
0135: * The current destination sampleModel is not suitable for the
0136: * two sources and their alpha images.
0137: * Create a suitable sampleModel for the destination image.
0138: */
0139: sampleModel = RasterFactory.createComponentSampleModel(
0140: sampleModel, dtype, tileWidth, tileHeight, bands);
0141:
0142: if (colorModel != null
0143: && !JDKWorkarounds.areCompatibleDataModels(
0144: sampleModel, colorModel)) {
0145: colorModel = ImageUtil.getCompatibleColorModel(
0146: sampleModel, config);
0147: }
0148: }
0149:
0150: aOffset = alphaFirst ? 0 : bands - 1;
0151: cOffset = alphaFirst ? 1 : 0;
0152:
0153: switch (dtype) {
0154: case DataBuffer.TYPE_BYTE:
0155: maxValue = 0xFF; // byte is unsigned
0156: maxValueByte = (byte) 0xFF;
0157: break;
0158: case DataBuffer.TYPE_USHORT:
0159: maxValue = 0xFFFF;
0160: maxValueShort = (short) 0xFFFF;
0161: break;
0162: case DataBuffer.TYPE_SHORT:
0163: maxValue = Short.MAX_VALUE;
0164: maxValueShort = Short.MAX_VALUE;
0165: break;
0166: case DataBuffer.TYPE_INT:
0167: maxValue = Integer.MAX_VALUE;
0168: break;
0169: default:
0170: }
0171: invMaxValue = 1.0F / maxValue;
0172: }
0173:
0174: /**
0175: * Composites two images within a specified rectangle.
0176: *
0177: * @param sources Cobbled source, guaranteed to provide all the
0178: * source data necessary for computing the rectangle.
0179: * @param dest The tile containing the rectangle to be computed.
0180: * @param destRect The rectangle within the tile to be computed.
0181: */
0182: protected void computeRect(Raster[] sources, WritableRaster dest,
0183: Rectangle destRect) {
0184: /* For PointOpImage, srcRect = destRect. */
0185: RenderedImage[] renderedSources = source2Alpha == null ? new RenderedImage[3]
0186: : new RenderedImage[4];
0187: renderedSources[0] = getSourceImage(0);
0188: renderedSources[1] = getSourceImage(1);
0189: renderedSources[2] = source1Alpha;
0190: Raster source1AlphaRaster = source1Alpha.getData(destRect);
0191: Raster source2AlphaRaster = null;
0192: if (source2Alpha != null) {
0193: renderedSources[3] = source2Alpha;
0194: source2AlphaRaster = source2Alpha.getData(destRect);
0195: }
0196:
0197: RasterFormatTag tags[] = RasterAccessor.findCompatibleTags(
0198: renderedSources, this );
0199: RasterAccessor s1 = new RasterAccessor(sources[0], destRect,
0200: tags[0], getSourceImage(0).getColorModel());
0201: RasterAccessor s2 = new RasterAccessor(sources[1], destRect,
0202: tags[1], getSourceImage(1).getColorModel());
0203: RasterAccessor a1 = new RasterAccessor(source1AlphaRaster,
0204: destRect, tags[2], source1Alpha.getColorModel());
0205: RasterAccessor a2 = null, d = null;
0206:
0207: if (source2Alpha != null) {
0208: a2 = new RasterAccessor(source2AlphaRaster, destRect,
0209: tags[3], source2Alpha.getColorModel());
0210: d = new RasterAccessor(dest, destRect, tags[4], this
0211: .getColorModel());
0212: } else {
0213: a2 = null;
0214: d = new RasterAccessor(dest, destRect, tags[3], this
0215: .getColorModel());
0216: }
0217:
0218: switch (d.getDataType()) {
0219: case DataBuffer.TYPE_BYTE:
0220: byteLoop(s1, s2, a1, a2, d);
0221: break;
0222: case DataBuffer.TYPE_USHORT:
0223: ushortLoop(s1, s2, a1, a2, d);
0224: break;
0225: case DataBuffer.TYPE_SHORT:
0226: shortLoop(s1, s2, a1, a2, d);
0227: break;
0228: case DataBuffer.TYPE_INT:
0229: intLoop(s1, s2, a1, a2, d);
0230: break;
0231: case DataBuffer.TYPE_FLOAT:
0232: floatLoop(s1, s2, a1, a2, d);
0233: break;
0234: case DataBuffer.TYPE_DOUBLE:
0235: doubleLoop(s1, s2, a1, a2, d);
0236: break;
0237: }
0238: d.copyDataToRaster();
0239: }
0240:
0241: /*
0242: * Formulas for integral data types:
0243: *
0244: * d[alpha] = dstAlpha * maxValue
0245: * = (src1Alpha + src2Alpha * (1 - src1Alpha)) * maxValue
0246: * if (source2 is opaque (src2Alpha = 1)) {
0247: * d[alpha] = (src1Alpha + 1 * (1 - src1Alpha)) * maxValue
0248: * = maxValue
0249: * } else {
0250: * d[alpha] = (a1/maxValue + a2/maxValue * (1 - a1/maxValue)) * maxValue
0251: * = a1 + a2 * (1 - a1/maxValue)
0252: * }
0253: *
0254: * if (alpha pre-multiplied to sources and destination) {
0255: * d[color] = dstColor
0256: * = src1Color + src2Color * (1 - src1Alpha)
0257: * = s1 + s2 * (1 - a1/maxValue)
0258: * } else {
0259: * if (source2 is opaque (src2Alpha = 1 & dstAlpha = 1)) {
0260: * d[color] = dstColor / dstAlpha
0261: * = (src1Color + src2Color * (1 - src1Alpha))
0262: * = s1 * a1/maxValue + s2 * (1 - a1/maxValue)
0263: * } else {
0264: * d[color] = dstColor / dstAlpha
0265: * = (src1Color + src2Color * (1 - src1Alpha)) / dstAlpha
0266: * = (s1 * a1/maxValue + s2 * a2/maxValue *
0267: * (1 - a1/maxValue)) / (d[alpha]/maxValue)
0268: * = (s1 * a1 + s2 * a2 * (1 - a1/maxValue)) / d[alpha]
0269: * }
0270: * }
0271: */
0272:
0273: private void byteLoop(RasterAccessor src1, RasterAccessor src2,
0274: RasterAccessor afa1, RasterAccessor afa2, RasterAccessor dst) {
0275: int dwidth = dst.getWidth();
0276: int dheight = dst.getHeight();
0277: int numBands = src1.getNumBands();
0278:
0279: /* First source color channels. */
0280: byte[][] s1 = src1.getByteDataArrays();
0281: int s1ss = src1.getScanlineStride(); // scanline stride
0282: int s1ps = src1.getPixelStride(); // pixel stride
0283: int[] s1bo = src1.getBandOffsets(); // band offsets
0284:
0285: /* Second source color channels. */
0286: byte[][] s2 = src2.getByteDataArrays();
0287: int s2ss = src2.getScanlineStride(); // scanline stride
0288: int s2ps = src2.getPixelStride(); // pixel stride
0289: int[] s2bo = src2.getBandOffsets(); // band offsets
0290:
0291: /* First source alpha channel. */
0292: byte[] a1 = afa1.getByteDataArray(0); // use band 0
0293: int a1ss = afa1.getScanlineStride(); // scanline stride
0294: int a1ps = afa1.getPixelStride(); // pixel stride
0295: int a1bo = afa1.getBandOffset(0); // band 0 offsets
0296:
0297: /* Second source alpha channel (if any). */
0298: byte[] a2 = null;
0299: int a2ss = 0;
0300: int a2ps = 0;
0301: int a2bo = 0;
0302: if (afa2 != null) {
0303: a2 = afa2.getByteDataArray(0); // use band 0
0304: a2ss = afa2.getScanlineStride(); // scanline stride
0305: a2ps = afa2.getPixelStride(); // pixel stride
0306: a2bo = afa2.getBandOffset(0); // band 0 offset
0307: }
0308:
0309: /* Destination color and alpha channels. */
0310: byte[][] d = dst.getByteDataArrays();
0311: int dss = dst.getScanlineStride(); // scanline stride
0312: int dps = dst.getPixelStride(); // pixel stride
0313: int[] dbo = dst.getBandOffsets(); // band offsets
0314:
0315: int s1so = 0, s2so = 0, a1so = 0, a2so = 0, dso = 0;
0316: int s1po, s2po, a1po, a2po, dpo; // po = pixel offset
0317: if (alphaPremultiplied) {
0318: if (afa2 == null) {
0319: for (int h = 0; h < dheight; h++) {
0320: s1po = s1so;
0321: s2po = s2so;
0322: a1po = a1so;
0323: dpo = dso;
0324:
0325: for (int w = 0; w < dwidth; w++) {
0326: float t = 1.0F - (a1[a1po + a1bo] & 0xFF)
0327: * invMaxValue;
0328:
0329: /* Destination alpha channel. */
0330: d[aOffset][dpo + dbo[aOffset]] = maxValueByte;
0331:
0332: /* Destination color channels. */
0333: for (int b = 0; b < numBands; b++) {
0334: int i = b + cOffset;
0335: d[i][dpo + dbo[i]] = (byte) ((s1[b][s1po
0336: + s1bo[b]] & 0xFF) + (s2[b][s2po
0337: + s2bo[b]] & 0xFF)
0338: * t);
0339: }
0340:
0341: s1po += s1ps;
0342: s2po += s2ps;
0343: a1po += a1ps;
0344: dpo += dps;
0345: }
0346:
0347: s1so += s1ss;
0348: s2so += s2ss;
0349: a1so += a1ss;
0350: dso += dss;
0351: }
0352: } else {
0353: for (int h = 0; h < dheight; h++) {
0354: s1po = s1so;
0355: s2po = s2so;
0356: a1po = a1so;
0357: a2po = a2so;
0358: dpo = dso;
0359:
0360: for (int w = 0; w < dwidth; w++) {
0361: int t1 = a1[a1po + a1bo] & 0xFF; // a1
0362: float t2 = 1.0F - t1 * invMaxValue; // 1-a1/maxValue
0363:
0364: /* Destination alpha channel. */
0365: d[aOffset][dpo + dbo[aOffset]] = (byte) (t1 + (a2[a2po
0366: + a2bo] & 0xFF)
0367: * t2);
0368:
0369: /* Destination color channels. */
0370: for (int b = 0; b < numBands; b++) {
0371: int i = b + cOffset;
0372: d[i][dpo + dbo[i]] = (byte) ((s1[b][s1po
0373: + s1bo[b]] & 0xFF) + (s2[b][s2po
0374: + s2bo[b]] & 0xFF)
0375: * t2);
0376: }
0377:
0378: s1po += s1ps;
0379: s2po += s2ps;
0380: a1po += a1ps;
0381: a2po += a2ps;
0382: dpo += dps;
0383: }
0384:
0385: s1so += s1ss;
0386: s2so += s2ss;
0387: a1so += a1ss;
0388: a2so += a2ss;
0389: dso += dss;
0390: }
0391: }
0392: } else {
0393: if (afa2 == null) {
0394: for (int h = 0; h < dheight; h++) {
0395: s1po = s1so;
0396: s2po = s2so;
0397: a1po = a1so;
0398: dpo = dso;
0399:
0400: for (int w = 0; w < dwidth; w++) {
0401: float t1 = (a1[a1po + a1bo] & 0xFF)
0402: * invMaxValue;
0403: float t2 = 1.0F - t1; // 1-a1/maxValue
0404:
0405: /* Destination alpha channel. */
0406: d[aOffset][dpo + dbo[aOffset]] = maxValueByte;
0407:
0408: /* Destination color channels. */
0409: for (int b = 0; b < numBands; b++) {
0410: int i = b + cOffset;
0411: d[i][dpo + dbo[i]] = (byte) ((s1[b][s1po
0412: + s1bo[b]] & 0xFF)
0413: * t1 + (s2[b][s2po + s2bo[b]] & 0xFF)
0414: * t2);
0415: }
0416:
0417: s1po += s1ps;
0418: s2po += s2ps;
0419: a1po += a1ps;
0420: dpo += dps;
0421: }
0422:
0423: s1so += s1ss;
0424: s2so += s2ss;
0425: a1so += a1ss;
0426: dso += dss;
0427: }
0428: } else {
0429: for (int h = 0; h < dheight; h++) {
0430: s1po = s1so;
0431: s2po = s2so;
0432: a1po = a1so;
0433: a2po = a2so;
0434: dpo = dso;
0435:
0436: for (int w = 0; w < dwidth; w++) {
0437: int t1 = a1[a1po + a1bo] & 0xFF; // a1
0438: float t2 = (1.0F - t1 * invMaxValue)
0439: * (a2[a2po + a2bo] & 0xFF); // a2*(1-a1/maxValue)
0440: float t3 = t1 + t2; // d[alpha]
0441: float t4, t5;
0442: if (t3 == 0.0F) {
0443: t4 = 0.0F;
0444: t5 = 0.0F;
0445: } else {
0446: t4 = t1 / t3;
0447: t5 = t2 / t3;
0448: }
0449:
0450: /* Destination alpha channel. */
0451: d[aOffset][dpo + dbo[aOffset]] = (byte) t3;
0452:
0453: /* Destination color channels. */
0454: for (int b = 0; b < numBands; b++) {
0455: int i = b + cOffset;
0456: d[i][dpo + dbo[i]] = (byte) ((s1[b][s1po
0457: + s1bo[b]] & 0xFF)
0458: * t4 + (s2[b][s2po + s2bo[b]] & 0xFF)
0459: * t5);
0460: }
0461:
0462: s1po += s1ps;
0463: s2po += s2ps;
0464: a1po += a1ps;
0465: a2po += a2ps;
0466: dpo += dps;
0467: }
0468:
0469: s1so += s1ss;
0470: s2so += s2ss;
0471: a1so += a1ss;
0472: a2so += a2ss;
0473: dso += dss;
0474: }
0475: }
0476: }
0477: }
0478:
0479: private void ushortLoop(RasterAccessor src1, RasterAccessor src2,
0480: RasterAccessor afa1, RasterAccessor afa2, RasterAccessor dst) {
0481: int dwidth = dst.getWidth();
0482: int dheight = dst.getHeight();
0483: int numBands = src1.getNumBands();
0484:
0485: /* First source color channels. */
0486: short[][] s1 = src1.getShortDataArrays();
0487: int s1ss = src1.getScanlineStride(); // scanline stride
0488: int s1ps = src1.getPixelStride(); // pixel stride
0489: int[] s1bo = src1.getBandOffsets(); // band offsets
0490:
0491: /* Second source color channels. */
0492: short[][] s2 = src2.getShortDataArrays();
0493: int s2ss = src2.getScanlineStride(); // scanline stride
0494: int s2ps = src2.getPixelStride(); // pixel stride
0495: int[] s2bo = src2.getBandOffsets(); // band offsets
0496:
0497: /* First source alpha channel. */
0498: short[] a1 = afa1.getShortDataArray(0); // use band 0
0499: int a1ss = afa1.getScanlineStride(); // scanline stride
0500: int a1ps = afa1.getPixelStride(); // pixel stride
0501: int a1bo = afa1.getBandOffset(0); // band 0 offsets
0502:
0503: /* Second source alpha channel (if any). */
0504: short[] a2 = null;
0505: int a2ss = 0;
0506: int a2ps = 0;
0507: int a2bo = 0;
0508: if (afa2 != null) {
0509: a2 = afa2.getShortDataArray(0); // use band 0
0510: a2ss = afa2.getScanlineStride(); // scanline stride
0511: a2ps = afa2.getPixelStride(); // pixel stride
0512: a2bo = afa2.getBandOffset(0); // band 0 offset
0513: }
0514:
0515: /* Destination color and alpha channels. */
0516: short[][] d = dst.getShortDataArrays();
0517: int dss = dst.getScanlineStride(); // scanline stride
0518: int dps = dst.getPixelStride(); // pixel stride
0519: int[] dbo = dst.getBandOffsets(); // band offsets
0520:
0521: int s1so = 0, s2so = 0, a1so = 0, a2so = 0, dso = 0;
0522: int s1po, s2po, a1po, a2po, dpo; // po = pixel offset
0523: if (alphaPremultiplied) {
0524: if (afa2 == null) {
0525: for (int h = 0; h < dheight; h++) {
0526: s1po = s1so;
0527: s2po = s2so;
0528: a1po = a1so;
0529: dpo = dso;
0530:
0531: for (int w = 0; w < dwidth; w++) {
0532: float t = 1.0F - (a1[a1po + a1bo] & 0xFFFF)
0533: * invMaxValue;
0534:
0535: /* Destination alpha channel. */
0536: d[aOffset][dpo + dbo[aOffset]] = maxValueShort;
0537:
0538: /* Destination color channels. */
0539: for (int b = 0; b < numBands; b++) {
0540: int i = b + cOffset;
0541: d[i][dpo + dbo[i]] = (short) ((s1[b][s1po
0542: + s1bo[b]] & 0xFFFF) + (s2[b][s2po
0543: + s2bo[b]] & 0xFFFF)
0544: * t);
0545: }
0546:
0547: s1po += s1ps;
0548: s2po += s2ps;
0549: a1po += a1ps;
0550: dpo += dps;
0551: }
0552:
0553: s1so += s1ss;
0554: s2so += s2ss;
0555: a1so += a1ss;
0556: dso += dss;
0557: }
0558: } else {
0559: for (int h = 0; h < dheight; h++) {
0560: s1po = s1so;
0561: s2po = s2so;
0562: a1po = a1so;
0563: a2po = a2so;
0564: dpo = dso;
0565:
0566: for (int w = 0; w < dwidth; w++) {
0567: int t1 = a1[a1po + a1bo] & 0xFFFF; // a1
0568: float t2 = 1.0F - t1 * invMaxValue; // 1-a1/maxValue
0569:
0570: /* Destination alpha channel. */
0571: d[aOffset][dpo + dbo[aOffset]] = (short) (t1 + (a2[a2po
0572: + a2bo] & 0xFFFF)
0573: * t2);
0574:
0575: /* Destination color channels. */
0576: for (int b = 0; b < numBands; b++) {
0577: int i = b + cOffset;
0578: d[i][dpo + dbo[i]] = (short) ((s1[b][s1po
0579: + s1bo[b]] & 0xFFFF) + (s2[b][s2po
0580: + s2bo[b]] & 0xFFFF)
0581: * t2);
0582: }
0583:
0584: s1po += s1ps;
0585: s2po += s2ps;
0586: a1po += a1ps;
0587: a2po += a2ps;
0588: dpo += dps;
0589: }
0590:
0591: s1so += s1ss;
0592: s2so += s2ss;
0593: a1so += a1ss;
0594: a2so += a2ss;
0595: dso += dss;
0596: }
0597: }
0598: } else {
0599: if (afa2 == null) {
0600: for (int h = 0; h < dheight; h++) {
0601: s1po = s1so;
0602: s2po = s2so;
0603: a1po = a1so;
0604: dpo = dso;
0605:
0606: for (int w = 0; w < dwidth; w++) {
0607: float t1 = (a1[a1po + a1bo] & 0xFFFF)
0608: * invMaxValue;
0609: float t2 = 1.0F - t1; // 1-a1/maxValue
0610:
0611: /* Destination alpha channel. */
0612: d[aOffset][dpo + dbo[aOffset]] = maxValueShort;
0613:
0614: /* Destination color channels. */
0615: for (int b = 0; b < numBands; b++) {
0616: int i = b + cOffset;
0617: d[i][dpo + dbo[i]] = (short) ((s1[b][s1po
0618: + s1bo[b]] & 0xFFFF)
0619: * t1 + (s2[b][s2po + s2bo[b]] & 0xFFFF)
0620: * t2);
0621: }
0622:
0623: s1po += s1ps;
0624: s2po += s2ps;
0625: a1po += a1ps;
0626: dpo += dps;
0627: }
0628:
0629: s1so += s1ss;
0630: s2so += s2ss;
0631: a1so += a1ss;
0632: dso += dss;
0633: }
0634: } else {
0635: for (int h = 0; h < dheight; h++) {
0636: s1po = s1so;
0637: s2po = s2so;
0638: a1po = a1so;
0639: a2po = a2so;
0640: dpo = dso;
0641:
0642: for (int w = 0; w < dwidth; w++) {
0643: int t1 = a1[a1po + a1bo] & 0xFFFF; // a1
0644: float t2 = (1.0F - t1 * invMaxValue)
0645: * (a2[a2po + a2bo] & 0xFFFF); // a2*(1-a1/maxValue)
0646: float t3 = t1 + t2; // d[alpha]
0647: float t4, t5;
0648: if (t3 == 0.0F) {
0649: t4 = 0.0F;
0650: t5 = 0.0F;
0651: } else {
0652: t4 = t1 / t3;
0653: t5 = t2 / t3;
0654: }
0655:
0656: /* Destination alpha channel. */
0657: d[aOffset][dpo + dbo[aOffset]] = (short) t3;
0658:
0659: /* Destination color channels. */
0660: for (int b = 0; b < numBands; b++) {
0661: int i = b + cOffset;
0662: d[i][dpo + dbo[i]] = (short) ((s1[b][s1po
0663: + s1bo[b]] & 0xFFFF)
0664: * t4 + (s2[b][s2po + s2bo[b]] & 0xFFFF)
0665: * t5);
0666: }
0667:
0668: s1po += s1ps;
0669: s2po += s2ps;
0670: a1po += a1ps;
0671: a2po += a2ps;
0672: dpo += dps;
0673: }
0674:
0675: s1so += s1ss;
0676: s2so += s2ss;
0677: a1so += a1ss;
0678: a2so += a2ss;
0679: dso += dss;
0680: }
0681: }
0682: }
0683: }
0684:
0685: private void shortLoop(RasterAccessor src1, RasterAccessor src2,
0686: RasterAccessor afa1, RasterAccessor afa2, RasterAccessor dst) {
0687: int dwidth = dst.getWidth();
0688: int dheight = dst.getHeight();
0689: int numBands = src1.getNumBands();
0690:
0691: /* First source color channels. */
0692: short[][] s1 = src1.getShortDataArrays();
0693: int s1ss = src1.getScanlineStride(); // scanline stride
0694: int s1ps = src1.getPixelStride(); // pixel stride
0695: int[] s1bo = src1.getBandOffsets(); // band offsets
0696:
0697: /* Second source color channels. */
0698: short[][] s2 = src2.getShortDataArrays();
0699: int s2ss = src2.getScanlineStride(); // scanline stride
0700: int s2ps = src2.getPixelStride(); // pixel stride
0701: int[] s2bo = src2.getBandOffsets(); // band offsets
0702:
0703: /* First source alpha channel. */
0704: short[] a1 = afa1.getShortDataArray(0); // use band 0
0705: int a1ss = afa1.getScanlineStride(); // scanline stride
0706: int a1ps = afa1.getPixelStride(); // pixel stride
0707: int a1bo = afa1.getBandOffset(0); // band 0 offsets
0708:
0709: /* Second source alpha channel (if any). */
0710: short[] a2 = null;
0711: int a2ss = 0;
0712: int a2ps = 0;
0713: int a2bo = 0;
0714: if (afa2 != null) {
0715: a2 = afa2.getShortDataArray(0); // use band 0
0716: a2ss = afa2.getScanlineStride(); // scanline stride
0717: a2ps = afa2.getPixelStride(); // pixel stride
0718: a2bo = afa2.getBandOffset(0); // band 0 offset
0719: }
0720:
0721: /* Destination color and alpha channels. */
0722: short[][] d = dst.getShortDataArrays();
0723: int dss = dst.getScanlineStride(); // scanline stride
0724: int dps = dst.getPixelStride(); // pixel stride
0725: int[] dbo = dst.getBandOffsets(); // band offsets
0726:
0727: int s1so = 0, s2so = 0, a1so = 0, a2so = 0, dso = 0;
0728: int s1po, s2po, a1po, a2po, dpo; // po = pixel offset
0729: if (alphaPremultiplied) {
0730: if (afa2 == null) {
0731: for (int h = 0; h < dheight; h++) {
0732: s1po = s1so;
0733: s2po = s2so;
0734: a1po = a1so;
0735: dpo = dso;
0736:
0737: for (int w = 0; w < dwidth; w++) {
0738: float t = 1.0F - a1[a1po + a1bo] * invMaxValue;
0739:
0740: /* Destination alpha channel. */
0741: d[aOffset][dpo + dbo[aOffset]] = maxValueShort;
0742:
0743: /* Destination color channels. */
0744: for (int b = 0; b < numBands; b++) {
0745: int i = b + cOffset;
0746: d[i][dpo + dbo[i]] = (short) (s1[b][s1po
0747: + s1bo[b]] + s2[b][s2po + s2bo[b]]
0748: * t);
0749: }
0750:
0751: s1po += s1ps;
0752: s2po += s2ps;
0753: a1po += a1ps;
0754: dpo += dps;
0755: }
0756:
0757: s1so += s1ss;
0758: s2so += s2ss;
0759: a1so += a1ss;
0760: dso += dss;
0761: }
0762: } else {
0763: for (int h = 0; h < dheight; h++) {
0764: s1po = s1so;
0765: s2po = s2so;
0766: a1po = a1so;
0767: a2po = a2so;
0768: dpo = dso;
0769:
0770: for (int w = 0; w < dwidth; w++) {
0771: int t1 = a1[a1po + a1bo]; // a1
0772: float t2 = 1.0F - t1 * invMaxValue; // 1-a1/maxValue
0773:
0774: /* Destination alpha channel. */
0775: d[aOffset][dpo + dbo[aOffset]] = (short) (t1 + a2[a2po
0776: + a2bo]
0777: * t2);
0778:
0779: /* Destination color channels. */
0780: for (int b = 0; b < numBands; b++) {
0781: int i = b + cOffset;
0782: d[i][dpo + dbo[i]] = (short) (s1[b][s1po
0783: + s1bo[b]] + s2[b][s2po + s2bo[b]]
0784: * t2);
0785: }
0786:
0787: s1po += s1ps;
0788: s2po += s2ps;
0789: a1po += a1ps;
0790: a2po += a2ps;
0791: dpo += dps;
0792: }
0793:
0794: s1so += s1ss;
0795: s2so += s2ss;
0796: a1so += a1ss;
0797: a2so += a2ss;
0798: dso += dss;
0799: }
0800: }
0801: } else {
0802: if (afa2 == null) {
0803: for (int h = 0; h < dheight; h++) {
0804: s1po = s1so;
0805: s2po = s2so;
0806: a1po = a1so;
0807: dpo = dso;
0808:
0809: for (int w = 0; w < dwidth; w++) {
0810: float t1 = a1[a1po + a1bo] * invMaxValue;
0811: float t2 = 1.0F - t1; // 1-a1/maxValue
0812:
0813: /* Destination alpha channel. */
0814: d[aOffset][dpo + dbo[aOffset]] = maxValueShort;
0815:
0816: /* Destination color channels. */
0817: for (int b = 0; b < numBands; b++) {
0818: int i = b + cOffset;
0819: d[i][dpo + dbo[i]] = (short) (s1[b][s1po
0820: + s1bo[b]]
0821: * t1 + s2[b][s2po + s2bo[b]] * t2);
0822: }
0823:
0824: s1po += s1ps;
0825: s2po += s2ps;
0826: a1po += a1ps;
0827: dpo += dps;
0828: }
0829:
0830: s1so += s1ss;
0831: s2so += s2ss;
0832: a1so += a1ss;
0833: dso += dss;
0834: }
0835: } else {
0836: for (int h = 0; h < dheight; h++) {
0837: s1po = s1so;
0838: s2po = s2so;
0839: a1po = a1so;
0840: a2po = a2so;
0841: dpo = dso;
0842:
0843: for (int w = 0; w < dwidth; w++) {
0844: int t1 = a1[a1po + a1bo]; // a1
0845: float t2 = (1.0F - t1 * invMaxValue)
0846: * a2[a2po + a2bo]; // a2*(1-a1/maxValue)
0847: float t3 = t1 + t2; // d[alpha]
0848: float t4, t5;
0849: if (t3 == 0.0F) {
0850: t4 = 0.0F;
0851: t5 = 0.0F;
0852: } else {
0853: t4 = t1 / t3;
0854: t5 = t2 / t3;
0855: }
0856:
0857: /* Destination alpha channel. */
0858: d[aOffset][dpo + dbo[aOffset]] = (short) t3;
0859:
0860: /* Destination color channels. */
0861: for (int b = 0; b < numBands; b++) {
0862: int i = b + cOffset;
0863: d[i][dpo + dbo[i]] = (short) (s1[b][s1po
0864: + s1bo[b]]
0865: * t4 + s2[b][s2po + s2bo[b]] * t5);
0866: }
0867:
0868: s1po += s1ps;
0869: s2po += s2ps;
0870: a1po += a1ps;
0871: a2po += a2ps;
0872: dpo += dps;
0873: }
0874:
0875: s1so += s1ss;
0876: s2so += s2ss;
0877: a1so += a1ss;
0878: a2so += a2ss;
0879: dso += dss;
0880: }
0881: }
0882: }
0883: }
0884:
0885: private void intLoop(RasterAccessor src1, RasterAccessor src2,
0886: RasterAccessor afa1, RasterAccessor afa2, RasterAccessor dst) {
0887: int dwidth = dst.getWidth();
0888: int dheight = dst.getHeight();
0889: int numBands = src1.getNumBands();
0890:
0891: /* First source color channels. */
0892: int[][] s1 = src1.getIntDataArrays();
0893: int s1ss = src1.getScanlineStride(); // scanline stride
0894: int s1ps = src1.getPixelStride(); // pixel stride
0895: int[] s1bo = src1.getBandOffsets(); // band offsets
0896:
0897: /* Second source color channels. */
0898: int[][] s2 = src2.getIntDataArrays();
0899: int s2ss = src2.getScanlineStride(); // scanline stride
0900: int s2ps = src2.getPixelStride(); // pixel stride
0901: int[] s2bo = src2.getBandOffsets(); // band offsets
0902:
0903: /* First source alpha channel. */
0904: int[] a1 = afa1.getIntDataArray(0); // use band 0
0905: int a1ss = afa1.getScanlineStride(); // scanline stride
0906: int a1ps = afa1.getPixelStride(); // pixel stride
0907: int a1bo = afa1.getBandOffset(0); // band 0 offsets
0908:
0909: /* Second source alpha channel (if any). */
0910: int[] a2 = null;
0911: int a2ss = 0;
0912: int a2ps = 0;
0913: int a2bo = 0;
0914: if (afa2 != null) {
0915: a2 = afa2.getIntDataArray(0); // use band 0
0916: a2ss = afa2.getScanlineStride(); // scanline stride
0917: a2ps = afa2.getPixelStride(); // pixel stride
0918: a2bo = afa2.getBandOffset(0); // band 0 offset
0919: }
0920:
0921: /* Destination color and alpha channels. */
0922: int[][] d = dst.getIntDataArrays();
0923: int dss = dst.getScanlineStride(); // scanline stride
0924: int dps = dst.getPixelStride(); // pixel stride
0925: int[] dbo = dst.getBandOffsets(); // band offsets
0926:
0927: int s1so = 0, s2so = 0, a1so = 0, a2so = 0, dso = 0;
0928: int s1po, s2po, a1po, a2po, dpo; // po = pixel offset
0929: if (alphaPremultiplied) {
0930: if (afa2 == null) {
0931: for (int h = 0; h < dheight; h++) {
0932: s1po = s1so;
0933: s2po = s2so;
0934: a1po = a1so;
0935: dpo = dso;
0936:
0937: for (int w = 0; w < dwidth; w++) {
0938: float t = 1.0F - a1[a1po + a1bo] * invMaxValue;
0939:
0940: /* Destination alpha channel. */
0941: d[aOffset][dpo + dbo[aOffset]] = maxValue;
0942:
0943: /* Destination color channels. */
0944: for (int b = 0; b < numBands; b++) {
0945: int i = b + cOffset;
0946: d[i][dpo + dbo[i]] = (int) (s1[b][s1po
0947: + s1bo[b]] + s2[b][s2po + s2bo[b]]
0948: * t);
0949: }
0950:
0951: s1po += s1ps;
0952: s2po += s2ps;
0953: a1po += a1ps;
0954: dpo += dps;
0955: }
0956:
0957: s1so += s1ss;
0958: s2so += s2ss;
0959: a1so += a1ss;
0960: dso += dss;
0961: }
0962: } else {
0963: for (int h = 0; h < dheight; h++) {
0964: s1po = s1so;
0965: s2po = s2so;
0966: a1po = a1so;
0967: a2po = a2so;
0968: dpo = dso;
0969:
0970: for (int w = 0; w < dwidth; w++) {
0971: int t1 = a1[a1po + a1bo]; // a1
0972: float t2 = 1.0F - t1 * invMaxValue; // 1-a1/maxValue
0973:
0974: /* Destination alpha channel. */
0975: d[aOffset][dpo + dbo[aOffset]] = (int) (t1 + a2[a2po
0976: + a2bo]
0977: * t2);
0978:
0979: /* Destination color channels. */
0980: for (int b = 0; b < numBands; b++) {
0981: int i = b + cOffset;
0982: d[i][dpo + dbo[i]] = (int) (s1[b][s1po
0983: + s1bo[b]] + s2[b][s2po + s2bo[b]]
0984: * t2);
0985: }
0986:
0987: s1po += s1ps;
0988: s2po += s2ps;
0989: a1po += a1ps;
0990: a2po += a2ps;
0991: dpo += dps;
0992: }
0993:
0994: s1so += s1ss;
0995: s2so += s2ss;
0996: a1so += a1ss;
0997: a2so += a2ss;
0998: dso += dss;
0999: }
1000: }
1001: } else {
1002: if (afa2 == null) {
1003: for (int h = 0; h < dheight; h++) {
1004: s1po = s1so;
1005: s2po = s2so;
1006: a1po = a1so;
1007: dpo = dso;
1008:
1009: for (int w = 0; w < dwidth; w++) {
1010: float t1 = a1[a1po + a1bo] * invMaxValue; // a1/maxValue
1011: float t2 = 1.0F - t1; // 1-a1/maxValue
1012:
1013: /* Destination alpha channel. */
1014: d[aOffset][dpo + dbo[aOffset]] = maxValue;
1015:
1016: /* Destination color channels. */
1017: for (int b = 0; b < numBands; b++) {
1018: int i = b + cOffset;
1019: d[i][dpo + dbo[i]] = (int) (s1[b][s1po
1020: + s1bo[b]]
1021: * t1 + s2[b][s2po + s2bo[b]] * t2);
1022: }
1023:
1024: s1po += s1ps;
1025: s2po += s2ps;
1026: a1po += a1ps;
1027: dpo += dps;
1028: }
1029:
1030: s1so += s1ss;
1031: s2so += s2ss;
1032: a1so += a1ss;
1033: dso += dss;
1034: }
1035: } else {
1036: for (int h = 0; h < dheight; h++) {
1037: s1po = s1so;
1038: s2po = s2so;
1039: a1po = a1so;
1040: a2po = a2so;
1041: dpo = dso;
1042:
1043: for (int w = 0; w < dwidth; w++) {
1044: int t1 = a1[a1po + a1bo]; // a1
1045: float t2 = (1.0F - t1 * invMaxValue)
1046: * a2[a2po + a2bo];
1047: // a2*(1-a1/maxValue)
1048: float t3 = t1 + t2; // d[alpha]
1049: float t4, t5;
1050: if (t3 == 0.0F) {
1051: t4 = 0.0F;
1052: t5 = 0.0F;
1053: } else {
1054: t4 = t1 / t3;
1055: t5 = t2 / t3;
1056: }
1057:
1058: /* Destination alpha channel. */
1059: d[aOffset][dpo + dbo[aOffset]] = (int) t3;
1060:
1061: /* Destination color channels. */
1062: for (int b = 0; b < numBands; b++) {
1063: int i = b + cOffset;
1064: d[i][dpo + dbo[i]] = (int) (s1[b][s1po
1065: + s1bo[b]]
1066: * t4 + s2[b][s2po + s2bo[b]] * t5);
1067: }
1068:
1069: s1po += s1ps;
1070: s2po += s2ps;
1071: a1po += a1ps;
1072: a2po += a2ps;
1073: dpo += dps;
1074: }
1075:
1076: s1so += s1ss;
1077: s2so += s2ss;
1078: a1so += a1ss;
1079: a2so += a2ss;
1080: dso += dss;
1081: }
1082: }
1083: }
1084: }
1085:
1086: private void floatLoop(RasterAccessor src1, RasterAccessor src2,
1087: RasterAccessor afa1, RasterAccessor afa2, RasterAccessor dst) {
1088: int dwidth = dst.getWidth();
1089: int dheight = dst.getHeight();
1090: int numBands = src1.getNumBands();
1091:
1092: /* First source color channels. */
1093: float[][] s1 = src1.getFloatDataArrays();
1094: int s1ss = src1.getScanlineStride(); // scanline stride
1095: int s1ps = src1.getPixelStride(); // pixel stride
1096: int[] s1bo = src1.getBandOffsets(); // band offsets
1097:
1098: /* Second source color channels. */
1099: float[][] s2 = src2.getFloatDataArrays();
1100: int s2ss = src2.getScanlineStride(); // scanline stride
1101: int s2ps = src2.getPixelStride(); // pixel stride
1102: int[] s2bo = src2.getBandOffsets(); // band offsets
1103:
1104: /* First source alpha channel. */
1105: float[] a1 = afa1.getFloatDataArray(0); // use band 0
1106: int a1ss = afa1.getScanlineStride(); // scanline stride
1107: int a1ps = afa1.getPixelStride(); // pixel stride
1108: int a1bo = afa1.getBandOffset(0); // band 0 offsets
1109:
1110: /* Second source alpha channel (if any). */
1111: float[] a2 = null;
1112: int a2ss = 0;
1113: int a2ps = 0;
1114: int a2bo = 0;
1115: if (afa2 != null) {
1116: a2 = afa2.getFloatDataArray(0); // use band 0
1117: a2ss = afa2.getScanlineStride(); // scanline stride
1118: a2ps = afa2.getPixelStride(); // pixel stride
1119: a2bo = afa2.getBandOffset(0); // band 0 offset
1120: }
1121:
1122: /* Destination color and alpha channels. */
1123: float[][] d = dst.getFloatDataArrays();
1124: int dss = dst.getScanlineStride(); // scanline stride
1125: int dps = dst.getPixelStride(); // pixel stride
1126: int[] dbo = dst.getBandOffsets(); // band offsets
1127:
1128: int s1so = 0, s2so = 0, a1so = 0, a2so = 0, dso = 0;
1129: int s1po, s2po, a1po, a2po, dpo; // po = pixel offset
1130: float invMaxValue = 1.0F / Float.MAX_VALUE;
1131: if (alphaPremultiplied) {
1132: if (afa2 == null) {
1133: for (int h = 0; h < dheight; h++) {
1134: s1po = s1so;
1135: s2po = s2so;
1136: a1po = a1so;
1137: dpo = dso;
1138:
1139: for (int w = 0; w < dwidth; w++) {
1140: float t = 1.0F - a1[a1po + a1bo] * invMaxValue;
1141:
1142: /* Destination alpha channel. */
1143: d[aOffset][dpo + dbo[aOffset]] = Float.MAX_VALUE;
1144:
1145: /* Destination color channels. */
1146: for (int b = 0; b < numBands; b++) {
1147: int i = b + cOffset;
1148: d[i][dpo + dbo[i]] = s1[b][s1po + s1bo[b]]
1149: + s2[b][s2po + s2bo[b]] * t;
1150: }
1151:
1152: s1po += s1ps;
1153: s2po += s2ps;
1154: a1po += a1ps;
1155: dpo += dps;
1156: }
1157:
1158: s1so += s1ss;
1159: s2so += s2ss;
1160: a1so += a1ss;
1161: dso += dss;
1162: }
1163: } else {
1164: for (int h = 0; h < dheight; h++) {
1165: s1po = s1so;
1166: s2po = s2so;
1167: a1po = a1so;
1168: a2po = a2so;
1169: dpo = dso;
1170:
1171: for (int w = 0; w < dwidth; w++) {
1172: float t1 = a1[a1po + a1bo]; // a1
1173: float t2 = 1.0F - t1 * invMaxValue; // 1-a1/maxValue
1174:
1175: /* Destination alpha channel. */
1176: d[aOffset][dpo + dbo[aOffset]] = t1
1177: + a2[a2po + a2bo] * t2;
1178:
1179: /* Destination color channels. */
1180: for (int b = 0; b < numBands; b++) {
1181: int i = b + cOffset;
1182: d[i][dpo + dbo[i]] = s1[b][s1po + s1bo[b]]
1183: + s2[b][s2po + s2bo[b]] * t2;
1184: }
1185:
1186: s1po += s1ps;
1187: s2po += s2ps;
1188: a1po += a1ps;
1189: a2po += a2ps;
1190: dpo += dps;
1191: }
1192:
1193: s1so += s1ss;
1194: s2so += s2ss;
1195: a1so += a1ss;
1196: a2so += a2ss;
1197: dso += dss;
1198: }
1199: }
1200: } else {
1201: if (afa2 == null) {
1202: for (int h = 0; h < dheight; h++) {
1203: s1po = s1so;
1204: s2po = s2so;
1205: a1po = a1so;
1206: dpo = dso;
1207:
1208: for (int w = 0; w < dwidth; w++) {
1209: float t1 = a1[a1po + a1bo] * invMaxValue; // a1/maxValue
1210: float t2 = 1.0F - t1; // 1-a1/maxValue
1211:
1212: /* Destination alpha channel. */
1213: d[aOffset][dpo + dbo[aOffset]] = Float.MAX_VALUE;
1214:
1215: /* Destination color channels. */
1216: for (int b = 0; b < numBands; b++) {
1217: int i = b + cOffset;
1218: d[i][dpo + dbo[i]] = s1[b][s1po + s1bo[b]]
1219: * t1 + s2[b][s2po + s2bo[b]] * t2;
1220: }
1221:
1222: s1po += s1ps;
1223: s2po += s2ps;
1224: a1po += a1ps;
1225: dpo += dps;
1226: }
1227:
1228: s1so += s1ss;
1229: s2so += s2ss;
1230: a1so += a1ss;
1231: dso += dss;
1232: }
1233: } else {
1234: for (int h = 0; h < dheight; h++) {
1235: s1po = s1so;
1236: s2po = s2so;
1237: a1po = a1so;
1238: a2po = a2so;
1239: dpo = dso;
1240:
1241: for (int w = 0; w < dwidth; w++) {
1242: float t1 = a1[a1po + a1bo]; // a1
1243: float t2 = (1.0F - t1 * invMaxValue)
1244: * a2[a2po + a2bo];
1245: // a2*(1-a1/maxValue)
1246: float t3 = t1 + t2; // d[alpha]
1247: float t4, t5;
1248: if (t3 == 0.0F) {
1249: t4 = 0.0F;
1250: t5 = 0.0F;
1251: } else {
1252: t4 = t1 / t3;
1253: t5 = t2 / t3;
1254: }
1255:
1256: /* Destination alpha channel. */
1257: d[aOffset][dpo + dbo[aOffset]] = t3;
1258:
1259: /* Destination color channels. */
1260: for (int b = 0; b < numBands; b++) {
1261: int i = b + cOffset;
1262: d[i][dpo + dbo[i]] = s1[b][s1po + s1bo[b]]
1263: * t4 + s2[b][s2po + s2bo[b]] * t5;
1264: }
1265:
1266: s1po += s1ps;
1267: s2po += s2ps;
1268: a1po += a1ps;
1269: a2po += a2ps;
1270: dpo += dps;
1271: }
1272:
1273: s1so += s1ss;
1274: s2so += s2ss;
1275: a1so += a1ss;
1276: a2so += a2ss;
1277: dso += dss;
1278: }
1279: }
1280: }
1281: }
1282:
1283: private void doubleLoop(RasterAccessor src1, RasterAccessor src2,
1284: RasterAccessor afa1, RasterAccessor afa2, RasterAccessor dst) {
1285: int dwidth = dst.getWidth();
1286: int dheight = dst.getHeight();
1287: int numBands = src1.getNumBands();
1288:
1289: /* First source color channels. */
1290: double[][] s1 = src1.getDoubleDataArrays();
1291: int s1ss = src1.getScanlineStride(); // scanline stride
1292: int s1ps = src1.getPixelStride(); // pixel stride
1293: int[] s1bo = src1.getBandOffsets(); // band offsets
1294:
1295: /* Second source color channels. */
1296: double[][] s2 = src2.getDoubleDataArrays();
1297: int s2ss = src2.getScanlineStride(); // scanline stride
1298: int s2ps = src2.getPixelStride(); // pixel stride
1299: int[] s2bo = src2.getBandOffsets(); // band offsets
1300:
1301: /* First source alpha channel. */
1302: double[] a1 = afa1.getDoubleDataArray(0); // use band 0
1303: int a1ss = afa1.getScanlineStride(); // scanline stride
1304: int a1ps = afa1.getPixelStride(); // pixel stride
1305: int a1bo = afa1.getBandOffset(0); // band 0 offsets
1306:
1307: /* Second source alpha channel (if any). */
1308: double[] a2 = null;
1309: int a2ss = 0;
1310: int a2ps = 0;
1311: int a2bo = 0;
1312: if (afa2 != null) {
1313: a2 = afa2.getDoubleDataArray(0); // use band 0
1314: a2ss = afa2.getScanlineStride(); // scanline stride
1315: a2ps = afa2.getPixelStride(); // pixel stride
1316: a2bo = afa2.getBandOffset(0); // band 0 offset
1317: }
1318:
1319: /* Destination color and alpha channels. */
1320: double[][] d = dst.getDoubleDataArrays();
1321: int dss = dst.getScanlineStride(); // scanline stride
1322: int dps = dst.getPixelStride(); // pixel stride
1323: int[] dbo = dst.getBandOffsets(); // band offsets
1324:
1325: int s1so = 0, s2so = 0, a1so = 0, a2so = 0, dso = 0;
1326: int s1po, s2po, a1po, a2po, dpo; // po = pixel offset
1327: double invMaxValue = 1.0D / Double.MAX_VALUE;
1328: if (alphaPremultiplied) {
1329: if (afa2 == null) {
1330: for (int h = 0; h < dheight; h++) {
1331: s1po = s1so;
1332: s2po = s2so;
1333: a1po = a1so;
1334: dpo = dso;
1335:
1336: for (int w = 0; w < dwidth; w++) {
1337: double t = 1.0D - a1[a1po + a1bo] * invMaxValue;
1338:
1339: /* Destination alpha channel. */
1340: d[aOffset][dpo + dbo[aOffset]] = Double.MAX_VALUE;
1341:
1342: /* Destination color channels. */
1343: for (int b = 0; b < numBands; b++) {
1344: int i = b + cOffset;
1345: d[i][dpo + dbo[i]] = s1[b][s1po + s1bo[b]]
1346: + s2[b][s2po + s2bo[b]] * t;
1347: }
1348:
1349: s1po += s1ps;
1350: s2po += s2ps;
1351: a1po += a1ps;
1352: dpo += dps;
1353: }
1354:
1355: s1so += s1ss;
1356: s2so += s2ss;
1357: a1so += a1ss;
1358: dso += dss;
1359: }
1360: } else {
1361: for (int h = 0; h < dheight; h++) {
1362: s1po = s1so;
1363: s2po = s2so;
1364: a1po = a1so;
1365: a2po = a2so;
1366: dpo = dso;
1367:
1368: for (int w = 0; w < dwidth; w++) {
1369: double t1 = a1[a1po + a1bo]; // a1
1370: double t2 = 1.0D - t1 * invMaxValue; // 1-a1/maxValue
1371:
1372: /* Destination alpha channel. */
1373: d[aOffset][dpo + dbo[aOffset]] = t1
1374: + a2[a2po + a2bo] * t2;
1375:
1376: /* Destination color channels. */
1377: for (int b = 0; b < numBands; b++) {
1378: int i = b + cOffset;
1379: d[i][dpo + dbo[i]] = s1[b][s1po + s1bo[b]]
1380: + s2[b][s2po + s2bo[b]] * t2;
1381: }
1382:
1383: s1po += s1ps;
1384: s2po += s2ps;
1385: a1po += a1ps;
1386: a2po += a2ps;
1387: dpo += dps;
1388: }
1389:
1390: s1so += s1ss;
1391: s2so += s2ss;
1392: a1so += a1ss;
1393: a2so += a2ss;
1394: dso += dss;
1395: }
1396: }
1397: } else {
1398: if (afa2 == null) {
1399: for (int h = 0; h < dheight; h++) {
1400: s1po = s1so;
1401: s2po = s2so;
1402: a1po = a1so;
1403: dpo = dso;
1404:
1405: for (int w = 0; w < dwidth; w++) {
1406: double t1 = a1[a1po + a1bo] * invMaxValue; // a1/maxValue
1407: double t2 = 1.0D - t1; // 1-a1/maxValue
1408:
1409: /* Destination alpha channel. */
1410: d[aOffset][dpo + dbo[aOffset]] = Double.MAX_VALUE;
1411:
1412: /* Destination color channels. */
1413: for (int b = 0; b < numBands; b++) {
1414: int i = b + cOffset;
1415: d[i][dpo + dbo[i]] = s1[b][s1po + s1bo[b]]
1416: * t1 + s2[b][s2po + s2bo[b]] * t2;
1417: }
1418:
1419: s1po += s1ps;
1420: s2po += s2ps;
1421: a1po += a1ps;
1422: dpo += dps;
1423: }
1424:
1425: s1so += s1ss;
1426: s2so += s2ss;
1427: a1so += a1ss;
1428: dso += dss;
1429: }
1430: } else {
1431: for (int h = 0; h < dheight; h++) {
1432: s1po = s1so;
1433: s2po = s2so;
1434: a1po = a1so;
1435: a2po = a2so;
1436: dpo = dso;
1437:
1438: for (int w = 0; w < dwidth; w++) {
1439: double t1 = a1[a1po + a1bo]; // a1
1440: double t2 = (1.0D - t1 * invMaxValue)
1441: * a2[a2po + a2bo];
1442: // a2*(1-a1/maxValue)
1443: double t3 = t1 + t2; // d[alpha]
1444: double t4, t5;
1445: if (t3 == 0.0D) {
1446: t4 = 0.0D;
1447: t5 = 0.0D;
1448: } else {
1449: t4 = t1 / t3;
1450: t5 = t2 / t3;
1451: }
1452:
1453: /* Destination alpha channel. */
1454: d[aOffset][dpo + dbo[aOffset]] = t3;
1455:
1456: /* Destination color channels. */
1457: for (int b = 0; b < numBands; b++) {
1458: int i = b + cOffset;
1459: d[i][dpo + dbo[i]] = s1[b][s1po + s1bo[b]]
1460: * t4 + s2[b][s2po + s2bo[b]] * t5;
1461: }
1462:
1463: s1po += s1ps;
1464: s2po += s2ps;
1465: a1po += a1ps;
1466: a2po += a2ps;
1467: dpo += dps;
1468: }
1469:
1470: s1so += s1ss;
1471: s2so += s2ss;
1472: a1so += a1ss;
1473: a2so += a2ss;
1474: dso += dss;
1475: }
1476: }
1477: }
1478: }
1479:
1480: // public static void main(String args[]) {
1481: // System.out.println("AddOpImage Test");
1482: // ImageLayout layoutSrc, layoutAlpha;
1483: // OpImage src1, src2, afa1, afa2, dst;
1484: // Rectangle rect = new Rectangle(0, 0, 10, 5);
1485:
1486: // layoutAlpha = OpImageTester.createImageLayout(
1487: // 0, 0, 800, 800, 0, 0, 200, 200, DataBuffer.TYPE_BYTE, 1, false);
1488: // afa1 = OpImageTester.createRandomOpImage(layoutAlpha);
1489: // afa2 = OpImageTester.createRandomOpImage(layoutAlpha);
1490: // OpImageTester.printPixels("Alpha 1", afa1, rect);
1491: // OpImageTester.printPixels("Alpha 2", afa2, rect);
1492:
1493: // System.out.println("1. PixelInterleaved byte 3-band");
1494:
1495: // layoutSrc = OpImageTester.createImageLayout(
1496: // 0, 0, 800, 800, 0, 0, 200, 200, DataBuffer.TYPE_BYTE, 3, false);
1497: // src1 = OpImageTester.createRandomOpImage(layoutSrc);
1498: // src2 = OpImageTester.createRandomOpImage(layoutSrc);
1499:
1500: // System.out.println("1a. Alpha premultiplied, source2 opaque");
1501: // dst = new CompositeOpImage(src1, src2, null, null,
1502: // afa1, null, true, true);
1503: // OpImageTester.testOpImage(dst, rect);
1504: // OpImageTester.timeOpImage(dst, 10);
1505:
1506: // System.out.println("1b. Alpha premultiplied, source2 not opaque");
1507: // dst = new CompositeOpImage(src1, src2, null, null,
1508: // afa1, afa2, true, true);
1509: // OpImageTester.testOpImage(dst, rect);
1510: // OpImageTester.timeOpImage(dst, 10);
1511:
1512: // System.out.println("1c. Alpha not premultiplied, source2 opaque");
1513: // dst = new CompositeOpImage(src1, src2, null, null,
1514: // afa1, null, false, true);
1515: // OpImageTester.testOpImage(dst, rect);
1516: // OpImageTester.timeOpImage(dst, 10);
1517:
1518: // System.out.println("1d. Alpha not premultiplied, source2 not opaque");
1519: // dst = new CompositeOpImage(src1, src2, null, null,
1520: // afa1, afa2, false, true);
1521: // OpImageTester.testOpImage(dst, rect);
1522: // OpImageTester.timeOpImage(dst, 10);
1523:
1524: // System.out.println("2. Banded byte 3-band");
1525:
1526: // layoutSrc = OpImageTester.createImageLayout(
1527: // 0, 0, 800, 800, 0, 0, 200, 200, DataBuffer.TYPE_BYTE, 3, true);
1528: // src1 = OpImageTester.createRandomOpImage(layoutSrc);
1529: // src2 = OpImageTester.createRandomOpImage(layoutSrc);
1530:
1531: // System.out.println("2b. Alpha premultiplied, source2 not opaque");
1532: // dst = new CompositeOpImage(src1, src2, null, null,
1533: // afa1, afa2, true, false);
1534: // OpImageTester.testOpImage(dst, rect);
1535: // OpImageTester.timeOpImage(dst, 10);
1536:
1537: // System.out.println("2d. Alpha not premultiplied, source2 not opaque");
1538: // dst = new CompositeOpImage(src1, src2, null, null,
1539: // afa1, afa2, false, true);
1540: // OpImageTester.testOpImage(dst, rect);
1541: // OpImageTester.timeOpImage(dst, 10);
1542:
1543: // layoutAlpha = OpImageTester.createImageLayout(
1544: // 0, 0, 800, 800, 0, 0, 200, 200, DataBuffer.TYPE_USHORT, 1, true);
1545: // afa1 = OpImageTester.createRandomOpImage(layoutAlpha);
1546: // afa2 = OpImageTester.createRandomOpImage(layoutAlpha);
1547: // OpImageTester.printPixels("Alpha 1", afa1, rect);
1548: // OpImageTester.printPixels("Alpha 2", afa2, rect);
1549:
1550: // System.out.println("3. PixelInterleaved ushort 3-band");
1551:
1552: // layoutSrc = OpImageTester.createImageLayout(
1553: // 0, 0, 800, 800, 0, 0, 200, 200, DataBuffer.TYPE_USHORT, 3, false);
1554: // src1 = OpImageTester.createRandomOpImage(layoutSrc);
1555: // src2 = OpImageTester.createRandomOpImage(layoutSrc);
1556:
1557: // System.out.println("3a. Alpha premultiplied, source2 opaque");
1558: // dst = new CompositeOpImage(src1, src2, null, null,
1559: // afa1, null, true, false);
1560: // OpImageTester.testOpImage(dst, rect);
1561: // OpImageTester.timeOpImage(dst, 10);
1562:
1563: // System.out.println("3d. Alpha not premultiplied, source2 not opaque");
1564: // dst = new CompositeOpImage(src1, src2, null, null,
1565: // afa1, afa2, false, false);
1566: // OpImageTester.testOpImage(dst, rect);
1567: // OpImageTester.timeOpImage(dst, 10);
1568: // }
1569: }
|