关于android:高级UI之Paint-Xfermode-总结

3次阅读

共计 25411 个字符,预计需要花费 64 分钟才能阅读完成。

前言

Xfermode 国外有大神称之为过渡模式, 这种翻译比拟贴切但恐怕不易了解,大家也能够间接称之为图像混合模式

一、图像混合模式

在之前的 Paint 的应用当中咱们提到了高级渲染和滤镜,那么明天咱们来学习最初一个内容点 Xfermode,咱们能通过应用 Xfermode 可能实现图像组合的成果

1.XFermode

在应用 Paint 的时候,咱们能通过应用 Xfermode 可能实现图像组合的成果将绘制的图形的像素和 Canvas 上对应地位的像素依照肯定的规定进行混合,造成新的像素,再更新到 Canvas 中造成最终的图形,那图具体成果见下图

看到上述图形,其实这个时候咱们可能很显著的晓得咱们的 XFermode 其实实际上就是在应用图形之间的互相组合以达到本人的想要的目标,他提供了 16 种组合模式

  • ADD: 饱和相加, 对图像饱和度进行相加, 不罕用
  • CLEAR: 革除图像
  • DARKEN: 变暗, 较深的色彩笼罩较浅的色彩,若两者深浅水平雷同则混合
  • DST: 只显示指标图像
  • DST_ATOP: 在源图像和指标图像相交的中央绘制【指标图像】,在不相交的中央绘制【源图像】,相交处的成果受到源图像和指标图像 alpha 的影响
  • DST_IN: 只在源图像和指标图像相交的中央绘制【指标图像】,绘制成果受到源图像对应中央透明度影响
  • DST_OUT: 只在源图像和指标图像不相交的中央绘制【指标图像】,在相交的中央依据源图像的 alpha 进行过滤,源图像齐全不通明则齐全过滤,齐全通明则不过滤
  • DST_OVER: 将指标图像放在源图像上方
  • LIGHTEN: 变亮,与 DARKEN 相同,DARKEN 和 LIGHTEN 生成的图像后果与 Android 对色彩值深浅的定义无关
  • MULTIPLY: 正片叠底,源图像素色彩值乘以指标图像素色彩值除以 255 失去混合后图像像素色彩值
  • OVERLAY: 叠加
  • SCREEN: 滤色,色调均和, 保留两个图层中较白的局部,较暗的局部被遮蔽
  • SRC: 只显示源图像
  • SRC_ATOP: 在源图像和指标图像相交的中央绘制【源图像】,在不相交的中央绘制【指标图像】,相交处的成果受到源图像和指标图像 alpha 的影响
  • SRC_IN: 只在源图像和指标图像相交的中央绘制【源图像】
  • SRC_OUT: 只在源图像和指标图像不相交的中央绘制【源图像】,相交的中央依据指标图像的对应中央的 alpha 进行过滤,指标图像齐全不通明则齐全过滤,齐全通明则不过滤
  • SRC_OVER: 将源图像放在指标图像上方
  • XOR: 在源图像和指标图像相交的中央之外绘制它们,在相交的中央受到对应 alpha 和色值影响,如果齐全不通明则相交处齐全不绘制

这个办法跟之前讲到的 setColorFilter 蛮类似的。 然而咱们能够看到谷歌官网所提供的和咱们本人写的还是有一些差别,那么咱们须要来理解到 XFermode 的实质到底是什么,下面开篇咱们有提到过,XFermode 是将绘制的图形的像素和 Canvas 上对应地位的像素依照肯定的规定进行混合,那么咱们须要晓得他到底是怎么进行混合,如何进行计算的?

这个时候我门走到源码当中,查看 API 文档发现其果然有三个子类:AvoidXfermode, PixelXorXfermodePorterDuffXfermode 这三个子类实现的性能要比 setColorFilter 的三个子类简单得多。

因为 AvoidXfermode, PixelXorXfermode 都曾经被标注为过期了,所以这次次要钻研的是依然在应用的PorterDuffXfermode

      /**
       * <p>Specialized implementation of {@link Paint}'s
       * {@link Paint#setXfermode(Xfermode) transfer mode}. Refer to the
       * documentation of the {@link PorterDuff.Mode} enum for more
       * information on the available alpha compositing and blending modes.      
       */
      public class PorterDuffXfermode extends Xfermode {
          /**
           * Create an xfermode that uses the specified porter-duff mode.
           *
           * @param mode           The porter-duff mode that is applied
           */
          public PorterDuffXfermode(PorterDuff.Mode mode) {porterDuffMode = mode.nativeInt;}
      }

那么在这里咱们能够看到其实实际上这个类非常简单,我门能够认为他就是一个常量类标注了 16 种模式,而在这里真正的模式切实 mode 当中(上面粗略看一下就行)

    public class PorterDuff {
/**
 * {@usesMathJax}
 *
 * <h3>Porter-Duff</h3>
 *
 * <p>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).</p>
 *
 * <p>"Compositing Digital Images" was published in <em>Computer Graphics</em>
 * Volume 18, Number 3 dated July 1984.</p>
 *
 * <p>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.</p>
 *
 * <p>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.</p>
 *
 * <h3>Diagrams</h3>
 *
 * <p>All the example diagrams presented below use the same source and destination
 * images:</p>
 *
 * <table summary="Source and Destination" style="background-color: transparent;">
 *     <tr>
 *         <td style="border: none; text-align: center;">
 *             <img src="{@docRoot}reference/android/images/graphics/composite_SRC.png" />
 *             <figcaption>Source image</figcaption>
 *         </td>
 *         <td style="border: none; text-align: center;">
 *             <img src="{@docRoot}reference/android/images/graphics/composite_DST.png" />
 *             <figcaption>Destination image</figcaption>
 *         </td>
 *     </tr>
 * </table>
 *
 * <p>The order of drawing operations used to generate each diagram is shown in the
 * following code snippet:</p>
 *
 * <pre class="pretty print"
 * 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);
 * </pre>

 *
 * <h3>Alpha compositing modes</h3>
 *
 * <table summary="Alpha compositing modes" style="background-color: transparent;">
 *     <tr>
 *         <td style="border: none; text-align: center;">
 *             <img src="{@docRoot}reference/android/images/graphics/composite_SRC.png" />
 *             <figcaption>{@link #SRC Source}</figcaption>
 *         </td>
 *         <td style="border: none; text-align: center;">
 *             <img src="{@docRoot}reference/android/images/graphics/composite_SRC_OVER.png" />
 *             <figcaption>{@link #SRC_OVER Source Over}</figcaption>
 *         </td>
 *         <td style="border: none; text-align: center;">
 *             <img src="{@docRoot}reference/android/images/graphics/composite_SRC_IN.png" />
 *             <figcaption>{@link #SRC_IN Source In}</figcaption>
 *         </td>
 *         <td style="border: none; text-align: center;">
 *             <img src="{@docRoot}reference/android/images/graphics/composite_SRC_ATOP.png" />
 *             <figcaption>{@link #SRC_ATOP Source Atop}</figcaption>
 *         </td>
 *     </tr>
 *     <tr>
 *         <td style="border: none; text-align: center;">
 *             <img src="{@docRoot}reference/android/images/graphics/composite_DST.png" />
 *             <figcaption>{@link #DST Destination}</figcaption>
 *         </td>
 *         <td style="border: none; text-align: center;">
 *             <img src="{@docRoot}reference/android/images/graphics/composite_DST_OVER.png" />
 *             <figcaption>{@link #DST_OVER Destination Over}</figcaption>
 *         </td>
 *         <td style="border: none; text-align: center;">
 *             <img src="{@docRoot}reference/android/images/graphics/composite_DST_IN.png" />
 *             <figcaption>{@link #DST_IN Destination In}</figcaption>
 *         </td>
 *         <td style="border: none; text-align: center;">
 *             <img src="{@docRoot}reference/android/images/graphics/composite_DST_ATOP.png" />
 *             <figcaption>{@link #DST_ATOP Destination Atop}</figcaption>
 *         </td>
 *     </tr>
 *     <tr>
 *         <td style="border: none; text-align: center;">
 *             <img src="{@docRoot}reference/android/images/graphics/composite_CLEAR.png" />
 *             <figcaption>{@link #CLEAR Clear}</figcaption>
 *         </td>
 *         <td style="border: none; text-align: center;">
 *             <img src="{@docRoot}reference/android/images/graphics/composite_SRC_OUT.png" />
 *             <figcaption>{@link #SRC_OUT Source Out}</figcaption>
 *         </td>
 *         <td style="border: none; text-align: center;">
 *             <img src="{@docRoot}reference/android/images/graphics/composite_DST_OUT.png" />
 *             <figcaption>{@link #DST_OUT Destination Out}</figcaption>
 *         </td>
 *         <td style="border: none; text-align: center;">
 *             <img src="{@docRoot}reference/android/images/graphics/composite_XOR.png" />
 *             <figcaption>{@link #XOR Exclusive Or}</figcaption>
 *         </td>
 *     </tr>
 * </table>
 *
 * <h3>Blending modes</h3>
 *
 * <table summary="Blending modes" style="background-color: transparent;">
 *     <tr>
 *         <td style="border: none; text-align: center;">
 *             <img src="{@docRoot}reference/android/images/graphics/composite_DARKEN.png" />
 *             <figcaption>{@link #DARKEN Darken}</figcaption>
 *         </td>
 *         <td style="border: none; text-align: center;">
 *             <img src="{@docRoot}reference/android/images/graphics/composite_LIGHTEN.png" />
 *             <figcaption>{@link #LIGHTEN Lighten}</figcaption>
 *         </td>
 *         <td style="border: none; text-align: center;">
 *             <img src="{@docRoot}reference/android/images/graphics/composite_MULTIPLY.png" />
 *             <figcaption>{@link #MULTIPLY Multiply}</figcaption>
 *         </td>
 *     </tr>
 *     <tr>
 *         <td style="border: none; text-align: center;">
 *             <img src="{@docRoot}reference/android/images/graphics/composite_SCREEN.png" />
 *             <figcaption>{@link #SCREEN Screen}</figcaption>
 *         </td>
 *         <td style="border: none; text-align: center;">
 *             <img src="{@docRoot}reference/android/images/graphics/composite_OVERLAY.png" />
 *             <figcaption>{@link #OVERLAY Overlay}</figcaption>
 *         </td>
 *     </tr>
 * </table>
 *
 * <h3>Compositing equations</h3>
 *
 * <p>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.</p>
 *
 * <p>The result (or output) alpha value is noted \(\alpha_{out}\). The result (or output)
 * color value is noted \(C_{out}\).</p>
 */
public enum Mode {
    // these value must match their native equivalents. See SkXfermode.h
    /**
     * <p>
     *     <img src="{@docRoot}reference/android/images/graphics/composite_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),
    /**
     * <p>
     *     <img src="{@docRoot}reference/android/images/graphics/composite_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),
    /**
     * <p>
     *     <img src="{@docRoot}reference/android/images/graphics/composite_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),
    /**
     * <p>
     *     <img src="{@docRoot}reference/android/images/graphics/composite_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),
    /**
     * <p>
     *     <img src="{@docRoot}reference/android/images/graphics/composite_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),
    /**
     * <p>
     *     <img src="{@docRoot}reference/android/images/graphics/composite_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),
    /**
     * <p>
     *     <img src="{@docRoot}reference/android/images/graphics/composite_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),
    /**
     * <p>
     *     <img src="{@docRoot}reference/android/images/graphics/composite_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),
    /**
     * <p>
     *     <img src="{@docRoot}reference/android/images/graphics/composite_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),
    /**
     * <p>
     *     <img src="{@docRoot}reference/android/images/graphics/composite_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),
    /**
     * <p>
     *     <img src="{@docRoot}reference/android/images/graphics/composite_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),
    /**
     * <p>
     *     <img src="{@docRoot}reference/android/images/graphics/composite_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),
    /**
     * <p>
     *     <img src="{@docRoot}reference/android/images/graphics/composite_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),
    /**
     * <p>
     *     <img src="{@docRoot}reference/android/images/graphics/composite_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),
    /**
     * <p>
     *     <img src="{@docRoot}reference/android/images/graphics/composite_MULTIPLY.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>
     */
    MULTIPLY    (13),
    /**
     * <p>
     *     <img src="{@docRoot}reference/android/images/graphics/composite_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),
    /**
     * <p>
     *     <img src="{@docRoot}reference/android/images/graphics/composite_ADD.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>
     */
    ADD         (12),
    /**
     * <p>
     *     <img src="{@docRoot}reference/android/images/graphics/composite_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);

    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;
    }
}

}

这个时候咱们会发现比拟的懵逼,都是 html 是什么情况?那么这个时候我帮大家做了个解决将这些正文贴到了一个 html 当中给大家翻译了一下

那么这里通过翻译进去之后咱们能够很显著晓得,这个类当中所定义的是这些 16 种模式的常量以及 16 模式所能达到的成果,以及虚浮如何进行计算的。

那么这里咱们就下面写的几个重点进行剖析

      The result (or output) alpha value is noted \(\alpha_{out}\). The result (or output)
      color value is noted \(C_{out}\).
      alpha 的后果或者输入被标记为 \(\alpha_{out}\).  色彩值的后果或输入被标记为 \(C_{out}\).

从这句话其实咱们能够看出,他写的很明确。在上述的过程中有提到 (\alpha_{out}) 示意通明输入值 (C_{out}). 示意是色彩输入值,那么其实就是通过两个图形计算的到这两个要害输入值就是形成咱们图形混合的最大机密
而上面就是具体的那些计算公式

       /**
     * <p>
     *     <img src="{@docRoot}reference/android/images/graphics/composite_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),
    /**
     * <p>
     *     <img src="{@docRoot}reference/android/images/graphics/composite_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),
    /**
     * <p>
     *     <img src="{@docRoot}reference/android/images/graphics/composite_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),
    /**
     * <p>
     *     <img src="{@docRoot}reference/android/images/graphics/composite_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),
    /**
     * <p>
     *     <img src="{@docRoot}reference/android/images/graphics/composite_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),
    /**
     * <p>
     *     <img src="{@docRoot}reference/android/images/graphics/composite_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),
    /**
     * <p>
     *     <img src="{@docRoot}reference/android/images/graphics/composite_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),
    /**
     * <p>
     *     <img src="{@docRoot}reference/android/images/graphics/composite_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),
    /**
     * <p>
     *     <img src="{@docRoot}reference/android/images/graphics/composite_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),
    /**
     * <p>
     *     <img src="{@docRoot}reference/android/images/graphics/composite_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),
    /**
     * <p>
     *     <img src="{@docRoot}reference/android/images/graphics/composite_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),
    /**
     * <p>
     *     <img src="{@docRoot}reference/android/images/graphics/composite_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),
    /**
     * <p>
     *     <img src="{@docRoot}reference/android/images/graphics/composite_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),
    /**
     * <p>
     *     <img src="{@docRoot}reference/android/images/graphics/composite_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),
    /**
     * <p>
     *     <img src="{@docRoot}reference/android/images/graphics/composite_MULTIPLY.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>
     */
    MULTIPLY    (13),
    /**
     * <p>
     *     <img src="{@docRoot}reference/android/images/graphics/composite_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),
    /**
     * <p>
     *     <img src="{@docRoot}reference/android/images/graphics/composite_ADD.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>
     */
    ADD         (12),
    /**
     * <p>
     *     <img src="{@docRoot}reference/android/images/graphics/composite_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);

咱们一个像素的色彩都是由四个重量组成,即 ARGB,A 示意的是咱们 Alpha 值,RGB 示意的是色彩,S 示意的是原像素,原像素的值示意[Sa,Sc] Sa 示意的就是源像素的 Alpha 值,Sc 示意源像素的色彩值,蓝色矩形示意的是原图片,黄色圆示意的是指标图片。

在上述的计算公式当中咱们关注几个关键点

  • alpha—— 透明度
  • C—— 色彩
  • src—— 原图
  • dst—— 指标图
  • out—— 输入

把这几个弄清楚,其实咱们的 xfermode 在我门背后就没有任何的机密可言了

那么留神,这个是 27 版本的, 与之前版本计算规定上必定有所差别,其实咱们看版本的源码更好了解写,没有这么简单那么在此贴住以前老版本 (21) 的作为参考比对

public class PorterDuff {

// these value must match their native equivalents. See SkPorterDuff.h
public enum Mode {/** [0, 0] */
    CLEAR       (0),
    /** [Sa, Sc] */
    SRC         (1),
    /** [Da, Dc] */
    DST         (2),
    /** [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] */
    SRC_OVER    (3),
    /** [Sa + (1 - Sa)*Da, Rc = Dc + (1 - Da)*Sc] */
    DST_OVER    (4),
    /** [Sa * Da, Sc * Da] */
    SRC_IN      (5),
    /** [Sa * Da, Sa * Dc] */
    DST_IN      (6),
    /** [Sa * (1 - Da), Sc * (1 - Da)] */
    SRC_OUT     (7),
    /** [Da * (1 - Sa), Dc * (1 - Sa)] */
    DST_OUT     (8),
    /** [Da, Sc * Da + (1 - Sa) * Dc] */
    SRC_ATOP    (9),
    /** [Sa, Sa * Dc + Sc * (1 - Da)] */
    DST_ATOP    (10),
    /** [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc] */
    XOR         (11),
    /** [Sa + Da - Sa*Da,
         Sc*(1 - Da) + Dc*(1 - Sa) + min(Sc, Dc)] */
    DARKEN      (12),
    /** [Sa + Da - Sa*Da,
         Sc*(1 - Da) + Dc*(1 - Sa) + max(Sc, Dc)] */
    LIGHTEN     (13),
    /** [Sa * Da, Sc * Dc] */
    MULTIPLY    (14),
    /** [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] */
    SCREEN      (15),
    /** Saturate(S + D) */
    ADD         (16),
    OVERLAY     (17);

    Mode(int nativeInt) {this.nativeInt = nativeInt;}

    /**
     * @hide
     */
    public final int nativeInt;
}
}

二、混合模式分类

我门能够将混合模式分为三个类型(留神看模式常量的名字)

1、SRC 类

优先显示的是源图片

  • SRC [Sa, Sc] —- 解决图片相交区域时,总是显示的是原图片
  • SRC_IN [Sa Da, Sc Da] —- 解决图片相交区域时,受到指标图片的 Alpha 值影响。当咱们的指标图片为空白像素的时候,指标图片也会变成空白。简略的来说就是用指标图片的透明度来扭转源图片的透明度和饱和度,当指标图片的透明度为 0 时,源图片就不会显示
  • SRC_OUT [Sa (1 – Da), Sc (1 – Da)] — 同 SRC_IN 相似 (1 – Da),用咱们指标图片的透明度的补值来扭转源图片的透明度和饱和度, 当指标图片的透明度为不通明时,源图片就不会显示
  • SRC_ATOP [Da, Sc Da + (1 – Sa) Dc]—- 当透明度为 100% 和 0% 时,SRC_IN 和 SRC_ATOP 是通用的。当透明度不为上述的两个值时,SRC_ATOP 比 SRC_IN 源图像的饱和度会增

2、DST 类

优先显示的是指标图片

DST_IN [Sa Da, Sa Dc] —– 比照一下 SRC_IN,正好和咱们 SRC_IN 想法,在相交的时候以源图片的透明度来扭转指标图片的透明度和饱和度。当源图片的透明度为 0 的时候,指标图片齐全不显示

3、其余的叠加成果

MULTIPLY[Sa Da, Sc Dc] — 能够把图片的轮廓取出来

LIGHTEN — 变亮头顶灯光变亮成果

那么到这里咱们曾经根本理解了 XFermode 的状况,咱们来看下具体是如何应用的,从应用角度来讲 soeasy, 只须要在 Paint 当中调用一句代码 (paint.setXfermode(Mode) 就能实现,上面是官网给出的 demo

 public class sampleActivity extends AppCompatActivity {
// create a bitmap with a circle, used for the "dst" image
static Bitmap makeDst(int w, int h) {Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
    Canvas c = new Canvas(bm);
    Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
    p.setColor(0xFFFFCC44);
    c.drawOval(new RectF(0, 0, w*3/4, h*3/4), p);
    return bm;
}
// create a bitmap with a rect, used for the "src" image
static Bitmap makeSrc(int w, int h) {Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
    Canvas c = new Canvas(bm);
    Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
    p.setColor(0xFF66AAFF);
    c.drawRect(w/3, h/3, w*19/20, h*19/20, p);
    return bm;
}
@Override
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
    setContentView(new SampleView(this));
}
private static class SampleView extends View {
    private static final int W = 200;
    private static final int H = 200;
    private static final int ROW_MAX = 4;   // number of samples per row
    private Bitmap mSrcB;
    private Bitmap mDstB;
    private Shader mBG;     // background checker-board pattern
    private static final Xfermode[] sModes = {new PorterDuffXfermode(PorterDuff.Mode.CLEAR),
            new PorterDuffXfermode(PorterDuff.Mode.SRC),
            new PorterDuffXfermode(PorterDuff.Mode.DST),
            new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER),
            new PorterDuffXfermode(PorterDuff.Mode.DST_OVER),
            new PorterDuffXfermode(PorterDuff.Mode.SRC_IN),
            new PorterDuffXfermode(PorterDuff.Mode.DST_IN),
            new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT),
            new PorterDuffXfermode(PorterDuff.Mode.DST_OUT),
            new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP),
            new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP),
            new PorterDuffXfermode(PorterDuff.Mode.XOR),
            new PorterDuffXfermode(PorterDuff.Mode.DARKEN),
            new PorterDuffXfermode(PorterDuff.Mode.LIGHTEN),
            new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY),
            new PorterDuffXfermode(PorterDuff.Mode.SCREEN)
    };
    private static final String[] sLabels = {
            "Clear", "Src", "Dst", "SrcOver",
            "DstOver", "SrcIn", "DstIn", "SrcOut",
            "DstOut", "SrcATop", "DstATop", "Xor",
            "Darken", "Lighten", "Multiply", "Screen"
    };
    public SampleView(Context context) {super(context);
        mSrcB = makeSrc(W, H);
        mDstB = makeDst(W, H);
        // make a ckeckerboard pattern
        Bitmap bm = Bitmap.createBitmap(new int[] { 0xFFFFFFFF, 0xFFCCCCCC,
                        0xFFCCCCCC, 0xFFFFFFFF }, 2, 2,
                Bitmap.Config.RGB_565);
        mBG = new BitmapShader(bm,
                Shader.TileMode.REPEAT,
                Shader.TileMode.REPEAT);
        Matrix m = new Matrix();
        m.setScale(6, 6);
        mBG.setLocalMatrix(m);
    }
    @Override protected void onDraw(Canvas canvas) {canvas.drawColor(Color.WHITE);
        Paint labelP = new Paint(Paint.ANTI_ALIAS_FLAG);
        labelP.setTextAlign(Paint.Align.CENTER);
        Paint paint = new Paint();
        paint.setFilterBitmap(false);
        canvas.translate(15, 35);
        int x = 0;
        int y = 0;
        for (int i = 0; i < sModes.length; i++) {
            // draw the border
            paint.setStyle(Paint.Style.STROKE);
            paint.setShader(null);
            canvas.drawRect(x - 0.5f, y - 0.5f,
                    x + W + 0.5f, y + H + 0.5f, paint);
            // draw the checker-board pattern
            paint.setStyle(Paint.Style.FILL);
            paint.setShader(mBG);
            canvas.drawRect(x, y, x + W, y + H, paint);
            // draw the src/dst example into our offscreen bitmap
            int sc = canvas.saveLayer(x, y, x + W, y + H, null,
                    Canvas.MATRIX_SAVE_FLAG |
                            Canvas.CLIP_SAVE_FLAG |
                            Canvas.HAS_ALPHA_LAYER_SAVE_FLAG |
                            Canvas.FULL_COLOR_LAYER_SAVE_FLAG |
                            Canvas.CLIP_TO_LAYER_SAVE_FLAG);
            canvas.translate(x, y);
            canvas.drawBitmap(mDstB, 0, 0, paint);
            paint.setXfermode(sModes[i]);
            canvas.drawBitmap(mSrcB, 0, 0, paint);
            paint.setXfermode(null);
            canvas.restoreToCount(sc);
            // draw the label
            canvas.drawText(sLabels[i],
                    x + W/2, y - labelP.getTextSize()/2, labelP);
            x += W + 10;
            // wrap around when we've drawn enough for one row
            if ((i % ROW_MAX) == ROW_MAX - 1) {
                x = 0;
                y += H + 30;
            }
        }
    }
}
}

小伙伴们能够去试着应用一下

看完三件事❤️


如果你感觉这篇内容对你还蛮有帮忙,我想邀请你帮我三个小忙:

  1. 点赞,转发,有你们的『点赞和评论』,才是我发明的能源。
  2. 关注公众号 『小新聊 Android』,不定期分享原创常识。
  3. 同时能够期待后续文章 ing🚀
  4. 公众号回复【666】扫码还可拿到 Android 进阶学习材料包
正文完
 0