Android 圖片倒影和setXfermode

1.MainActivity類:

package org.wp.activity;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.PorterDuffXfermode;
import android.graphics.Bitmap.Config;
import android.graphics.PorterDuff.Mode;
import android.graphics.Shader.TileMode;
import android.graphics.Paint;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.widget.ImageView;
/**
 * ==========================================
 * Matrix
 * ==========================================
 * The Matrix class holds a 3x3 matrix for transforming coordinates.
 * Matrix does not have a constructor,
 * so it must be explicitly initialized using either reset()
 * - to construct an identity matrix,
 * or one of the set..() functions
 * (e.g. setTranslate, setRotate, etc.).
 *
 * Matrix 中文裏叫矩陣,高等數學裏有介紹
 * 在圖像處理方面,主要是用於平面的縮放、平移、旋轉等操作。
 * Matrix的操作,總共分爲translate(平移),rotate(旋轉),
 * scale(縮放)和skew(傾斜)四種,
 * 每一種變換在Android的API裏都提供了set, post和pre三種操作方式
 * 除了translate,其他三種操作都可以指定中心點。
 *
 * ==========================================
 * createBitmap
 * ==========================================
 * public static Bitmap createBitmap (Bitmap source, int x, int y,
 *                  int width, int height, Matrix m, boolean filter)
 * Since: API Level 1 Returns an immutable bitmap from subset of the
 *        source bitmap, transformed by the optional matrix.
 *        It is initialized with the same density as the original bitmap.
 * Parameters
 * source  The bitmap we are subsetting
 * x  The x coordinate of the first pixel in source
 * y  The y coordinate of the first pixel in source
 * width  The number of pixels in each row
 * height  The number of rows
 * m  Optional matrix to be applied to the pixels
 * filter  true if the source should be filtered.
 *         Only applies if the matrix contains more than
 *         just translation.
 * Returns
 * A bitmap that represents the specified subset of source
 * Throws
 * IllegalArgumentException
 * if the x, y, width, height values are outside of the
 * dimensions of the source bitmap.
 *
 * source 源 bitmap對象
 * x 源座標x位置
 * y 源座標y位置
 * width 寬度
 * height 高度
 * m 接受的maxtrix對象,如果沒有可以設置 爲null
 * filter 該參數僅對maxtrix包含了超過一個翻轉纔有效
 *
 * ==========================================
 * LinearGradient
 * ==========================================
 * public LinearGradient (float x0, float y0, float x1, float y1, i
 *              nt color0, int color1, Shader.TileMode tile)
 * Since: API Level 1 Create a shader that draws a linear gradient along a line.
 * Parameters
 * x0  The x-coordinate for the start of the gradient line
 * y0  The y-coordinate for the start of the gradient line
 * x1  The x-coordinate for the end of the gradient line
 * y1  The y-coordinate for the end of the gradient line
 * color0  The color at the start of the gradient line.
 * color1  The color at the end of the gradient line.
 * tile  The Shader tiling mode
 *
 * 在android.graphics中我們可以找到有關Gradient字樣的類,
 * 比如LinearGradient 線性漸變、RadialGradient徑向漸變  和 角度漸變SweepGradient 三種,
 * 他們的基類爲android.graphics.Shader。
 *
 * LinearGradient線性漸變
 * 在android平臺中提供了兩種重載方式來實例化該類分別爲,
 * 他們的不同之處爲參數中第一種方法可以用顏色數組,和位置來實現更細膩的過渡效果,
 * 比如顏色採樣int[] colors數組中存放20種顏色,則漸變將會逐一處理。
 * 而第二種方法參數僅爲起初顏色color0和最終顏色color1。
 * LinearGradient(float x0, float y0, float x1, float y1,
 *      int[] colors, float[] positions, Shader.TileMode tile)
 * LinearGradient(float x0, float y0, float x1, float y1,
 *      int color0, int color1, Shader.TileMode tile)
 *
 * 參數一爲漸變起初點座標x位置,參數二爲y軸位置,
 * 參數三和四分辨對應漸變終點,最後參數爲平鋪方式,這裏設置爲鏡像
 *
 * 剛纔已經講到Gradient是基於Shader類,
 * 所以我們通過Paint的setShader方法來設置這個漸變
 * p.setShader(lg);
 *
 * ==========================================
 * setXfermode
 * ==========================================
 * Xfermode
 * 可以通過修改Paint的Xfermode來影響在
 * Canvas已有的圖像上面繪製新的顏色的方式 。
 *
 * 在正常的情況下,在已有的圖像上繪圖將會在其上面添加一層新的形狀。
 * 如果新的Paint是完全不透明的,那麼它將完全遮擋住下面的Paint;
 * 如果它是部分透明的,那麼它將會被染上下面的顏色。
 *
 * 下面的Xfermode子類可以改變這種行爲:
 *
 * AvoidXfermode  指定了一個顏色和容差,
 *                    強制Paint避免在它上面繪圖(或者只在它上面繪圖)。
 * PixelXorXfermode  當覆蓋已有的顏色時,應用一個簡單的像素XOR操作。
 *
 * PorterDuffXfermode  這是一個非常強大的轉換模式,使用它,
 *                     可以使用圖像合成的16條Porter-Duff規則的任意
 *                     一條來控制Paint如何與已有的Canvas圖像進行交互。
 *
 * 16條Porter-Duff規則
 * 1.PorterDuff.Mode.CLEAR
 * 2.PorterDuff.Mode.SRC
 * 3.PorterDuff.Mode.DST
 * 4.PorterDuff.Mode.SRC_OVER
 * 5.PorterDuff.Mode.DST_OVER
 * 6.PorterDuff.Mode.SRC_IN
 * 7.PorterDuff.Mode.DST_IN
 * 8.PorterDuff.Mode.SRC_OUT
 * 9.PorterDuff.Mode.DST_OUT
 * 10.PorterDuff.Mode.SRC_ATOP
 * 11.PorterDuff.Mode.DST_ATOP
 * 12.PorterDuff.Mode.XOR
 * 13.PorterDuff.Mode.DARKEN
 * 14.PorterDuff.Mode.LIGHTEN
 * 15.PorterDuff.Mode.MULTIPLY
 * 16.PorterDuff.Mode.SCREEN
 *
 * @author wp
 */
public class MainActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        ImageView myImageView = (ImageView) this.findViewById(R.id.myImageView);
        Bitmap bitmap = ((BitmapDrawable) getResources().getDrawable(
                R.drawable.qianqian)).getBitmap();
        myImageView.setImageBitmap(createReflectedImage(bitmap));
    }
    private Bitmap createReflectedImage(Bitmap originalBitmap) {
        // 圖片與倒影間隔距離
        final int reflectionGap = 4;
                                    
        // 圖片的寬度
        int width = originalBitmap.getWidth();
        // 圖片的高度
        int height = originalBitmap.getHeight();
                                    
        Matrix matrix = new Matrix();
        // 圖片縮放,x軸變爲原來的1倍,y軸爲-1倍,實現圖片的反轉
        matrix.preScale(1, -1);
        // 創建反轉後的圖片Bitmap對象,圖片高是原圖的一半。
        Bitmap reflectionBitmap = Bitmap.createBitmap(originalBitmap, 0,
                height / 2, width, height / 2, matrix, false);
        // 創建標準的Bitmap對象,寬和原圖一致,高是原圖的1.5倍。
        Bitmap withReflectionBitmap = Bitmap.createBitmap(width, (height
                + height / 2 + reflectionGap), Config.ARGB_8888);
        // 構造函數傳入Bitmap對象,爲了在圖片上畫圖
        Canvas canvas = new Canvas(withReflectionBitmap);
        // 畫原始圖片
        canvas.drawBitmap(originalBitmap, 0, 0, null);
        // 畫間隔矩形
        Paint defaultPaint = new Paint();
        canvas.drawRect(0, height, width, height + reflectionGap, defaultPaint);
        // 畫倒影圖片
        canvas.drawBitmap(reflectionBitmap, 0, height + reflectionGap, null);
        // 實現倒影效果
        Paint paint = new Paint();
        LinearGradient shader = new LinearGradient(0, originalBitmap.getHeight(),
                0, withReflectionBitmap.getHeight(), 0x70ffffff, 0x00ffffff,
                TileMode.MIRROR);
        paint.setShader(shader);
        paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
        // 覆蓋效果
        canvas.drawRect(0, height, width, withReflectionBitmap.getHeight(), paint);
        return withReflectionBitmap;
    }
}


效果圖:

201159619.png


2.setXfermode

設置兩張圖片相交時的模式

我們知道 在正常的情況下,在已有的圖像上繪圖將會在其上面添加一層新的形狀。 如果新的Paint是完全不透明的,那麼它將完全遮擋住下面的Paint;

而setXfermode就可以來解決這個問題



一般來說 用法是這樣的

Canvas canvas = new Canvas(bitmap1);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(mask, 0f, 0f, paint);

canvas原有的圖片 可以理解爲背景 就是dst
新畫上去的圖片 可以理解爲前景 就是src

Mode的值 如下圖

200703275.png





一個遮罩層的具體例子 參見

http://lonesane.iteye.com/blog/791267


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章