/* * Copyright (C) 2006 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.graphics; /** *

This class contains the list of alpha compositing and blending modes * that can be passed to {@link PorterDuffXfermode}, a specialized implementation * of {@link Paint}'s {@link Paint#setXfermode(Xfermode) transfer mode}. * All the available modes can be found in the {@link Mode} enum.

*/ public class PorterDuff { /** * {@usesMathJax} * *

Porter-Duff

* *

The name of the parent class is an homage to the work of Thomas Porter and * Tom Duff, presented in their seminal 1984 paper titled "Compositing Digital Images". * In this paper, the authors describe 12 compositing operators that govern how to * compute the color resulting of the composition of a source (the graphics object * to render) with a destination (the content of the render target).

* *

"Compositing Digital Images" was published in Computer Graphics * Volume 18, Number 3 dated July 1984.

* *

Because the work of Porter and Duff focuses solely on the effects of the alpha * channel of the source and destination, the 12 operators described in the original * paper are called alpha compositing modes here.

* *

For convenience, this class also provides several blending modes, which similarly * define the result of compositing a source and a destination but without being * constrained to the alpha channel. These blending modes are not defined by Porter * and Duff but have been included in this class for convenience purposes.

* *

Diagrams

* *

All the example diagrams presented below use the same source and destination * images:

* * * * * * *
* *
Source image
*
* *
Destination image
*
* *

The order of drawing operations used to generate each diagram is shown in the * following code snippet:

* *
     * Paint paint = new Paint();
     * canvas.drawBitmap(destinationImage, 0, 0, paint);
     *
     * PorterDuff.Mode mode = // choose a mode
     * paint.setXfermode(new PorterDuffXfermode(mode));
     *
     * canvas.drawBitmap(sourceImage, 0, 0, paint);
     * 
* *

Alpha compositing modes

* * * * * * * * * * * * * * * * * * * * *
* *
{@link #SRC Source}
*
* *
{@link #SRC_OVER Source Over}
*
* *
{@link #SRC_IN Source In}
*
* *
{@link #SRC_ATOP Source Atop}
*
* *
{@link #DST Destination}
*
* *
{@link #DST_OVER Destination Over}
*
* *
{@link #DST_IN Destination In}
*
* *
{@link #DST_ATOP Destination Atop}
*
* *
{@link #CLEAR Clear}
*
* *
{@link #SRC_OUT Source Out}
*
* *
{@link #DST_OUT Destination Out}
*
* *
{@link #XOR Exclusive Or}
*
* *

Blending modes

* * * * * * * * * * * *
* *
{@link #DARKEN Darken}
*
* *
{@link #LIGHTEN Lighten}
*
* *
{@link #MULTIPLY Multiply}
*
* *
{@link #SCREEN Screen}
*
* *
{@link #OVERLAY Overlay}
*
* *

Compositing equations

* *

The documentation of each individual alpha compositing or blending mode below * provides the exact equation used to compute alpha and color value of the result * of the composition of a source and destination.

* *

The result (or output) alpha value is noted \(\alpha_{out}\). The result (or output) * color value is noted \(C_{out}\).

*/ public enum Mode { // these value must match their native equivalents. See SkXfermode.h /** *

* *

Destination pixels covered by the source are cleared to 0.
*

*

\(\alpha_{out} = 0\)

*

\(C_{out} = 0\)

*/ CLEAR (0), /** *

* *

The source pixels replace the destination pixels.
*

*

\(\alpha_{out} = \alpha_{src}\)

*

\(C_{out} = C_{src}\)

*/ SRC (1), /** *

* *

The source pixels are discarded, leaving the destination intact.
*

*

\(\alpha_{out} = \alpha_{dst}\)

*

\(C_{out} = C_{dst}\)

*/ DST (2), /** *

* *

The source pixels are drawn over the destination pixels.
*

*

\(\alpha_{out} = \alpha_{src} + (1 - \alpha_{src}) * \alpha_{dst}\)

*

\(C_{out} = C_{src} + (1 - \alpha_{src}) * C_{dst}\)

*/ SRC_OVER (3), /** *

* *

The source pixels are drawn behind the destination pixels.
*

*

\(\alpha_{out} = \alpha_{dst} + (1 - \alpha_{dst}) * \alpha_{src}\)

*

\(C_{out} = C_{dst} + (1 - \alpha_{dst}) * C_{src}\)

*/ DST_OVER (4), /** *

* *

Keeps the source pixels that cover the destination pixels, * discards the remaining source and destination pixels.
*

*

\(\alpha_{out} = \alpha_{src} * \alpha_{dst}\)

*

\(C_{out} = C_{src} * \alpha_{dst}\)

*/ SRC_IN (5), /** *

* *

Keeps the destination pixels that cover source pixels, * discards the remaining source and destination pixels.
*

*

\(\alpha_{out} = \alpha_{src} * \alpha_{dst}\)

*

\(C_{out} = C_{dst} * \alpha_{src}\)

*/ DST_IN (6), /** *

* *

Keeps the source pixels that do not cover destination pixels. * Discards source pixels that cover destination pixels. Discards all * destination pixels.
*

*

\(\alpha_{out} = (1 - \alpha_{dst}) * \alpha_{src}\)

*

\(C_{out} = (1 - \alpha_{dst}) * C_{src}\)

*/ SRC_OUT (7), /** *

* *

Keeps the destination pixels that are not covered by source pixels. * Discards destination pixels that are covered by source pixels. Discards all * source pixels.
*

*

\(\alpha_{out} = (1 - \alpha_{src}) * \alpha_{dst}\)

*

\(C_{out} = (1 - \alpha_{src}) * C_{dst}\)

*/ DST_OUT (8), /** *

* *

Discards the source pixels that do not cover destination pixels. * Draws remaining source pixels over destination pixels.
*

*

\(\alpha_{out} = \alpha_{dst}\)

*

\(C_{out} = \alpha_{dst} * C_{src} + (1 - \alpha_{src}) * C_{dst}\)

*/ SRC_ATOP (9), /** *

* *

Discards the destination pixels that are not covered by source pixels. * Draws remaining destination pixels over source pixels.
*

*

\(\alpha_{out} = \alpha_{src}\)

*

\(C_{out} = \alpha_{src} * C_{dst} + (1 - \alpha_{dst}) * C_{src}\)

*/ DST_ATOP (10), /** *

* *

Discards the source and destination pixels where source pixels * cover destination pixels. Draws remaining source pixels.
*

*

\(\alpha_{out} = (1 - \alpha_{dst}) * \alpha_{src} + (1 - \alpha_{src}) * \alpha_{dst}\)

*

\(C_{out} = (1 - \alpha_{dst}) * C_{src} + (1 - \alpha_{src}) * C_{dst}\)

*/ XOR (11), /** *

* *

Retains the smallest component of the source and * destination pixels.
*

*

\(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)

*

\(C_{out} = (1 - \alpha_{dst}) * C_{src} + (1 - \alpha_{src}) * C_{dst} + min(C_{src}, C_{dst})\)

*/ DARKEN (16), /** *

* *

Retains the largest component of the source and * destination pixel.
*

*

\(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)

*

\(C_{out} = (1 - \alpha_{dst}) * C_{src} + (1 - \alpha_{src}) * C_{dst} + max(C_{src}, C_{dst})\)

*/ LIGHTEN (17), /** *

* *

Multiplies the source and destination pixels.
*

*

\(\alpha_{out} = \alpha_{src} * \alpha_{dst}\)

*

\(C_{out} = C_{src} * C_{dst}\)

*/ MULTIPLY (13), /** *

* *

Adds the source and destination pixels, then subtracts the * source pixels multiplied by the destination.
*

*

\(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)

*

\(C_{out} = C_{src} + C_{dst} - C_{src} * C_{dst}\)

*/ SCREEN (14), /** *

* *

Adds the source pixels to the destination pixels and saturates * the result.
*

*

\(\alpha_{out} = max(0, min(\alpha_{src} + \alpha_{dst}, 1))\)

*

\(C_{out} = max(0, min(C_{src} + C_{dst}, 1))\)

*/ ADD (12), /** *

* *

Multiplies or screens the source and destination depending on the * destination color.
*

*

\(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)

*

\(\begin{equation} * C_{out} = \begin{cases} 2 * C_{src} * C_{dst} & 2 * C_{dst} \lt \alpha_{dst} \\ * \alpha_{src} * \alpha_{dst} - 2 (\alpha_{dst} - C_{src}) (\alpha_{src} - C_{dst}) & otherwise \end{cases} * \end{equation}\)

*/ OVERLAY (15); Mode(int nativeInt) { this.nativeInt = nativeInt; } /** * @hide */ public final int nativeInt; } /** * @hide */ public static int modeToInt(Mode mode) { return mode.nativeInt; } /** * @hide */ public static Mode intToMode(int val) { switch (val) { default: case 0: return Mode.CLEAR; case 1: return Mode.SRC; case 2: return Mode.DST; case 3: return Mode.SRC_OVER; case 4: return Mode.DST_OVER; case 5: return Mode.SRC_IN; case 6: return Mode.DST_IN; case 7: return Mode.SRC_OUT; case 8: return Mode.DST_OUT; case 9: return Mode.SRC_ATOP; case 10: return Mode.DST_ATOP; case 11: return Mode.XOR; case 16: return Mode.DARKEN; case 17: return Mode.LIGHTEN; case 13: return Mode.MULTIPLY; case 14: return Mode.SCREEN; case 12: return Mode.ADD; case 15: return Mode.OVERLAY; } } }