動腦學(xué)院UI預(yù)習(xí)資料-Paint(Xfermode)

前言
圖像混合模式
在之前的Paint的使用當(dāng)中我們提到了高級渲染和濾鏡箩言,那么今天我們來學(xué)習(xí)最后一個內(nèi)容點Xfermode,我們能通過使用Xfermode能夠完成圖像組合的效果

1.XFermode
在使用Paint的時候焕襟,我們能通過使用Xfermode能夠完成圖像組合的效果將繪制的圖形的像素和Canvas上對應(yīng)位置的像素按照一定的規(guī)則進行混合陨收,形成新的像素,再更新到Canvas中形成最終的圖形鸵赖,那圖具體效果見下圖

谷歌官方-PorterDuffXfermode.png
這個是我寫的一個demo.png

看到上述圖形务漩,其實這個時候我們能夠很明顯的知道我們的XFermode其實實際上就是在使用圖形之間的相互組合以達到自己的想要的目的, 他提供了16種組合模式

ADD:飽和相加,對圖像飽和度進行相加,不常用

CLEAR:清除圖像

DARKEN:變暗,較深的顏色覆蓋較淺的顏色卫漫,若兩者深淺程度相同則混合

DST:只顯示目標(biāo)圖像

DST_ATOP:在源圖像和目標(biāo)圖像相交的地方繪制【目標(biāo)圖像】菲饼,在不相交的地方繪制【源圖像】,相交處的效果受到源圖像和目標(biāo)圖像alpha的影響

DST_IN:只在源圖像和目標(biāo)圖像相交的地方繪制【目標(biāo)圖像】列赎,繪制效果受到源圖像對應(yīng)地方透明度影響

DST_OUT:只在源圖像和目標(biāo)圖像不相交的地方繪制【目標(biāo)圖像】宏悦,在相交的地方根據(jù)源圖像的alpha進行過濾镐确,源圖像完全不透明則完全過濾,完全透明則不過濾

DST_OVER:將目標(biāo)圖像放在源圖像上方

LIGHTEN:變亮饼煞,與DARKEN相反源葫,DARKEN和LIGHTEN生成的圖像結(jié)果與Android對顏色值深淺的定義有關(guān)

MULTIPLY:正片疊底,源圖像素顏色值乘以目標(biāo)圖像素顏色值除以255得到混合后圖像像素顏色值

OVERLAY:疊加

SCREEN:濾色砖瞧,色調(diào)均和,保留兩個圖層中較白的部分息堂,較暗的部分被遮蓋

SRC:只顯示源圖像

SRC_ATOP:在源圖像和目標(biāo)圖像相交的地方繪制【源圖像】,在不相交的地方繪制【目標(biāo)圖像】块促,相交處的效果受到源圖像和目標(biāo)圖像alpha的影響

SRC_IN:只在源圖像和目標(biāo)圖像相交的地方繪制【源圖像】

SRC_OUT:只在源圖像和目標(biāo)圖像不相交的地方繪制【源圖像】荣堰,相交的地方根據(jù)目標(biāo)圖像的對應(yīng)地方的alpha進行過濾,目標(biāo)圖像完全不透明則完全過濾竭翠,完全透明則不過濾

SRC_OVER:將源圖像放在目標(biāo)圖像上方

XOR:在源圖像和目標(biāo)圖像相交的地方之外繪制它們振坚,在相交的地方受到對應(yīng)alpha和色值影響,如果完全不透明則相交處完全不繪制

這個方法跟我們上節(jié)課講到的setColorFilter蠻相似的斋扰。
但是我門可以看到谷歌官方所提供的和我們自己寫的還是有一些差異渡八, 那么我門需要來了解到XFermode的本質(zhì)到底是什么,上面開篇我們有提到過传货,XFermode是將繪制的圖形的像素和Canvas上對應(yīng)位置的像素按照一定的規(guī)則進行混合屎鳍,那么我們需要知道他到底是怎么進行混合,如何進行計算的
這個時候我門走到源碼當(dāng)中问裕,查看API文檔發(fā)現(xiàn)其果然有三個子類:AvoidXfermode, PixelXorXfermode和PorterDuffXfermode這三個子類實現(xiàn)的功能要比setColorFilter的三個子類復(fù)雜得多逮壁。
由于AvoidXfermode, PixelXorXfermode都已經(jīng)被標(biāo)注為過時了,所以這次主要研究的是仍然在使用的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;
          }
      }

那么在這里我們可以看到其實實際上這個類非常簡單僻澎, 我門可以認為他就是一個常量類標(biāo)注了16種模式貌踏, 而在這里真正的模式實在mode當(dāng)中(下面粗略看一下就行)

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

}

這個時候我們會發(fā)現(xiàn)比較的懵逼十饥,都是html是什么狀況窟勃?那么這個時候我?guī)痛蠹易隽藗€處理將這些注釋貼到了一個html當(dāng)中(具體見課件)給大家翻譯了一下

image.png

image.png

image.png

那么這里通過翻譯出來之后我們可以很明顯知道,這個類當(dāng)中所定義的是這些16種模式的常量以及16模式所能達到的效果逗堵,以及踏實如何進行計算的秉氧。

那么這里我們就上面寫的幾個重點進行分析

      The result (or output) alpha value is noted \(\alpha_{out}\). The result (or output)
      color value is noted \(C_{out}\).
      alpha的結(jié)果或者輸出被標(biāo)記為 \(\alpha_{out}\).  顏色值的結(jié)果或輸出被標(biāo)記為\(C_{out}\).

從這句話其實我門可以看出,他寫的很明白
在上述的過程中有提到(\alpha_{out})表示透明輸出值(C_{out}).表示是顏色輸出值蜒秤,那么其實就是通過兩個圖形計算的到這兩個關(guān)鍵輸出值就是構(gòu)成我們圖形混合的最大秘密
而下面就是具體的那些計算公式

       /**
     * <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表示源像素的顏色值
藍色矩形表示的是原圖片纸泡,黃色圓表示的是目標(biāo)圖片
在上述的計算公式當(dāng)中我們關(guān)注幾個關(guān)鍵點
alpha------透明度
C------顏色
src------原圖
dst------目標(biāo)圖
out------輸出

把這幾個弄清楚漂问,其實我們的xfermode在我門面前就沒有任何的秘密可言了

那么注意, 這個是27版本的,與之前版本計算規(guī)則上肯定有所差異, 其實我們看版本的源碼更好理解寫蚤假,沒有這么復(fù)雜那么在此貼住以前老版本(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類

----優(yōu)先顯示的是源圖片

SRC [Sa, Sc] ---- 處理圖片相交區(qū)域時磷仰,總是顯示的是原圖片

SRC_IN [Sa * Da, Sc * Da] ---- 處理圖片相交區(qū)域時袍嬉,受到目標(biāo)圖片的Alpha值影響
當(dāng)我們的目標(biāo)圖片為空白像素的時候,目標(biāo)圖片也會變成空白
簡單的來說就是用目標(biāo)圖片的透明度來改變源圖片的透明度和飽和度灶平,當(dāng)目標(biāo)圖片的透明度為0時伺通,源圖片就不會顯示

SRC_OUT [Sa * (1 - Da), Sc * (1 - Da)] --- 同SRC_IN類似 (1 - Da)
用我們目標(biāo)圖片的透明度的補值來改變源圖片的透明度和飽和度,當(dāng)目標(biāo)圖片的透明度為不透明時,源圖片就不會顯示

SRC_ATOP [Da, Sc * Da + (1 - Sa) * Dc]
---- 當(dāng)透明度為100%和0%時逢享,SRC_IN 和 SRC_ATOP是通用的
當(dāng)透明度不為上述的兩個值時泵殴,SRC_ATOP 比 SRC_IN 源圖像的飽和度會增

2、DST類

----優(yōu)先顯示的是目標(biāo)圖片

DST_IN [Sa * Da, Sa * Dc] ----- 對比一下SRC_IN拼苍,正好和我們SRC_IN想法笑诅,在相交的時候以源圖片的透明度來改變目標(biāo)圖片的透明度和飽和度
當(dāng)源圖片的透明度為0的時候,目標(biāo)圖片完全不顯示

3疮鲫、其他的疊加效果

MULTIPLY[Sa * Da, Sc * Dc] ---

        應(yīng)用:可以把圖片的輪廓取出來
            LIGHTEN -- 變亮
         書架 頭頂燈光變亮效果

那么到這里我們已經(jīng)基本了解了XFermode的情況吆你,我們來看下具體是如何使用的,從使用角度來講soeasy, 只需要在Paint當(dāng)中調(diào)用一句代碼( 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;
            }
        }
    }
}
}

同學(xué)們可以去試著使用一下

作者:動腦學(xué)院Barry老師
原創(chuàng)博客俊犯,請注明轉(zhuǎn)載處....
原文鏈接:http://www.reibang.com/p/713584d018fc
來源:簡書(昵稱BarryKerwin)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末妇多,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子燕侠,更是在濱河造成了極大的恐慌者祖,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件绢彤,死亡現(xiàn)場離奇詭異七问,居然都是意外死亡,警方通過查閱死者的電腦和手機茫舶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門械巡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人饶氏,你說我怎么就攤上這事讥耗。” “怎么了疹启?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵古程,是天一觀的道長。 經(jīng)常有香客問我喊崖,道長挣磨,這世上最難降的妖魔是什么菲宴? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮趋急,結(jié)果婚禮上喝峦,老公的妹妹穿的比我還像新娘。我一直安慰自己呜达,他們只是感情好谣蠢,可當(dāng)我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著查近,像睡著了一般眉踱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上霜威,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天谈喳,我揣著相機與錄音,去河邊找鬼戈泼。 笑死婿禽,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的大猛。 我是一名探鬼主播扭倾,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼挽绩!你這毒婦竟也來了膛壹?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤唉堪,失蹤者是張志新(化名)和其女友劉穎模聋,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體唠亚,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡链方,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了趾撵。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片侄柔。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖占调,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情移剪,我是刑警寧澤究珊,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站纵苛,受9級特大地震影響剿涮,放射性物質(zhì)發(fā)生泄漏言津。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一取试、第九天 我趴在偏房一處隱蔽的房頂上張望悬槽。 院中可真熱鬧,春花似錦瞬浓、人聲如沸初婆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽磅叛。三九已至,卻和暖如春萨赁,著一層夾襖步出監(jiān)牢的瞬間弊琴,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工杖爽, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留敲董,地道東北人。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓慰安,卻偏偏與公主長得像臣缀,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子精置,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容