Canvas&Paint 知識梳理(4) 影象合成 Paint#setXfermode

澤毛發表於2017-12-21

一、概述

顏色合成文章中的最後一個小結當中,我們已經見到了PorterDuff.Mode這個列舉類,在本次的影象合成中,我們也需要用到這個類,我們先看一下最終呼叫的方法為:

    /**
     * Set or clear the xfermode object.
     * <p />
     * Pass null to clear any previous xfermode.
     * As a convenience, the parameter passed is also returned.
     *
     * @param xfermode May be null. The xfermode to be installed in the paint
     * @return         xfermode
     */
    public Xfermode setXfermode(Xfermode xfermode) {
        long xfermodeNative = 0;
        if (xfermode != null)
            xfermodeNative = xfermode.native_instance;
        native_setXfermode(mNativePaint, xfermodeNative);
        mXfermode = xfermode;
        return xfermode;
    }
複製程式碼

當一個Paint被設定了某個Xfermode時,那麼會根據源圖層、畫筆和Mode,來決定畫完之後的影象到底是什麼,在使用的時候,我們一般採用PorterDuffXfermode作為Xfermode的實現類,它的建構函式的引數就是我們之前說到的PoterDuff.Mode中的某個型別。

二、混合方式

關於混合的方式,網上有張圖是這麼總結的,其中DST表示原本有的影象,而SRC表示即將繪製上去的影象:

Canvas&Paint 知識梳理(4)   影象合成 Paint#setXfermode
在某些我們以為的情況下,並不能得到對應的結果,感謝下面這篇部落格的作者: http://blog.csdn.net/u010335298/article/details/51983420 他總結了獲得圖中的結果,上面的圖中還有幾個隱含的條件:

  • 關閉硬體加速。
  • 兩個進行疊加的圖層的大小是相同的。
  • 除了有顏色的部分,其它部分都是透明的。

三、示例

下面我們來看一下,DST_ATOP這種方式

3.1 開啟硬體加速

    private void drawPorterDuffXferMode(Canvas canvas) {
        Paint paint = new Paint();
        //繪製DST影象.
        paint.setColor(Color.YELLOW);
        canvas.drawCircle(100, 100, 100, paint);
        //繪製SRC影象.
        paint.setColor(Color.BLUE);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP));
        canvas.drawRect(100, 100, 300, 300, paint);
    }
複製程式碼

對應的結果為:

Canvas&Paint 知識梳理(4)   影象合成 Paint#setXfermode
和效果圖完全不符,下面,我們試一下關閉硬體加速:

3.2 關閉硬體加速

    private void init() {
        setLayerType(LAYER_TYPE_SOFTWARE, null);
    }

    private void drawPorterDuffXferMode(Canvas canvas) {
        Paint paint = new Paint();
        //繪製DST影象.
        paint.setColor(Color.YELLOW);
        canvas.drawCircle(100, 100, 100, paint);
        //繪製SRC影象.
        paint.setColor(Color.BLUE);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP));
        canvas.drawRect(100, 100, 300, 300, paint);
    }
複製程式碼

結果為:

Canvas&Paint 知識梳理(4)   影象合成 Paint#setXfermode
還是和理論結果不符合。

3.3 使用兩個大小一樣的Bitmap

    private Paint mDstPaint;
    private Paint mSrcPaint;
    private Canvas mDstCanvas;
    private Canvas mSrcCanvas;
    private Bitmap mSrcBitmap;
    private Bitmap mDstBitmap;
    
    private void init() {
        setLayerType(LAYER_TYPE_SOFTWARE, null);
        mDstPaint = new Paint();
        mSrcPaint = new Paint();
        mDstPaint.setColor(Color.YELLOW);
        mSrcPaint.setColor(Color.BLUE);
        mDstBitmap = Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888);
        mSrcBitmap = Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888);
        mDstCanvas = new Canvas(mDstBitmap);
        mSrcCanvas = new Canvas(mSrcBitmap);
    }

    private void drawPorterDuffXferMode(Canvas canvas) {
        //繪製DST影象.
        mDstCanvas.drawCircle(100, 100, 100, mDstPaint);
        canvas.drawBitmap(mDstBitmap, 0, 0, mDstPaint);
        //繪製SRC影象
        mSrcCanvas.drawRect(100, 100, 300, 300, mSrcPaint);
        mSrcPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP));
        canvas.drawBitmap(mSrcBitmap, 0, 0, mSrcPaint);
    }
複製程式碼

來看看這個的結果:

Canvas&Paint 知識梳理(4)   影象合成 Paint#setXfermode
為了得到這個結果,例項化了一堆的物件,並且需要在Bitmap的大小一樣的時候才可以生效,其實這也不能說是坑,因為根據原始碼來看,計算的計算本來就是取各畫素點的ARGB進行計算,如果圖層的大小不一樣,那麼計算的結果自然就和上面不同,從圖中來看,它也表明了DSTSRC的大小是相同的,並且在除了有顏色之外的部分都是透明的。

四、參考文獻

1.http://blog.csdn.net/u010335298/article/details/51983420

相關文章