| /* | |
| * 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} | |
| * | |
| * <p> | |
| * <img src="{@docRoot}reference/android/images/graphics/blendmode_CLEAR.png" /> | |
| * <figcaption>Destination pixels covered by the source are cleared to 0.</figcaption> | |
| * </p> | |
| * <p>\(\alpha_{out} = 0\)</p> | |
| * <p>\(C_{out} = 0\)</p> | |
| */ | |
| CLEAR(0), | |
| /** | |
| * {@usesMathJax} | |
| * | |
| * <p> | |
| * <img src="{@docRoot}reference/android/images/graphics/blendmode_SRC.png" /> | |
| * <figcaption>The source pixels replace the destination pixels.</figcaption> | |
| * </p> | |
| * <p>\(\alpha_{out} = \alpha_{src}\)</p> | |
| * <p>\(C_{out} = C_{src}\)</p> | |
| */ | |
| SRC(1), | |
| /** | |
| * {@usesMathJax} | |
| * | |
| * <p> | |
| * <img src="{@docRoot}reference/android/images/graphics/blendmode_DST.png" /> | |
| * <figcaption>The source pixels are discarded, leaving the destination intact.</figcaption> | |
| * </p> | |
| * <p>\(\alpha_{out} = \alpha_{dst}\)</p> | |
| * <p>\(C_{out} = C_{dst}\)</p> | |
| */ | |
| DST(2), | |
| /** | |
| * {@usesMathJax} | |
| * | |
| * <p> | |
| * <img src="{@docRoot}reference/android/images/graphics/blendmode_SRC_OVER.png" /> | |
| * <figcaption>The source pixels are drawn over the destination pixels.</figcaption> | |
| * </p> | |
| * <p>\(\alpha_{out} = \alpha_{src} + (1 - \alpha_{src}) * \alpha_{dst}\)</p> | |
| * <p>\(C_{out} = C_{src} + (1 - \alpha_{src}) * C_{dst}\)</p> | |
| */ | |
| SRC_OVER(3), | |
| /** | |
| * {@usesMathJax} | |
| * | |
| * <p> | |
| * <img src="{@docRoot}reference/android/images/graphics/blendmode_DST_OVER.png" /> | |
| * <figcaption>The source pixels are drawn behind the destination pixels.</figcaption> | |
| * </p> | |
| * <p>\(\alpha_{out} = \alpha_{dst} + (1 - \alpha_{dst}) * \alpha_{src}\)</p> | |
| * <p>\(C_{out} = C_{dst} + (1 - \alpha_{dst}) * C_{src}\)</p> | |
| */ | |
| DST_OVER(4), | |
| /** | |
| * {@usesMathJax} | |
| * | |
| * <p> | |
| * <img src="{@docRoot}reference/android/images/graphics/blendmode_SRC_IN.png" /> | |
| * <figcaption>Keeps the source pixels that cover the destination pixels, | |
| * discards the remaining source and destination pixels.</figcaption> | |
| * </p> | |
| * <p>\(\alpha_{out} = \alpha_{src} * \alpha_{dst}\)</p> | |
| * <p>\(C_{out} = C_{src} * \alpha_{dst}\)</p> | |
| */ | |
| SRC_IN(5), | |
| /** | |
| * {@usesMathJax} | |
| * | |
| * <p> | |
| * <img src="{@docRoot}reference/android/images/graphics/blendmode_DST_IN.png" /> | |
| * <figcaption>Keeps the destination pixels that cover source pixels, | |
| * discards the remaining source and destination pixels.</figcaption> | |
| * </p> | |
| * <p>\(\alpha_{out} = \alpha_{src} * \alpha_{dst}\)</p> | |
| * <p>\(C_{out} = C_{dst} * \alpha_{src}\)</p> | |
| */ | |
| DST_IN(6), | |
| /** | |
| * {@usesMathJax} | |
| * | |
| * <p> | |
| * <img src="{@docRoot}reference/android/images/graphics/blendmode_SRC_OUT.png" /> | |
| * <figcaption>Keeps the source pixels that do not cover destination pixels. | |
| * Discards source pixels that cover destination pixels. Discards all | |
| * destination pixels.</figcaption> | |
| * </p> | |
| * <p>\(\alpha_{out} = (1 - \alpha_{dst}) * \alpha_{src}\)</p> | |
| * <p>\(C_{out} = (1 - \alpha_{dst}) * C_{src}\)</p> | |
| */ | |
| SRC_OUT(7), | |
| /** | |
| * {@usesMathJax} | |
| * | |
| * <p> | |
| * <img src="{@docRoot}reference/android/images/graphics/blendmode_DST_OUT.png" /> | |
| * <figcaption>Keeps the destination pixels that are not covered by source pixels. | |
| * Discards destination pixels that are covered by source pixels. Discards all | |
| * source pixels.</figcaption> | |
| * </p> | |
| * <p>\(\alpha_{out} = (1 - \alpha_{src}) * \alpha_{dst}\)</p> | |
| * <p>\(C_{out} = (1 - \alpha_{src}) * C_{dst}\)</p> | |
| */ | |
| DST_OUT(8), | |
| /** | |
| * {@usesMathJax} | |
| * | |
| * <p> | |
| * <img src="{@docRoot}reference/android/images/graphics/blendmode_SRC_ATOP.png" /> | |
| * <figcaption>Discards the source pixels that do not cover destination pixels. | |
| * Draws remaining source pixels over destination pixels.</figcaption> | |
| * </p> | |
| * <p>\(\alpha_{out} = \alpha_{dst}\)</p> | |
| * <p>\(C_{out} = \alpha_{dst} * C_{src} + (1 - \alpha_{src}) * C_{dst}\)</p> | |
| */ | |
| SRC_ATOP(9), | |
| /** | |
| * {@usesMathJax} | |
| * | |
| * <p> | |
| * <img src="{@docRoot}reference/android/images/graphics/blendmode_DST_ATOP.png" /> | |
| * <figcaption>Discards the destination pixels that are not covered by source pixels. | |
| * Draws remaining destination pixels over source pixels.</figcaption> | |
| * </p> | |
| * <p>\(\alpha_{out} = \alpha_{src}\)</p> | |
| * <p>\(C_{out} = \alpha_{src} * C_{dst} + (1 - \alpha_{dst}) * C_{src}\)</p> | |
| */ | |
| DST_ATOP(10), | |
| /** | |
| * {@usesMathJax} | |
| * | |
| * <p> | |
| * <img src="{@docRoot}reference/android/images/graphics/blendmode_XOR.png" /> | |
| * <figcaption>Discards the source and destination pixels where source pixels | |
| * cover destination pixels. Draws remaining source pixels.</figcaption> | |
| * </p> | |
| * <p> | |
| * \(\alpha_{out} = (1 - \alpha_{dst}) * \alpha_{src} + (1 - \alpha_{src}) * \alpha_{dst}\) | |
| * </p> | |
| * <p>\(C_{out} = (1 - \alpha_{dst}) * C_{src} + (1 - \alpha_{src}) * C_{dst}\)</p> | |
| */ | |
| XOR(11), | |
| /** | |
| * {@usesMathJax} | |
| * | |
| * <p> | |
| * <img src="{@docRoot}reference/android/images/graphics/blendmode_PLUS.png" /> | |
| * <figcaption>Adds the source pixels to the destination pixels and saturates | |
| * the result.</figcaption> | |
| * </p> | |
| * <p>\(\alpha_{out} = max(0, min(\alpha_{src} + \alpha_{dst}, 1))\)</p> | |
| * <p>\(C_{out} = max(0, min(C_{src} + C_{dst}, 1))\)</p> | |
| */ | |
| PLUS(12), | |
| /** | |
| * {@usesMathJax} | |
| * | |
| * <p> | |
| * <img src="{@docRoot}reference/android/images/graphics/blendmode_MODULATE.png" /> | |
| * <figcaption>Multiplies the source and destination pixels.</figcaption> | |
| * </p> | |
| * <p>\(\alpha_{out} = \alpha_{src} * \alpha_{dst}\)</p> | |
| * <p>\(C_{out} = C_{src} * C_{dst}\)</p> | |
| * | |
| */ | |
| MODULATE(13), | |
| /** | |
| * {@usesMathJax} | |
| * | |
| * <p> | |
| * <img src="{@docRoot}reference/android/images/graphics/blendmode_SCREEN.png" /> | |
| * <figcaption> | |
| * Adds the source and destination pixels, then subtracts the | |
| * source pixels multiplied by the destination. | |
| * </figcaption> | |
| * </p> | |
| * <p>\(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)</p> | |
| * <p>\(C_{out} = C_{src} + C_{dst} - C_{src} * C_{dst}\)</p> | |
| */ | |
| SCREEN(14), | |
| /** | |
| * {@usesMathJax} | |
| * | |
| * <p> | |
| * <img src="{@docRoot}reference/android/images/graphics/blendmode_OVERLAY.png" /> | |
| * <figcaption> | |
| * Multiplies or screens the source and destination depending on the | |
| * destination color. | |
| * </figcaption> | |
| * </p> | |
| * <p>\(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)</p> | |
| * <p>\(\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}\)</p> | |
| */ | |
| OVERLAY(15), | |
| /** | |
| * {@usesMathJax} | |
| * | |
| * <p> | |
| * <img src="{@docRoot}reference/android/images/graphics/blendmode_DARKEN.png" /> | |
| * <figcaption> | |
| * Retains the smallest component of the source and | |
| * destination pixels. | |
| * </figcaption> | |
| * </p> | |
| * <p>\(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)</p> | |
| * <p> | |
| * \(C_{out} = | |
| * (1 - \alpha_{dst}) * C_{src} + (1 - \alpha_{src}) * C_{dst} + min(C_{src}, C_{dst})\) | |
| * </p> | |
| */ | |
| DARKEN(16), | |
| /** | |
| * {@usesMathJax} | |
| * | |
| * <p> | |
| * <img src="{@docRoot}reference/android/images/graphics/blendmode_LIGHTEN.png" /> | |
| * <figcaption>Retains the largest component of the source and | |
| * destination pixel.</figcaption> | |
| * </p> | |
| * <p>\(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)</p> | |
| * <p> | |
| * \(C_{out} = | |
| * (1 - \alpha_{dst}) * C_{src} + (1 - \alpha_{src}) * C_{dst} + max(C_{src}, C_{dst})\) | |
| * </p> | |
| */ | |
| LIGHTEN(17), | |
| /** | |
| * {@usesMathJax} | |
| * | |
| * <p> | |
| * <img src="{@docRoot}reference/android/images/graphics/blendmode_COLOR_DODGE.png" /> | |
| * <figcaption>Makes destination brighter to reflect source.</figcaption> | |
| * </p> | |
| * <p> | |
| * \(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\) | |
| * </p> | |
| * <p> | |
| * \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} | |
| * </p> | |
| */ | |
| COLOR_DODGE(18), | |
| /** | |
| * {@usesMathJax} | |
| * | |
| * <p> | |
| * <img src="{@docRoot}reference/android/images/graphics/blendmode_COLOR_BURN.png" /> | |
| * <figcaption>Makes destination darker to reflect source.</figcaption> | |
| * </p> | |
| * <p> | |
| * \(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\) | |
| * </p> | |
| * <p> | |
| * \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} | |
| * </p> | |
| */ | |
| COLOR_BURN(19), | |
| /** | |
| * {@usesMathJax} | |
| * | |
| * <p> | |
| * <img src="{@docRoot}reference/android/images/graphics/blendmode_HARD_LIGHT.png" /> | |
| * <figcaption>Makes destination lighter or darker, depending on source.</figcaption> | |
| * </p> | |
| * <p> | |
| * \(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\) | |
| * </p> | |
| * <p> | |
| * \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} | |
| * </p> | |
| */ | |
| HARD_LIGHT(20), | |
| /** | |
| * {@usesMathJax} | |
| * | |
| * <p> | |
| * <img src="{@docRoot}reference/android/images/graphics/blendmode_SOFT_LIGHT.png" /> | |
| * <figcaption>Makes destination lighter or darker, depending on source.</figcaption> | |
| * </p> | |
| * <p> | |
| * Where | |
| * \begin{equation} | |
| * m = | |
| * \begin{cases} | |
| * C_{dst} / \alpha_{dst} & \alpha_{dst} \gt 0 \\ | |
| * 0 & otherwise | |
| * \end{cases} | |
| * \end{equation} | |
| * </p> | |
| * <p> | |
| * \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} | |
| * </p> | |
| * <p> | |
| * \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} | |
| * </p> | |
| * <p> | |
| * \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} | |
| * </p> | |
| */ | |
| SOFT_LIGHT(21), | |
| /** | |
| * {@usesMathJax} | |
| * | |
| * <p> | |
| * <img src="{@docRoot}reference/android/images/graphics/blendmode_DIFFERENCE.png" /> | |
| * <figcaption>Subtracts darker from lighter with higher contrast.</figcaption> | |
| * </p> | |
| * <p> | |
| * \begin{equation} | |
| * \alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst} | |
| * \end{equation} | |
| * </p> | |
| * <p> | |
| * \begin{equation} | |
| * C_{out} = C_{src} + C_{dst} - 2 * min(C_{src} | |
| * * \alpha_{dst}, C_{dst} * \alpha_{src}) | |
| * \end{equation} | |
| * </p> | |
| */ | |
| DIFFERENCE(22), | |
| /** | |
| * {@usesMathJax} | |
| * | |
| * <p> | |
| * <img src="{@docRoot}reference/android/images/graphics/blendmode_DIFFERENCE.png" /> | |
| * <figcaption>Subtracts darker from lighter with lower contrast.</figcaption> | |
| * </p> | |
| * <p> | |
| * \begin{equation} | |
| * \alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst} | |
| * \end{equation} | |
| * </p> | |
| * <p> | |
| * \begin{equation} | |
| * C_{out} = C_{src} + C_{dst} - 2 * C_{src} * C_{dst} | |
| * \end{equation} | |
| * </p> | |
| */ | |
| EXCLUSION(23), | |
| /** | |
| * {@usesMathJax} | |
| * | |
| * <p> | |
| * <img src="{@docRoot}reference/android/images/graphics/blendmode_MODULATE.png" /> | |
| * <figcaption>Multiplies the source and destination pixels.</figcaption> | |
| * </p> | |
| * <p>\(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)</p> | |
| * <p>\(C_{out} = | |
| * C_{src} * (1 - \alpha_{dst}) + C_{dst} * (1 - \alpha_{src}) + (C_{src} * C_{dst})\) | |
| * </p> | |
| */ | |
| MULTIPLY(24), | |
| /** | |
| * {@usesMathJax} | |
| * | |
| * <p> | |
| * <img src="{@docRoot}reference/android/images/graphics/blendmode_HUE.png" /> | |
| * <figcaption> | |
| * Replaces hue of destination with hue of source, leaving saturation | |
| * and luminosity unchanged. | |
| * </figcaption> | |
| * </p> | |
| */ | |
| HUE(25), | |
| /** | |
| * {@usesMathJax} | |
| * | |
| * <p> | |
| * <img src="{@docRoot}reference/android/images/graphics/blendmode_SATURATION.png" /> | |
| * <figcaption> | |
| * Replaces saturation of destination saturation hue of source, leaving hue and | |
| * luminosity unchanged. | |
| * </figcaption> | |
| * </p> | |
| */ | |
| SATURATION(26), | |
| /** | |
| * {@usesMathJax} | |
| * | |
| * <p> | |
| * <img src="{@docRoot}reference/android/images/graphics/blendmode_COLOR.png" /> | |
| * <figcaption> | |
| * Replaces hue and saturation of destination with hue and saturation of source, | |
| * leaving luminosity unchanged. | |
| * </figcaption> | |
| * </p> | |
| */ | |
| COLOR(27), | |
| /** | |
| * {@usesMathJax} | |
| * | |
| * <p> | |
| * <img src="{@docRoot}reference/android/images/graphics/blendmode_LUMINOSITY.png" /> | |
| * <figcaption> | |
| * Replaces luminosity of destination with luminosity of source, leaving hue and | |
| * saturation unchanged. | |
| * </figcaption> | |
| * </p> | |
| */ | |
| 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; | |
| } | |
| } |