blob: 5c294aa72ce80407e0db881cd8f87285495b3662 [file] [log] [blame]
/*
* 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;
}
}