0001: /*
0002: * $RCSfile: CompositeNoDestAlphaOpImage.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.1 $
0009: * $Date: 2005/02/11 04:56:18 $
0010: * $State: Exp $
0011: */
0012: package com.sun.media.jai.opimage;
0013:
0014: import java.awt.Rectangle;
0015: import java.awt.image.DataBuffer;
0016: import java.awt.image.Raster;
0017: import java.awt.image.RenderedImage;
0018: import java.awt.image.SampleModel;
0019: import java.awt.image.WritableRaster;
0020: import javax.media.jai.ImageLayout;
0021: import javax.media.jai.PointOpImage;
0022: import javax.media.jai.RasterAccessor;
0023: import javax.media.jai.RasterFormatTag;
0024: import javax.media.jai.RasterFactory;
0025: import java.util.Map;
0026:
0027: /**
0028: * An <code>OpImage</code> implementing the "Composite" operation as
0029: * described in <code>javax.media.jai.operator.CompositeDescriptor</code>.
0030: * This implementation handles the case where the destination image does
0031: * not include its result alpha channel.
0032: *
0033: * <p> For two source images <code>source1</code> and <code>source2</code>,
0034: * this <code>OpImage</code> places the foreground <code>source1</code>
0035: * in front of the background <code>source2</code>. This is what commonly
0036: * known as the "over" composite. The destination color values are
0037: * calculated using the following formula:
0038: * <pre>
0039: * dest = source1 * alpha1 + source2 * alpha2 * (1 - alpha1)
0040: * </pre>
0041: * where <code>source1</code> and <code>source2</code> are the color values
0042: * of the two source images, without their alpha multiplied to them, and
0043: * <code>alpha1</code> and <code>alpha2</code> are the two sources's alpha
0044: * values in fraction.
0045: *
0046: * @see javax.media.jai.operator.CompositeDescriptor
0047: * @see CompositeCRIF
0048: *
0049: */
0050: final class CompositeNoDestAlphaOpImage extends PointOpImage {
0051:
0052: /** The alpha image for the first source. */
0053: private RenderedImage alpha1;
0054:
0055: /** The alpha image for the second source. */
0056: private RenderedImage alpha2;
0057:
0058: /** Indicates whether alpha has been premultiplied. */
0059: private boolean premultiplied;
0060:
0061: /** The RasterAccessor format tags. */
0062: private RasterFormatTag[] tags;
0063:
0064: /**
0065: * Constructor.
0066: *
0067: * @param source1 The foreground source image.
0068: * @param source2 The background source image.
0069:
0070: * @param layout The destination image layout.
0071: * @param alpha1 The alpha image for the first source.
0072: * @param alpha2 The alpha image for the second source. If
0073: * <code>null</code>, the second source is assumed to be opaque.
0074: * @param premultiplied Indicates whether both sources and destination
0075: * have their alpha premultiplied.
0076: */
0077: public CompositeNoDestAlphaOpImage(RenderedImage source1,
0078: RenderedImage source2, Map config, ImageLayout layout,
0079: RenderedImage alpha1, RenderedImage alpha2,
0080: boolean premultiplied) {
0081: super (source1, source2, layout, config, true);
0082:
0083: this .alpha1 = alpha1;
0084: this .alpha2 = alpha2;
0085: this .premultiplied = premultiplied;
0086:
0087: tags = getFormatTags();
0088: }
0089:
0090: /**
0091: * Composites two images within a specified rectangle.
0092: *
0093: * @param sources Cobbled sources, guaranteed to provide all the
0094: * source data necessary for computing the rectangle.
0095: * @param dest The tile containing the rectangle to be computed.
0096: * @param destRect The rectangle within the tile to be computed.
0097: */
0098: protected void computeRect(Raster[] sources, WritableRaster dest,
0099: Rectangle destRect) {
0100: /* For PointOpImage, srcRect = destRect. */
0101: RasterAccessor s1 = new RasterAccessor(sources[0], destRect,
0102: tags[0], getSourceImage(0).getColorModel());
0103:
0104: RasterAccessor s2 = new RasterAccessor(sources[1], destRect,
0105: tags[1], getSourceImage(1).getColorModel());
0106:
0107: RasterAccessor a1 = new RasterAccessor(
0108: alpha1.getData(destRect), destRect, tags[2], alpha1
0109: .getColorModel());
0110:
0111: RasterAccessor a2 = null, d;
0112: if (alpha2 == null) {
0113: d = new RasterAccessor(dest, destRect, tags[3],
0114: getColorModel());
0115: } else {
0116: a2 = new RasterAccessor(alpha2.getData(destRect), destRect,
0117: tags[3], alpha2.getColorModel());
0118: d = new RasterAccessor(dest, destRect, tags[4],
0119: getColorModel());
0120: }
0121:
0122: switch (d.getDataType()) {
0123: case DataBuffer.TYPE_BYTE:
0124: byteLoop(s1, s2, a1, a2, d);
0125: break;
0126: case DataBuffer.TYPE_USHORT:
0127: ushortLoop(s1, s2, a1, a2, d);
0128: break;
0129: case DataBuffer.TYPE_SHORT:
0130: shortLoop(s1, s2, a1, a2, d);
0131: break;
0132: case DataBuffer.TYPE_INT:
0133: intLoop(s1, s2, a1, a2, d);
0134: break;
0135: case DataBuffer.TYPE_FLOAT:
0136: floatLoop(s1, s2, a1, a2, d);
0137: break;
0138: case DataBuffer.TYPE_DOUBLE:
0139: doubleLoop(s1, s2, a1, a2, d);
0140: break;
0141: }
0142:
0143: if (d.isDataCopy()) {
0144: d.clampDataArrays();
0145: d.copyDataToRaster();
0146: }
0147: }
0148:
0149: /*
0150: * Formulas for integral data types:
0151: *
0152: * if (premultiplied) {
0153: * dest = source1 + source2 * (1 - alpha1/maxValue)
0154: * } else {
0155: * if (alpha2 == null) {
0156: * dest = source1 * alpha1/maxValue +
0157: * source2 * (1 - alpha1/maxValue)
0158: * } else {
0159: * dest = (source1 * alpha1 +
0160: * source2 * alpha2 * (1 - alpha1/maxValue)) /
0161: * (alpha1 + alpha2 * (1 - alpha1/maxValue))
0162: * }
0163: * }
0164: */
0165:
0166: private void byteLoop(RasterAccessor s1, RasterAccessor s2,
0167: RasterAccessor a1, RasterAccessor a2, RasterAccessor d) {
0168: /* First source color channels. */
0169: int s1LineStride = s1.getScanlineStride();
0170: int s1PixelStride = s1.getPixelStride();
0171: int[] s1BandOffsets = s1.getBandOffsets();
0172: byte[][] s1Data = s1.getByteDataArrays();
0173:
0174: /* Second source color channels. */
0175: int s2LineStride = s2.getScanlineStride();
0176: int s2PixelStride = s2.getPixelStride();
0177: int[] s2BandOffsets = s2.getBandOffsets();
0178: byte[][] s2Data = s2.getByteDataArrays();
0179:
0180: /* First source alpha channel. */
0181: int a1LineStride = a1.getScanlineStride();
0182: int a1PixelStride = a1.getPixelStride();
0183: int a1BandOffset = a1.getBandOffset(0);
0184: byte[] a1Data = a1.getByteDataArray(0);
0185:
0186: /* Second source alpha channel (if any). */
0187: int a2LineStride = 0;
0188: int a2PixelStride = 0;
0189: int a2BandOffset = 0;
0190: byte[] a2Data = null;
0191: if (alpha2 != null) {
0192: a2LineStride = a2.getScanlineStride();
0193: a2PixelStride = a2.getPixelStride();
0194: a2BandOffset = a2.getBandOffset(0);
0195: a2Data = a2.getByteDataArray(0);
0196: }
0197:
0198: /* Destination color channels. */
0199: int dLineStride = d.getScanlineStride();
0200: int dPixelStride = d.getPixelStride();
0201: int[] dBandOffsets = d.getBandOffsets();
0202: byte[][] dData = d.getByteDataArrays();
0203:
0204: int dwidth = d.getWidth();
0205: int dheight = d.getHeight();
0206: int dbands = d.getNumBands();
0207:
0208: float invMax = 1.0F / 0xFF;
0209:
0210: int s1LineOffset = 0, s2LineOffset = 0, a1LineOffset = 0, a2LineOffset = 0, dLineOffset = 0, s1PixelOffset, s2PixelOffset, a1PixelOffset, a2PixelOffset, dPixelOffset;
0211:
0212: if (premultiplied) {
0213: /* dest = source1 + source2 * (1 - alpha1/max) */
0214:
0215: for (int h = 0; h < dheight; h++) {
0216: s1PixelOffset = s1LineOffset;
0217: s2PixelOffset = s2LineOffset;
0218: a1PixelOffset = a1LineOffset + a1BandOffset;
0219: dPixelOffset = dLineOffset;
0220:
0221: s1LineOffset += s1LineStride;
0222: s2LineOffset += s2LineStride;
0223: a1LineOffset += a1LineStride;
0224: dLineOffset += dLineStride;
0225:
0226: for (int w = 0; w < dwidth; w++) {
0227: float t = 1.0F - (a1Data[a1PixelOffset] & 0xFF)
0228: * invMax;
0229:
0230: /* Destination color channels. */
0231: for (int b = 0; b < dbands; b++) {
0232: dData[b][dPixelOffset + dBandOffsets[b]] = (byte) ((s1Data[b][s1PixelOffset
0233: + s1BandOffsets[b]] & 0xFF) + (s2Data[b][s2PixelOffset
0234: + s2BandOffsets[b]] & 0xFF)
0235: * t);
0236: }
0237:
0238: s1PixelOffset += s1PixelStride;
0239: s2PixelOffset += s2PixelStride;
0240: a1PixelOffset += a1PixelStride;
0241: dPixelOffset += dPixelStride;
0242: }
0243: }
0244:
0245: } else {
0246: if (alpha2 == null) {
0247: /* dest = source1 * alpha1/max + source2 * (1 - alpha1/max) */
0248:
0249: for (int h = 0; h < dheight; h++) {
0250: s1PixelOffset = s1LineOffset;
0251: s2PixelOffset = s2LineOffset;
0252: a1PixelOffset = a1LineOffset + a1BandOffset;
0253: dPixelOffset = dLineOffset;
0254:
0255: s1LineOffset += s1LineStride;
0256: s2LineOffset += s2LineStride;
0257: a1LineOffset += a1LineStride;
0258: dLineOffset += dLineStride;
0259:
0260: for (int w = 0; w < dwidth; w++) {
0261: float t1 = (a1Data[a1PixelOffset] & 0xFF)
0262: * invMax;
0263: float t2 = 1.0F - t1;
0264:
0265: /* Destination color channels. */
0266: for (int b = 0; b < dbands; b++) {
0267: dData[b][dPixelOffset + dBandOffsets[b]] = (byte) ((s1Data[b][s1PixelOffset
0268: + s1BandOffsets[b]] & 0xFF)
0269: * t1 + (s2Data[b][s2PixelOffset
0270: + s2BandOffsets[b]] & 0xFF)
0271: * t2);
0272: }
0273:
0274: s1PixelOffset += s1PixelStride;
0275: s2PixelOffset += s2PixelStride;
0276: a1PixelOffset += a1PixelStride;
0277: dPixelOffset += dPixelStride;
0278: }
0279: }
0280: } else {
0281: /*
0282: * dest = (source1 * alpha1 +
0283: * source2 * alpha2 * (1 - alpha1/maxValue)) /
0284: * (alpha1 + alpha2 * (1 - alpha1/maxValue))
0285: */
0286:
0287: for (int h = 0; h < dheight; h++) {
0288: s1PixelOffset = s1LineOffset;
0289: s2PixelOffset = s2LineOffset;
0290: a1PixelOffset = a1LineOffset + a1BandOffset;
0291: a2PixelOffset = a2LineOffset + a2BandOffset;
0292: dPixelOffset = dLineOffset;
0293:
0294: s1LineOffset += s1LineStride;
0295: s2LineOffset += s2LineStride;
0296: a1LineOffset += a1LineStride;
0297: a2LineOffset += a2LineStride;
0298: dLineOffset += dLineStride;
0299:
0300: for (int w = 0; w < dwidth; w++) {
0301: int t1 = a1Data[a1PixelOffset] & 0xFF;
0302: float t2 = (a2Data[a2PixelOffset] & 0xFF)
0303: * (1.0F - t1 * invMax);
0304: float t3 = t1 + t2;
0305: float t4, t5;
0306: if (t3 == 0.0F) {
0307: t4 = 0.0F;
0308: t5 = 0.0F;
0309: } else {
0310: t4 = t1 / t3;
0311: t5 = t2 / t3;
0312: }
0313:
0314: /* Destination color channels. */
0315: for (int b = 0; b < dbands; b++) {
0316: dData[b][dPixelOffset + dBandOffsets[b]] = (byte) ((s1Data[b][s1PixelOffset
0317: + s1BandOffsets[b]] & 0xFF)
0318: * t4 + (s2Data[b][s2PixelOffset
0319: + s2BandOffsets[b]] & 0xFF)
0320: * t5);
0321: }
0322:
0323: s1PixelOffset += s1PixelStride;
0324: s2PixelOffset += s2PixelStride;
0325: a1PixelOffset += a1PixelStride;
0326: a2PixelOffset += a2PixelStride;
0327: dPixelOffset += dPixelStride;
0328: }
0329: }
0330: }
0331: }
0332: }
0333:
0334: private void ushortLoop(RasterAccessor s1, RasterAccessor s2,
0335: RasterAccessor a1, RasterAccessor a2, RasterAccessor d) {
0336: /* First source color channels. */
0337: int s1LineStride = s1.getScanlineStride();
0338: int s1PixelStride = s1.getPixelStride();
0339: int[] s1BandOffsets = s1.getBandOffsets();
0340: short[][] s1Data = s1.getShortDataArrays();
0341:
0342: /* Second source color channels. */
0343: int s2LineStride = s2.getScanlineStride();
0344: int s2PixelStride = s2.getPixelStride();
0345: int[] s2BandOffsets = s2.getBandOffsets();
0346: short[][] s2Data = s2.getShortDataArrays();
0347:
0348: /* First source alpha channel. */
0349: int a1LineStride = a1.getScanlineStride();
0350: int a1PixelStride = a1.getPixelStride();
0351: int a1BandOffset = a1.getBandOffset(0);
0352: short[] a1Data = a1.getShortDataArray(0);
0353:
0354: /* Second source alpha channel (if any). */
0355: int a2LineStride = 0;
0356: int a2PixelStride = 0;
0357: int a2BandOffset = 0;
0358: short[] a2Data = null;
0359: if (alpha2 != null) {
0360: a2LineStride = a2.getScanlineStride();
0361: a2PixelStride = a2.getPixelStride();
0362: a2BandOffset = a2.getBandOffset(0);
0363: a2Data = a2.getShortDataArray(0);
0364: }
0365:
0366: /* Destination color channels. */
0367: int dLineStride = d.getScanlineStride();
0368: int dPixelStride = d.getPixelStride();
0369: int[] dBandOffsets = d.getBandOffsets();
0370: short[][] dData = d.getShortDataArrays();
0371:
0372: int dwidth = d.getWidth();
0373: int dheight = d.getHeight();
0374: int dbands = d.getNumBands();
0375:
0376: float invMax = 1.0F / 0xFFFF;
0377:
0378: int s1LineOffset = 0, s2LineOffset = 0, a1LineOffset = 0, a2LineOffset = 0, dLineOffset = 0, s1PixelOffset, s2PixelOffset, a1PixelOffset, a2PixelOffset, dPixelOffset;
0379:
0380: if (premultiplied) {
0381: /* dest = source1 + source2 * (1 - alpha1/max) */
0382:
0383: for (int h = 0; h < dheight; h++) {
0384: s1PixelOffset = s1LineOffset;
0385: s2PixelOffset = s2LineOffset;
0386: a1PixelOffset = a1LineOffset + a1BandOffset;
0387: dPixelOffset = dLineOffset;
0388:
0389: s1LineOffset += s1LineStride;
0390: s2LineOffset += s2LineStride;
0391: a1LineOffset += a1LineStride;
0392: dLineOffset += dLineStride;
0393:
0394: for (int w = 0; w < dwidth; w++) {
0395: float t = 1.0F - (a1Data[a1PixelOffset] & 0xFFFF)
0396: * invMax;
0397:
0398: /* Destination color channels. */
0399: for (int b = 0; b < dbands; b++) {
0400: dData[b][dPixelOffset + dBandOffsets[b]] = (short) ((s1Data[b][s1PixelOffset
0401: + s1BandOffsets[b]] & 0xFFFF) + (s2Data[b][s2PixelOffset
0402: + s2BandOffsets[b]] & 0xFFFF)
0403: * t);
0404: }
0405:
0406: s1PixelOffset += s1PixelStride;
0407: s2PixelOffset += s2PixelStride;
0408: a1PixelOffset += a1PixelStride;
0409: dPixelOffset += dPixelStride;
0410: }
0411: }
0412:
0413: } else {
0414: if (alpha2 == null) {
0415: /* dest = source1 * alpha1/max + source2 * (1 - alpha1/max) */
0416:
0417: for (int h = 0; h < dheight; h++) {
0418: s1PixelOffset = s1LineOffset;
0419: s2PixelOffset = s2LineOffset;
0420: a1PixelOffset = a1LineOffset + a1BandOffset;
0421: dPixelOffset = dLineOffset;
0422:
0423: s1LineOffset += s1LineStride;
0424: s2LineOffset += s2LineStride;
0425: a1LineOffset += a1LineStride;
0426: dLineOffset += dLineStride;
0427:
0428: for (int w = 0; w < dwidth; w++) {
0429: float t1 = (a1Data[a1PixelOffset] & 0xFFFF)
0430: * invMax;
0431: float t2 = 1.0F - t1;
0432:
0433: /* Destination color channels. */
0434: for (int b = 0; b < dbands; b++) {
0435: dData[b][dPixelOffset + dBandOffsets[b]] = (short) ((s1Data[b][s1PixelOffset
0436: + s1BandOffsets[b]] & 0xFFFF)
0437: * t1 + (s2Data[b][s2PixelOffset
0438: + s2BandOffsets[b]] & 0xFFFF)
0439: * t2);
0440: }
0441:
0442: s1PixelOffset += s1PixelStride;
0443: s2PixelOffset += s2PixelStride;
0444: a1PixelOffset += a1PixelStride;
0445: dPixelOffset += dPixelStride;
0446: }
0447: }
0448: } else {
0449: /*
0450: * dest = (source1 * alpha1 +
0451: * source2 * alpha2 * (1 - alpha1/maxValue)) /
0452: * (alpha1 + alpha2 * (1 - alpha1/maxValue))
0453: */
0454:
0455: for (int h = 0; h < dheight; h++) {
0456: s1PixelOffset = s1LineOffset;
0457: s2PixelOffset = s2LineOffset;
0458: a1PixelOffset = a1LineOffset + a1BandOffset;
0459: a2PixelOffset = a2LineOffset + a2BandOffset;
0460: dPixelOffset = dLineOffset;
0461:
0462: s1LineOffset += s1LineStride;
0463: s2LineOffset += s2LineStride;
0464: a1LineOffset += a1LineStride;
0465: a2LineOffset += a2LineStride;
0466: dLineOffset += dLineStride;
0467:
0468: for (int w = 0; w < dwidth; w++) {
0469: int t1 = a1Data[a1PixelOffset] & 0xFFFF;
0470: float t2 = (a2Data[a2PixelOffset] & 0xFFFF)
0471: * (1.0F - t1 * invMax);
0472: float t3 = t1 + t2;
0473: float t4, t5;
0474: if (t3 == 0.0F) {
0475: t4 = 0.0F;
0476: t5 = 0.0F;
0477: } else {
0478: t4 = t1 / t3;
0479: t5 = t2 / t3;
0480: }
0481:
0482: /* Destination color channels. */
0483: for (int b = 0; b < dbands; b++) {
0484: dData[b][dPixelOffset + dBandOffsets[b]] = (short) ((s1Data[b][s1PixelOffset
0485: + s1BandOffsets[b]] & 0xFFFF)
0486: * t4 + (s2Data[b][s2PixelOffset
0487: + s2BandOffsets[b]] & 0xFFFF)
0488: * t5);
0489: }
0490:
0491: s1PixelOffset += s1PixelStride;
0492: s2PixelOffset += s2PixelStride;
0493: a1PixelOffset += a1PixelStride;
0494: a2PixelOffset += a2PixelStride;
0495: dPixelOffset += dPixelStride;
0496: }
0497: }
0498: }
0499: }
0500: }
0501:
0502: private void shortLoop(RasterAccessor s1, RasterAccessor s2,
0503: RasterAccessor a1, RasterAccessor a2, RasterAccessor d) {
0504: /* First source color channels. */
0505: int s1LineStride = s1.getScanlineStride();
0506: int s1PixelStride = s1.getPixelStride();
0507: int[] s1BandOffsets = s1.getBandOffsets();
0508: short[][] s1Data = s1.getShortDataArrays();
0509:
0510: /* Second source color channels. */
0511: int s2LineStride = s2.getScanlineStride();
0512: int s2PixelStride = s2.getPixelStride();
0513: int[] s2BandOffsets = s2.getBandOffsets();
0514: short[][] s2Data = s2.getShortDataArrays();
0515:
0516: /* First source alpha channel. */
0517: int a1LineStride = a1.getScanlineStride();
0518: int a1PixelStride = a1.getPixelStride();
0519: int a1BandOffset = a1.getBandOffset(0);
0520: short[] a1Data = a1.getShortDataArray(0);
0521:
0522: /* Second source alpha channel (if any). */
0523: int a2LineStride = 0;
0524: int a2PixelStride = 0;
0525: int a2BandOffset = 0;
0526: short[] a2Data = null;
0527: if (alpha2 != null) {
0528: a2LineStride = a2.getScanlineStride();
0529: a2PixelStride = a2.getPixelStride();
0530: a2BandOffset = a2.getBandOffset(0);
0531: a2Data = a2.getShortDataArray(0);
0532: }
0533:
0534: /* Destination color channels. */
0535: int dLineStride = d.getScanlineStride();
0536: int dPixelStride = d.getPixelStride();
0537: int[] dBandOffsets = d.getBandOffsets();
0538: short[][] dData = d.getShortDataArrays();
0539:
0540: int dwidth = d.getWidth();
0541: int dheight = d.getHeight();
0542: int dbands = d.getNumBands();
0543:
0544: float invMax = 1.0F / Short.MAX_VALUE;
0545:
0546: int s1LineOffset = 0, s2LineOffset = 0, a1LineOffset = 0, a2LineOffset = 0, dLineOffset = 0, s1PixelOffset, s2PixelOffset, a1PixelOffset, a2PixelOffset, dPixelOffset;
0547:
0548: if (premultiplied) {
0549: /* dest = source1 + source2 * (1 - alpha1/max) */
0550:
0551: for (int h = 0; h < dheight; h++) {
0552: s1PixelOffset = s1LineOffset;
0553: s2PixelOffset = s2LineOffset;
0554: a1PixelOffset = a1LineOffset + a1BandOffset;
0555: dPixelOffset = dLineOffset;
0556:
0557: s1LineOffset += s1LineStride;
0558: s2LineOffset += s2LineStride;
0559: a1LineOffset += a1LineStride;
0560: dLineOffset += dLineStride;
0561:
0562: for (int w = 0; w < dwidth; w++) {
0563: float t = 1.0F - a1Data[a1PixelOffset] * invMax;
0564:
0565: /* Destination color channels. */
0566: for (int b = 0; b < dbands; b++) {
0567: dData[b][dPixelOffset + dBandOffsets[b]] = (short) (s1Data[b][s1PixelOffset
0568: + s1BandOffsets[b]] + s2Data[b][s2PixelOffset
0569: + s2BandOffsets[b]]
0570: * t);
0571: }
0572:
0573: s1PixelOffset += s1PixelStride;
0574: s2PixelOffset += s2PixelStride;
0575: a1PixelOffset += a1PixelStride;
0576: dPixelOffset += dPixelStride;
0577: }
0578: }
0579:
0580: } else {
0581: if (alpha2 == null) {
0582: /* dest = source1 * alpha1/max + source2 * (1 - alpha1/max) */
0583:
0584: for (int h = 0; h < dheight; h++) {
0585: s1PixelOffset = s1LineOffset;
0586: s2PixelOffset = s2LineOffset;
0587: a1PixelOffset = a1LineOffset + a1BandOffset;
0588: dPixelOffset = dLineOffset;
0589:
0590: s1LineOffset += s1LineStride;
0591: s2LineOffset += s2LineStride;
0592: a1LineOffset += a1LineStride;
0593: dLineOffset += dLineStride;
0594:
0595: for (int w = 0; w < dwidth; w++) {
0596: float t1 = a1Data[a1PixelOffset] * invMax;
0597: float t2 = 1.0F - t1;
0598:
0599: /* Destination color channels. */
0600: for (int b = 0; b < dbands; b++) {
0601: dData[b][dPixelOffset + dBandOffsets[b]] = (short) (s1Data[b][s1PixelOffset
0602: + s1BandOffsets[b]]
0603: * t1 + s2Data[b][s2PixelOffset
0604: + s2BandOffsets[b]]
0605: * t2);
0606: }
0607:
0608: s1PixelOffset += s1PixelStride;
0609: s2PixelOffset += s2PixelStride;
0610: a1PixelOffset += a1PixelStride;
0611: dPixelOffset += dPixelStride;
0612: }
0613: }
0614: } else {
0615: /*
0616: * dest = (source1 * alpha1 +
0617: * source2 * alpha2 * (1 - alpha1/maxValue)) /
0618: * (alpha1 + alpha2 * (1 - alpha1/maxValue))
0619: */
0620:
0621: for (int h = 0; h < dheight; h++) {
0622: s1PixelOffset = s1LineOffset;
0623: s2PixelOffset = s2LineOffset;
0624: a1PixelOffset = a1LineOffset + a1BandOffset;
0625: a2PixelOffset = a2LineOffset + a2BandOffset;
0626: dPixelOffset = dLineOffset;
0627:
0628: s1LineOffset += s1LineStride;
0629: s2LineOffset += s2LineStride;
0630: a1LineOffset += a1LineStride;
0631: a2LineOffset += a2LineStride;
0632: dLineOffset += dLineStride;
0633:
0634: for (int w = 0; w < dwidth; w++) {
0635: int t1 = a1Data[a1PixelOffset];
0636: float t2 = a2Data[a2PixelOffset]
0637: * (1.0F - t1 * invMax);
0638: float t3 = t1 + t2;
0639: float t4, t5;
0640: if (t3 == 0.0F) {
0641: t4 = 0.0F;
0642: t5 = 0.0F;
0643: } else {
0644: t4 = t1 / t3;
0645: t5 = t2 / t3;
0646: }
0647:
0648: /* Destination color channels. */
0649: for (int b = 0; b < dbands; b++) {
0650: dData[b][dPixelOffset + dBandOffsets[b]] = (short) (s1Data[b][s1PixelOffset
0651: + s1BandOffsets[b]]
0652: * t4 + s2Data[b][s2PixelOffset
0653: + s2BandOffsets[b]]
0654: * t5);
0655: }
0656:
0657: s1PixelOffset += s1PixelStride;
0658: s2PixelOffset += s2PixelStride;
0659: a1PixelOffset += a1PixelStride;
0660: a2PixelOffset += a2PixelStride;
0661: dPixelOffset += dPixelStride;
0662: }
0663: }
0664: }
0665: }
0666: }
0667:
0668: private void intLoop(RasterAccessor s1, RasterAccessor s2,
0669: RasterAccessor a1, RasterAccessor a2, RasterAccessor d) {
0670: /* First source color channels. */
0671: int s1LineStride = s1.getScanlineStride();
0672: int s1PixelStride = s1.getPixelStride();
0673: int[] s1BandOffsets = s1.getBandOffsets();
0674: int[][] s1Data = s1.getIntDataArrays();
0675:
0676: /* Second source color channels. */
0677: int s2LineStride = s2.getScanlineStride();
0678: int s2PixelStride = s2.getPixelStride();
0679: int[] s2BandOffsets = s2.getBandOffsets();
0680: int[][] s2Data = s2.getIntDataArrays();
0681:
0682: /* First source alpha channel. */
0683: int a1LineStride = a1.getScanlineStride();
0684: int a1PixelStride = a1.getPixelStride();
0685: int a1BandOffset = a1.getBandOffset(0);
0686: int[] a1Data = a1.getIntDataArray(0);
0687:
0688: /* Second source alpha channel (if any). */
0689: int a2LineStride = 0;
0690: int a2PixelStride = 0;
0691: int a2BandOffset = 0;
0692: int[] a2Data = null;
0693: if (alpha2 != null) {
0694: a2LineStride = a2.getScanlineStride();
0695: a2PixelStride = a2.getPixelStride();
0696: a2BandOffset = a2.getBandOffset(0);
0697: a2Data = a2.getIntDataArray(0);
0698: }
0699:
0700: /* Destination color channels. */
0701: int dLineStride = d.getScanlineStride();
0702: int dPixelStride = d.getPixelStride();
0703: int[] dBandOffsets = d.getBandOffsets();
0704: int[][] dData = d.getIntDataArrays();
0705:
0706: int dwidth = d.getWidth();
0707: int dheight = d.getHeight();
0708: int dbands = d.getNumBands();
0709:
0710: float invMax = 1.0F / Integer.MAX_VALUE;
0711:
0712: int s1LineOffset = 0, s2LineOffset = 0, a1LineOffset = 0, a2LineOffset = 0, dLineOffset = 0, s1PixelOffset, s2PixelOffset, a1PixelOffset, a2PixelOffset, dPixelOffset;
0713:
0714: if (premultiplied) {
0715: /* dest = source1 + source2 * (1 - alpha1/max) */
0716:
0717: for (int h = 0; h < dheight; h++) {
0718: s1PixelOffset = s1LineOffset;
0719: s2PixelOffset = s2LineOffset;
0720: a1PixelOffset = a1LineOffset + a1BandOffset;
0721: dPixelOffset = dLineOffset;
0722:
0723: s1LineOffset += s1LineStride;
0724: s2LineOffset += s2LineStride;
0725: a1LineOffset += a1LineStride;
0726: dLineOffset += dLineStride;
0727:
0728: for (int w = 0; w < dwidth; w++) {
0729: float t = 1.0F - a1Data[a1PixelOffset] * invMax;
0730:
0731: /* Destination color channels. */
0732: for (int b = 0; b < dbands; b++) {
0733: dData[b][dPixelOffset + dBandOffsets[b]] = (int) (s1Data[b][s1PixelOffset
0734: + s1BandOffsets[b]] + s2Data[b][s2PixelOffset
0735: + s2BandOffsets[b]]
0736: * t);
0737: }
0738:
0739: s1PixelOffset += s1PixelStride;
0740: s2PixelOffset += s2PixelStride;
0741: a1PixelOffset += a1PixelStride;
0742: dPixelOffset += dPixelStride;
0743: }
0744: }
0745:
0746: } else {
0747: if (alpha2 == null) {
0748: /* dest = source1 * alpha1/max + source2 * (1 - alpha1/max) */
0749:
0750: for (int h = 0; h < dheight; h++) {
0751: s1PixelOffset = s1LineOffset;
0752: s2PixelOffset = s2LineOffset;
0753: a1PixelOffset = a1LineOffset + a1BandOffset;
0754: dPixelOffset = dLineOffset;
0755:
0756: s1LineOffset += s1LineStride;
0757: s2LineOffset += s2LineStride;
0758: a1LineOffset += a1LineStride;
0759: dLineOffset += dLineStride;
0760:
0761: for (int w = 0; w < dwidth; w++) {
0762: float t1 = a1Data[a1PixelOffset] * invMax;
0763: float t2 = 1.0F - t1;
0764:
0765: /* Destination color channels. */
0766: for (int b = 0; b < dbands; b++) {
0767: dData[b][dPixelOffset + dBandOffsets[b]] = (int) (s1Data[b][s1PixelOffset
0768: + s1BandOffsets[b]]
0769: * t1 + s2Data[b][s2PixelOffset
0770: + s2BandOffsets[b]]
0771: * t2);
0772: }
0773:
0774: s1PixelOffset += s1PixelStride;
0775: s2PixelOffset += s2PixelStride;
0776: a1PixelOffset += a1PixelStride;
0777: dPixelOffset += dPixelStride;
0778: }
0779: }
0780: } else {
0781: /*
0782: * dest = (source1 * alpha1 +
0783: * source2 * alpha2 * (1 - alpha1/maxValue)) /
0784: * (alpha1 + alpha2 * (1 - alpha1/maxValue))
0785: */
0786:
0787: for (int h = 0; h < dheight; h++) {
0788: s1PixelOffset = s1LineOffset;
0789: s2PixelOffset = s2LineOffset;
0790: a1PixelOffset = a1LineOffset + a1BandOffset;
0791: a2PixelOffset = a2LineOffset + a2BandOffset;
0792: dPixelOffset = dLineOffset;
0793:
0794: s1LineOffset += s1LineStride;
0795: s2LineOffset += s2LineStride;
0796: a1LineOffset += a1LineStride;
0797: a2LineOffset += a2LineStride;
0798: dLineOffset += dLineStride;
0799:
0800: for (int w = 0; w < dwidth; w++) {
0801: int t1 = a1Data[a1PixelOffset];
0802: float t2 = a2Data[a2PixelOffset]
0803: * (1.0F - t1 * invMax);
0804: float t3 = t1 + t2;
0805: float t4, t5;
0806: if (t3 == 0.0F) {
0807: t4 = 0.0F;
0808: t5 = 0.0F;
0809: } else {
0810: t4 = t1 / t3;
0811: t5 = t2 / t3;
0812: }
0813:
0814: /* Destination color channels. */
0815: for (int b = 0; b < dbands; b++) {
0816: dData[b][dPixelOffset + dBandOffsets[b]] = (int) (s1Data[b][s1PixelOffset
0817: + s1BandOffsets[b]]
0818: * t4 + s2Data[b][s2PixelOffset
0819: + s2BandOffsets[b]]
0820: * t5);
0821: }
0822:
0823: s1PixelOffset += s1PixelStride;
0824: s2PixelOffset += s2PixelStride;
0825: a1PixelOffset += a1PixelStride;
0826: a2PixelOffset += a2PixelStride;
0827: dPixelOffset += dPixelStride;
0828: }
0829: }
0830: }
0831: }
0832: }
0833:
0834: private void floatLoop(RasterAccessor s1, RasterAccessor s2,
0835: RasterAccessor a1, RasterAccessor a2, RasterAccessor d) {
0836: /* First source color channels. */
0837: int s1LineStride = s1.getScanlineStride();
0838: int s1PixelStride = s1.getPixelStride();
0839: int[] s1BandOffsets = s1.getBandOffsets();
0840: float[][] s1Data = s1.getFloatDataArrays();
0841:
0842: /* Second source color channels. */
0843: int s2LineStride = s2.getScanlineStride();
0844: int s2PixelStride = s2.getPixelStride();
0845: int[] s2BandOffsets = s2.getBandOffsets();
0846: float[][] s2Data = s2.getFloatDataArrays();
0847:
0848: /* First source alpha channel. */
0849: int a1LineStride = a1.getScanlineStride();
0850: int a1PixelStride = a1.getPixelStride();
0851: int a1BandOffset = a1.getBandOffset(0);
0852: float[] a1Data = a1.getFloatDataArray(0);
0853:
0854: /* Second source alpha channel (if any). */
0855: int a2LineStride = 0;
0856: int a2PixelStride = 0;
0857: int a2BandOffset = 0;
0858: float[] a2Data = null;
0859: if (alpha2 != null) {
0860: a2LineStride = a2.getScanlineStride();
0861: a2PixelStride = a2.getPixelStride();
0862: a2BandOffset = a2.getBandOffset(0);
0863: a2Data = a2.getFloatDataArray(0);
0864: }
0865:
0866: /* Destination color channels. */
0867: int dLineStride = d.getScanlineStride();
0868: int dPixelStride = d.getPixelStride();
0869: int[] dBandOffsets = d.getBandOffsets();
0870: float[][] dData = d.getFloatDataArrays();
0871:
0872: int dwidth = d.getWidth();
0873: int dheight = d.getHeight();
0874: int dbands = d.getNumBands();
0875:
0876: int s1LineOffset = 0, s2LineOffset = 0, a1LineOffset = 0, a2LineOffset = 0, dLineOffset = 0, s1PixelOffset, s2PixelOffset, a1PixelOffset, a2PixelOffset, dPixelOffset;
0877:
0878: if (premultiplied) {
0879: /* dest = source1 + source2 * (1 - alpha1) */
0880:
0881: for (int h = 0; h < dheight; h++) {
0882: s1PixelOffset = s1LineOffset;
0883: s2PixelOffset = s2LineOffset;
0884: a1PixelOffset = a1LineOffset + a1BandOffset;
0885: dPixelOffset = dLineOffset;
0886:
0887: s1LineOffset += s1LineStride;
0888: s2LineOffset += s2LineStride;
0889: a1LineOffset += a1LineStride;
0890: dLineOffset += dLineStride;
0891:
0892: for (int w = 0; w < dwidth; w++) {
0893: float t = 1.0F - a1Data[a1PixelOffset];
0894:
0895: /* Destination color channels. */
0896: for (int b = 0; b < dbands; b++) {
0897: dData[b][dPixelOffset + dBandOffsets[b]] = s1Data[b][s1PixelOffset
0898: + s1BandOffsets[b]]
0899: + s2Data[b][s2PixelOffset
0900: + s2BandOffsets[b]] * t;
0901: }
0902:
0903: s1PixelOffset += s1PixelStride;
0904: s2PixelOffset += s2PixelStride;
0905: a1PixelOffset += a1PixelStride;
0906: dPixelOffset += dPixelStride;
0907: }
0908: }
0909:
0910: } else {
0911: if (alpha2 == null) {
0912: /* dest = source1 * alpha1 + source2 * (1 - alpha1) */
0913:
0914: for (int h = 0; h < dheight; h++) {
0915: s1PixelOffset = s1LineOffset;
0916: s2PixelOffset = s2LineOffset;
0917: a1PixelOffset = a1LineOffset + a1BandOffset;
0918: dPixelOffset = dLineOffset;
0919:
0920: s1LineOffset += s1LineStride;
0921: s2LineOffset += s2LineStride;
0922: a1LineOffset += a1LineStride;
0923: dLineOffset += dLineStride;
0924:
0925: for (int w = 0; w < dwidth; w++) {
0926: float t1 = a1Data[a1PixelOffset];
0927: float t2 = 1.0F - t1;
0928:
0929: /* Destination color channels. */
0930: for (int b = 0; b < dbands; b++) {
0931: dData[b][dPixelOffset + dBandOffsets[b]] = s1Data[b][s1PixelOffset
0932: + s1BandOffsets[b]]
0933: * t1
0934: + s2Data[b][s2PixelOffset
0935: + s2BandOffsets[b]] * t2;
0936: }
0937:
0938: s1PixelOffset += s1PixelStride;
0939: s2PixelOffset += s2PixelStride;
0940: a1PixelOffset += a1PixelStride;
0941: dPixelOffset += dPixelStride;
0942: }
0943: }
0944: } else {
0945: /*
0946: * dest = (source1 * alpha1 + source2 * alpha2 * (1 - alpha1)) /
0947: * (alpha1 + alpha2 * (1 - alpha1))
0948: */
0949:
0950: for (int h = 0; h < dheight; h++) {
0951: s1PixelOffset = s1LineOffset;
0952: s2PixelOffset = s2LineOffset;
0953: a1PixelOffset = a1LineOffset + a1BandOffset;
0954: a2PixelOffset = a2LineOffset + a2BandOffset;
0955: dPixelOffset = dLineOffset;
0956:
0957: s1LineOffset += s1LineStride;
0958: s2LineOffset += s2LineStride;
0959: a1LineOffset += a1LineStride;
0960: a2LineOffset += a2LineStride;
0961: dLineOffset += dLineStride;
0962:
0963: for (int w = 0; w < dwidth; w++) {
0964: float t1 = a1Data[a1PixelOffset];
0965: float t2 = a2Data[a2PixelOffset] * (1.0F - t1);
0966: float t3 = t1 + t2;
0967: float t4, t5;
0968: if (t3 == 0.0F) {
0969: t4 = 0.0F;
0970: t5 = 0.0F;
0971: } else {
0972: t4 = t1 / t3;
0973: t5 = t2 / t3;
0974: }
0975:
0976: /* Destination color channels. */
0977: for (int b = 0; b < dbands; b++) {
0978: dData[b][dPixelOffset + dBandOffsets[b]] = s1Data[b][s1PixelOffset
0979: + s1BandOffsets[b]]
0980: * t4
0981: + s2Data[b][s2PixelOffset
0982: + s2BandOffsets[b]] * t5;
0983: }
0984:
0985: s1PixelOffset += s1PixelStride;
0986: s2PixelOffset += s2PixelStride;
0987: a1PixelOffset += a1PixelStride;
0988: a2PixelOffset += a2PixelStride;
0989: dPixelOffset += dPixelStride;
0990: }
0991: }
0992: }
0993: }
0994: }
0995:
0996: private void doubleLoop(RasterAccessor s1, RasterAccessor s2,
0997: RasterAccessor a1, RasterAccessor a2, RasterAccessor d) {
0998: /* First source color channels. */
0999: int s1LineStride = s1.getScanlineStride();
1000: int s1PixelStride = s1.getPixelStride();
1001: int[] s1BandOffsets = s1.getBandOffsets();
1002: double[][] s1Data = s1.getDoubleDataArrays();
1003:
1004: /* Second source color channels. */
1005: int s2LineStride = s2.getScanlineStride();
1006: int s2PixelStride = s2.getPixelStride();
1007: int[] s2BandOffsets = s2.getBandOffsets();
1008: double[][] s2Data = s2.getDoubleDataArrays();
1009:
1010: /* First source alpha channel. */
1011: int a1LineStride = a1.getScanlineStride();
1012: int a1PixelStride = a1.getPixelStride();
1013: int a1BandOffset = a1.getBandOffset(0);
1014: double[] a1Data = a1.getDoubleDataArray(0);
1015:
1016: /* Second source alpha channel (if any). */
1017: int a2LineStride = 0;
1018: int a2PixelStride = 0;
1019: int a2BandOffset = 0;
1020: double[] a2Data = null;
1021: if (alpha2 != null) {
1022: a2LineStride = a2.getScanlineStride();
1023: a2PixelStride = a2.getPixelStride();
1024: a2BandOffset = a2.getBandOffset(0);
1025: a2Data = a2.getDoubleDataArray(0);
1026: }
1027:
1028: /* Destination color channels. */
1029: int dLineStride = d.getScanlineStride();
1030: int dPixelStride = d.getPixelStride();
1031: int[] dBandOffsets = d.getBandOffsets();
1032: double[][] dData = d.getDoubleDataArrays();
1033:
1034: int dwidth = d.getWidth();
1035: int dheight = d.getHeight();
1036: int dbands = d.getNumBands();
1037:
1038: int s1LineOffset = 0, s2LineOffset = 0, a1LineOffset = 0, a2LineOffset = 0, dLineOffset = 0, s1PixelOffset, s2PixelOffset, a1PixelOffset, a2PixelOffset, dPixelOffset;
1039:
1040: if (premultiplied) {
1041: /* dest = source1 + source2 * (1 - alpha1) */
1042:
1043: for (int h = 0; h < dheight; h++) {
1044: s1PixelOffset = s1LineOffset;
1045: s2PixelOffset = s2LineOffset;
1046: a1PixelOffset = a1LineOffset + a1BandOffset;
1047: dPixelOffset = dLineOffset;
1048:
1049: s1LineOffset += s1LineStride;
1050: s2LineOffset += s2LineStride;
1051: a1LineOffset += a1LineStride;
1052: dLineOffset += dLineStride;
1053:
1054: for (int w = 0; w < dwidth; w++) {
1055: double t = 1.0 - a1Data[a1PixelOffset];
1056:
1057: /* Destination color channels. */
1058: for (int b = 0; b < dbands; b++) {
1059: dData[b][dPixelOffset + dBandOffsets[b]] = s1Data[b][s1PixelOffset
1060: + s1BandOffsets[b]]
1061: + s2Data[b][s2PixelOffset
1062: + s2BandOffsets[b]] * t;
1063: }
1064:
1065: s1PixelOffset += s1PixelStride;
1066: s2PixelOffset += s2PixelStride;
1067: a1PixelOffset += a1PixelStride;
1068: dPixelOffset += dPixelStride;
1069: }
1070: }
1071:
1072: } else {
1073: if (alpha2 == null) {
1074: /* dest = source1 * alpha1 + source2 * (1 - alpha1) */
1075:
1076: for (int h = 0; h < dheight; h++) {
1077: s1PixelOffset = s1LineOffset;
1078: s2PixelOffset = s2LineOffset;
1079: a1PixelOffset = a1LineOffset + a1BandOffset;
1080: dPixelOffset = dLineOffset;
1081:
1082: s1LineOffset += s1LineStride;
1083: s2LineOffset += s2LineStride;
1084: a1LineOffset += a1LineStride;
1085: dLineOffset += dLineStride;
1086:
1087: for (int w = 0; w < dwidth; w++) {
1088: double t1 = a1Data[a1PixelOffset];
1089: double t2 = 1.0 - t1;
1090:
1091: /* Destination color channels. */
1092: for (int b = 0; b < dbands; b++) {
1093: dData[b][dPixelOffset + dBandOffsets[b]] = s1Data[b][s1PixelOffset
1094: + s1BandOffsets[b]]
1095: * t1
1096: + s2Data[b][s2PixelOffset
1097: + s2BandOffsets[b]] * t2;
1098: }
1099:
1100: s1PixelOffset += s1PixelStride;
1101: s2PixelOffset += s2PixelStride;
1102: a1PixelOffset += a1PixelStride;
1103: dPixelOffset += dPixelStride;
1104: }
1105: }
1106: } else {
1107: /*
1108: * dest = (source1 * alpha1 + source2 * alpha2 * (1 - alpha1)) /
1109: * (alpha1 + alpha2 * (1 - alpha1))
1110: */
1111:
1112: for (int h = 0; h < dheight; h++) {
1113: s1PixelOffset = s1LineOffset;
1114: s2PixelOffset = s2LineOffset;
1115: a1PixelOffset = a1LineOffset + a1BandOffset;
1116: a2PixelOffset = a2LineOffset + a2BandOffset;
1117: dPixelOffset = dLineOffset;
1118:
1119: s1LineOffset += s1LineStride;
1120: s2LineOffset += s2LineStride;
1121: a1LineOffset += a1LineStride;
1122: a2LineOffset += a2LineStride;
1123: dLineOffset += dLineStride;
1124:
1125: for (int w = 0; w < dwidth; w++) {
1126: double t1 = a1Data[a1PixelOffset];
1127: double t2 = a2Data[a2PixelOffset] * (1.0 - t1);
1128: double t3 = t1 + t2;
1129: double t4, t5;
1130: if (t3 == 0.0) {
1131: t4 = 0.0;
1132: t5 = 0.0;
1133: } else {
1134: t4 = t1 / t3;
1135: t5 = t2 / t3;
1136: }
1137:
1138: /* Destination color channels. */
1139: for (int b = 0; b < dbands; b++) {
1140: dData[b][dPixelOffset + dBandOffsets[b]] = s1Data[b][s1PixelOffset
1141: + s1BandOffsets[b]]
1142: * t4
1143: + s2Data[b][s2PixelOffset
1144: + s2BandOffsets[b]] * t5;
1145: }
1146:
1147: s1PixelOffset += s1PixelStride;
1148: s2PixelOffset += s2PixelStride;
1149: a1PixelOffset += a1PixelStride;
1150: a2PixelOffset += a2PixelStride;
1151: dPixelOffset += dPixelStride;
1152: }
1153: }
1154: }
1155: }
1156: }
1157:
1158: /** Returns the format tags to be used with <code>RasterAccessor</code>. */
1159: protected synchronized RasterFormatTag[] getFormatTags() {
1160: RenderedImage[] ri;
1161: if (alpha2 == null) {
1162: ri = new RenderedImage[3];
1163: } else {
1164: ri = new RenderedImage[4];
1165: ri[3] = alpha2;
1166: }
1167: ri[0] = getSourceImage(0);
1168: ri[1] = getSourceImage(1);
1169: ri[2] = alpha1;
1170:
1171: return RasterAccessor.findCompatibleTags(ri, this);
1172: }
1173: }
|