/* * Copyright (C) 2018 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; import android.annotation.NonNull; import android.annotation.Nullable; public enum BlendMode { /** * {@usesMathJax} * *

* *

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

*

\(\alpha_{out} = 0\)

*

\(C_{out} = 0\)

*/ CLEAR(0), /** * {@usesMathJax} * *

* *

The source pixels replace the destination pixels.
*

*

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

*

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

*/ SRC(1), /** * {@usesMathJax} * *

* *

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

*

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

*

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

*/ DST(2), /** * {@usesMathJax} * *

* *

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), /** * {@usesMathJax} * *

* *

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), /** * {@usesMathJax} * *

* *

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), /** * {@usesMathJax} * *

* *

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), /** * {@usesMathJax} * *

* *

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), /** * {@usesMathJax} * *

* *

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), /** * {@usesMathJax} * *

* *

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), /** * {@usesMathJax} * *

* *

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), /** * {@usesMathJax} * *

* *

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), /** * {@usesMathJax} * *

* *

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))\)

*/ PLUS(12), /** * {@usesMathJax} * *

* *

Multiplies the source and destination pixels.
*

*

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

*

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

* */ MODULATE(13), /** * {@usesMathJax} * *

* *

* 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), /** * {@usesMathJax} * *

* *

* 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), /** * {@usesMathJax} * *

* *

* 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), /** * {@usesMathJax} * *

* *

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), /** * {@usesMathJax} * *

* *

Makes destination brighter to reflect source.
*

*

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

*

* \begin{equation} * C_{out} = * \begin{cases} * C_{src} * (1 - \alpha_{dst}) & C_{dst} = 0 \\ * C_{src} + \alpha_{dst}*(1 - \alpha_{src}) & C_{src} = \alpha_{src} \\ * \alpha_{src} * min(\alpha_{dst}, C_{dst} * \alpha_{src}/(\alpha_{src} - C_{src})) * + C_{src} *(1 - \alpha_{dst} + \alpha_{dst}*(1 - \alpha_{src}) & otherwise * \end{cases} * \end{equation} *

*/ COLOR_DODGE(18), /** * {@usesMathJax} * *

* *

Makes destination darker to reflect source.
*

*

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

*

* \begin{equation} * C_{out} = * \begin{cases} * C_{dst} + C_{src}*(1 - \alpha_{dst}) & C_{dst} = \alpha_{dst} \\ * \alpha_{dst}*(1 - \alpha_{src}) & C_{src} = 0 \\ * \alpha_{src}*(\alpha_{dst} - min(\alpha_{dst}, (\alpha_{dst} * - C_{dst})*\alpha_{src}/C_{src})) * + C_{src} * (1 - \alpha_{dst}) + \alpha_{dst}*(1-\alpha_{src}) & otherwise * \end{cases} * \end{equation} *

*/ COLOR_BURN(19), /** * {@usesMathJax} * *

* *

Makes destination lighter or darker, depending on source.
*

*

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

*

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

*/ HARD_LIGHT(20), /** * {@usesMathJax} * *

* *

Makes destination lighter or darker, depending on source.
*

*

* Where * \begin{equation} * m = * \begin{cases} * C_{dst} / \alpha_{dst} & \alpha_{dst} \gt 0 \\ * 0 & otherwise * \end{cases} * \end{equation} *

*

* \begin{equation} * g = * \begin{cases} * (16 * m * m + 4 * m) * (m - 1) + 7 * m & 4 * C_{dst} \leq \alpha_{dst} \\ * \sqrt m - m & otherwise * \end{cases} * \end{equation} *

*

* \begin{equation} * f = * \begin{cases} * C_{dst} * (\alpha_{src} + (2 * C_{src} - \alpha_{src}) * (1 - m)) * & 2 * C_{src} \leq \alpha_{src} \\ * C_{dst} * \alpha_{src} + \alpha_{dst} * (2 * C_{src} - \alpha_{src}) * g * & otherwise * \end{cases} * \end{equation} *

*

* \begin{equation} * \alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst} * \end{equation} * \begin{equation} * C_{out} = C_{src} / \alpha_{dst} + C_{dst} / \alpha_{src} + f * \end{equation} *

*/ SOFT_LIGHT(21), /** * {@usesMathJax} * *

* *

Subtracts darker from lighter with higher contrast.
*

*

* \begin{equation} * \alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst} * \end{equation} *

*

* \begin{equation} * C_{out} = C_{src} + C_{dst} - 2 * min(C_{src} * * \alpha_{dst}, C_{dst} * \alpha_{src}) * \end{equation} *

*/ DIFFERENCE(22), /** * {@usesMathJax} * *

* *

Subtracts darker from lighter with lower contrast.
*

*

* \begin{equation} * \alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst} * \end{equation} *

*

* \begin{equation} * C_{out} = C_{src} + C_{dst} - 2 * C_{src} * C_{dst} * \end{equation} *

*/ EXCLUSION(23), /** * {@usesMathJax} * *

* *

Multiplies the source and destination pixels.
*

*

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

*

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

*/ MULTIPLY(24), /** * {@usesMathJax} * *

* *

* Replaces hue of destination with hue of source, leaving saturation * and luminosity unchanged. *
*

*/ HUE(25), /** * {@usesMathJax} * *

* *

* Replaces saturation of destination saturation hue of source, leaving hue and * luminosity unchanged. *
*

*/ SATURATION(26), /** * {@usesMathJax} * *

* *

* Replaces hue and saturation of destination with hue and saturation of source, * leaving luminosity unchanged. *
*

*/ COLOR(27), /** * {@usesMathJax} * *

* *

* Replaces luminosity of destination with luminosity of source, leaving hue and * saturation unchanged. *
*

*/ LUMINOSITY(28); private static final BlendMode[] BLEND_MODES = values(); /** * @hide */ public static @Nullable BlendMode fromValue(int value) { for (BlendMode mode : BLEND_MODES) { if (mode.mXfermode.porterDuffMode == value) { return mode; } } return null; } /** * @hide */ public static int toValue(BlendMode mode) { return mode.getXfermode().porterDuffMode; } /** * @hide */ public static @Nullable PorterDuff.Mode blendModeToPorterDuffMode(@Nullable BlendMode mode) { if (mode != null) { switch (mode) { case CLEAR: return PorterDuff.Mode.CLEAR; case SRC: return PorterDuff.Mode.SRC; case DST: return PorterDuff.Mode.DST; case SRC_OVER: return PorterDuff.Mode.SRC_OVER; case DST_OVER: return PorterDuff.Mode.DST_OVER; case SRC_IN: return PorterDuff.Mode.SRC_IN; case DST_IN: return PorterDuff.Mode.DST_IN; case SRC_OUT: return PorterDuff.Mode.SRC_OUT; case DST_OUT: return PorterDuff.Mode.DST_OUT; case SRC_ATOP: return PorterDuff.Mode.SRC_ATOP; case DST_ATOP: return PorterDuff.Mode.DST_ATOP; case XOR: return PorterDuff.Mode.XOR; case DARKEN: return PorterDuff.Mode.DARKEN; case LIGHTEN: return PorterDuff.Mode.LIGHTEN; // b/73224934 PorterDuff Multiply maps to Skia Modulate case MODULATE: return PorterDuff.Mode.MULTIPLY; case SCREEN: return PorterDuff.Mode.SCREEN; case PLUS: return PorterDuff.Mode.ADD; case OVERLAY: return PorterDuff.Mode.OVERLAY; default: return null; } } else { return null; } } @NonNull private final Xfermode mXfermode; BlendMode(int mode) { mXfermode = new Xfermode(); mXfermode.porterDuffMode = mode; } /** * @hide */ @NonNull public Xfermode getXfermode() { return mXfermode; } }