Android圖形繪製-Paint高級使用

1、渲染

在這裏插入圖片描述

Shader—着色器

BitmapShader–位圖渲染

        /**
         * 位圖渲染,BitmapShader(@NonNull Bitmap bitmap, @NonNull TileMode tileX, @NonNull TileMode tileY)
         * Bitmap:構造shader使用的bitmap
         * tileX:X軸方向的TileMode
         * tileY:Y軸方向的TileMode
         */
        /**
         * TileMode.CLAMP 拉伸最後一個像素去鋪滿剩下的地方
         * TileMode.MIRROR 通過鏡像翻轉鋪滿剩下的地方。
         * TileMode.REPEAT 重複圖片平鋪整個畫面(電腦設置壁紙)
         * 在圖片和顯示區域大小不符的情況進行擴充渲染
         */
//        BitmapShader bitMapShader = new BitmapShader(mBitMap, Shader.TileMode.CLAMP,
//                Shader.TileMode.CLAMP);
//        BitmapShader bitMapShader = new BitmapShader(mBitMap, Shader.TileMode.MIRROR,
//                Shader.TileMode.MIRROR);
        BitmapShader bitMapShader = new BitmapShader(mBitMap, Shader.TileMode.REPEAT,
                Shader.TileMode.REPEAT);

        mPaint.setShader(bitMapShader);
        mPaint.setAntiAlias(true);
        canvas.drawRect(0, 0, 800, 1800, mPaint);

3種效果如下顯示:
在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述

LinearGradient–線性渲染

        /**線性渲染
         * x0, y0, 起始點
         *  x1, y1, 結束點
         * int[]  mColors, 中間依次要出現的幾個顏色
         * float[] positions 位置數組,position的取值範圍[0,1],作用是指定幾個顏色分別放置在那個位置上,
         * 如果傳null,漸變就線性變化。
         *    tile 用於指定控件區域大於指定的漸變區域時,空白區域的顏色填充方法
         */
		LinearGradient linearGradient = new LinearGradient( 0, 0,800, 800,
                mColors, null, Shader.TileMode.CLAMP);
        // linearGradient = new LinearGradient(0, 0, 400, 400, mColors, null, Shader.TileMode.REPEAT);
		mPaint.setShader(linearGradient);
		canvas.drawRect(0, 0, 800, 800, mPaint);

在這裏插入圖片描述

RadialGradient—環形渲染

 		/**
         * 環形渲染
         * centerX ,centerY:shader的中心座標,開始漸變的座標
         * radius:漸變的半徑
         * centerColor,edgeColor:中心點漸變顏色,邊界的漸變顏色
         * colors:漸變顏色數組
         * stops:漸變位置數組,類似掃描漸變的positions數組,取值[0,1],中心點爲0,半徑到達位置爲1.0f
         * tileMode:shader未覆蓋以外的填充模式
         */
        RadialGradient mRadialGradient = new RadialGradient(300, 300, 100,
         mColors, null, Shader.TileMode.REPEAT);
		mPaint.setShader(mRadialGradient);
		canvas.drawCircle(300, 300, 300, mPaint);

在這裏插入圖片描述

SweepGradient—掃描渲染

      /**
         * 掃描渲染
         * cx,cy 漸變中心座標
         * color0,color1:漸變開始結束顏色
         * colors,positions:類似LinearGradient,用於多顏色漸變,positions爲null時,根據顏色線性漸變
         */
        SweepGradient mSweepGradient = new SweepGradient(300, 300, mColors, null);
		mPaint.setShader(mSweepGradient);
		canvas.drawCircle(300, 300, 300, mPaint);

在這裏插入圖片描述

ComposeShader—組合渲染

        /**
         * 組合渲染,
         * ComposeShader(@NonNull Shader shaderA, @NonNull Shader shaderB, Xfermode mode)
         * ComposeShader(@NonNull Shader shaderA, @NonNull Shader shaderB, PorterDuff.Mode mode)
         * shaderA,shaderB:要混合的兩種shader
         * Xfermode mode: 組合兩種shader顏色的模式
         * PorterDuff.Mode mode: 組合兩種shader顏色的模式
         */
 		/***************用ComposeShader即可實現心形圖漸變效果*********************************/
        //創建BitmapShader,用以繪製心
        Bitmap mBitmap = ((BitmapDrawable)getResources().getDrawable(R.drawable.heart)).getBitmap();
         BitmapShader bitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
         //創建LinearGradient,用以產生從左上角到右下角的顏色漸變效果
         LinearGradient linearGradient = new LinearGradient(0, 0, mWidth, mHeight,
                 Color.GREEN, Color.BLUE, Shader.TileMode.CLAMP);
         //bitmapShader對應目標像素,linearGradient對應源像素,像素顏色混合採用MULTIPLY模式
         ComposeShader composeShader = new ComposeShader(linearGradient, bitmapShader, PorterDuff.Mode.MULTIPLY);
//         ComposeShader composeShader2 = new ComposeShader(composeShader, linearGradient, PorterDuff.Mode.MULTIPLY);
         //將組合的composeShader作爲畫筆paint繪圖所使用的shader
         mPaint.setShader(composeShader);
         //用composeShader繪製矩形區域
         canvas.drawRect(0, 0, mBitmap.getWidth(), mBitmap.getHeight(), mPaint);

在這裏插入圖片描述

放大鏡效果

/**
 * 放大鏡效果
 */

public class ZoomImageView extends View {

    //放大倍數
    private static final int FACTOR = 2;
    //放大鏡的半徑
    private static final int RADIUS  = 100;
    // 原圖
    private Bitmap mBitmap;
    // 放大後的圖
    private Bitmap mBitmapScale;
    // 製作的圓形的圖片(放大的局部),蓋在Canvas上面
    private ShapeDrawable mShapeDrawable;

    private Matrix mMatrix;

    public ZoomImageView(Context context) {
        super(context);

        mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.xyjy3);
        mBitmapScale = mBitmap;
        //放大後的整個圖片
        mBitmapScale = Bitmap.createScaledBitmap(mBitmapScale,mBitmapScale.getWidth() * FACTOR,
                mBitmapScale.getHeight() * FACTOR,true);
        BitmapShader bitmapShader = new BitmapShader(mBitmapScale, Shader.TileMode.CLAMP,
                Shader.TileMode.CLAMP);

        mShapeDrawable = new ShapeDrawable(new OvalShape());
        mShapeDrawable.getPaint().setShader(bitmapShader);
        // 切出矩形區域,用來畫圓(內切圓)
        mShapeDrawable.setBounds(0,0,RADIUS * 2,RADIUS * 2);

        mMatrix = new Matrix();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        // 1、畫原圖
        canvas.drawBitmap(mBitmap, 0 , 0 , null);

        // 2、畫放大鏡的圖
        mShapeDrawable.draw(canvas);
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int x = (int) event.getX();
        int y = (int) event.getY();

        // 將放大的圖片往相反的方向挪動
        mMatrix.setTranslate(RADIUS - x * FACTOR, RADIUS - y *FACTOR);
        mShapeDrawable.getPaint().getShader().setLocalMatrix(mMatrix);
        // 切出手勢區域點位置的圓
        mShapeDrawable.setBounds(x-RADIUS,y - RADIUS, x + RADIUS, y + RADIUS);
        invalidate();
        return true;
    }
}

在這裏插入圖片描述

2、濾鏡

在這裏插入圖片描述

BlurMaskFilter模糊遮罩濾鏡

參考:
https://blog.csdn.net/lyz_zyx/article/details/78783956

        //關閉單個View的硬件加速功
        setLayerType(View.LAYER_TYPE_SOFTWARE,null);
        RectF rectF = new RectF(200,100,bitmap.getWidth()+200,bitmap.getHeight());
         /**
         * @param radius 陰影的半徑
         * @param style  NORMAL -- 整個圖像都被模糊掉
         *               SOLID -- 圖像邊界外產生一層與Paint顏色一致陰影效果,不影響圖像的本身
         *               OUTER -- 圖像邊界外產生一層陰影,並且將圖像變成透明效果
         *               INNER -- 在圖像內部邊沿產生模糊效果
         */
        paint.setMaskFilter(new BlurMaskFilter(50, BlurMaskFilter.Blur.SOLID));
        canvas.drawRect(rectF,paint);

4種效果如下:
在這裏插入圖片描述

EmbossMaskFilter浮雕遮罩濾鏡

        /**
         * @param direction  指定光源的位置,長度爲xxx的數組標量[x,y,z]
         * @param ambient    環境光的因子 (0~1),越接近0,環境光越暗
         * @param specular   鏡面反射係數 越接近0,鏡面反射越強
         * @param blurRadius 模糊半徑 值越大,模糊效果越明顯
         */
        paint.setMaskFilter(new EmbossMaskFilter(new float[]{1,1,1},0.5f,1,5    ));
        paint.setTextSize(200);
        canvas.drawText("Hello World", 50, 200, paint);

在這裏插入圖片描述

顏色矩陣

平移運算—加法

        // 平移運算---加法
        ColorMatrix colorMartrix = new ColorMatrix(new float[]{
                1, 0,0,0,0,
                0,1,0,0,100,
                0,0,1,0,0,
                0,0,0,1,0,
        });
        RectF rectF2 = new RectF(200,100 + bitmap.getHeight(),bitmap.getWidth()+200,bitmap.getHeight() * 2);
        paint.setColorFilter(new ColorMatrixColorFilter(colorMartrix));
        canvas.drawBitmap(bitmap,null, rectF2,paint);

在這裏插入圖片描述

反相效果 – 底片效果

        // 反相效果 -- 底片效果
       ColorMatrix colorMartrix = new ColorMatrix(new float[]{
                -1, 0,0,0,255,
                0,-1,0,0,255,
                0,0,-1,0,255,
                0,0,0,1,0,
        });

在這裏插入圖片描述

縮放運算—乘法 – 顏色增強

        // 縮放運算---乘法 -- 顏色增強
        ColorMatrix colorMartrix = new ColorMatrix(new float[]{
                1.5f, 0,0,0,0,
                0,1.5f,0,0,0,
                0,0,1.5f,0,0,
                0,0,0,1.5f,0,
        });

在這裏插入圖片描述

黑白照片

         /** 黑白照片
          *是將我們的三通道變爲單通道的灰度模式
          *去色原理:只要把R G B 三通道的色彩信息設置成一樣,那麼圖像就會變成灰色,
          *同時爲了保證圖像亮度不變,同一個通道里的R+G+B =1
          */
        ColorMatrix colorMartrix = new ColorMatrix(new float[]{
                0.213f, 0.715f,0.072f,0,0,
                0.213f, 0.715f,0.072f,0,0,
                0.213f, 0.715f,0.072f,0,0,
                0,0,0,1,0,
        });

在這裏插入圖片描述

髮色效果

        // 髮色效果---(比如紅色和綠色交換)
        ColorMatrix colorMartrix = new ColorMatrix(new float[]{
                1,0,0,0,0,
                0, 0,1,0,0,
                0,1,0,0,0,
                0,0,0,0.5F,0,
        });

在這裏插入圖片描述

復古效果

        // 復古效果
        ColorMatrix colorMartrix = new ColorMatrix(new float[]{
                1/2f,1/2f,1/2f,0,0,
                1/3f, 1/3f,1/3f,0,0,
                1/4f,1/4f,1/4f,0,0,
                0,0,0,1,0,
        });

在這裏插入圖片描述

3、xfermode圖形組合

參考:
https://developer.android.google.cn/reference/android/graphics/PorterDuff.Mode?hl=en#ADD

在這裏插入圖片描述

public class MyView extends View {

    Paint mPaint;
    float mItemSize = 0;
    float mItemHorizontalOffset = 0;
    float mItemVerticalOffset = 0;
    float mCircleRadius = 0;
    float mRectSize = 0;
    int mCircleColor = 0xffffcc44;//黃色
    int mRectColor = 0xff66aaff;//藍色
    float mTextSize = 25;

    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 MyView(Context context) {
        super(context);
        init(null, 0);
    }

    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(attrs, 0);
    }

    public MyView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(attrs, defStyle);
    }

    private void init(AttributeSet attrs, int defStyle) {
        if(Build.VERSION.SDK_INT >= 11){
            setLayerType(LAYER_TYPE_SOFTWARE, null);
        }
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setTextSize(mTextSize);
        mPaint.setTextAlign(Paint.Align.CENTER);
        mPaint.setStrokeWidth(2);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //設置背景色
//        canvas.drawARGB(255, 139, 197, 186);
        int canvasWidth = canvas.getWidth();
        int canvasHeight = canvas.getHeight();

        for(int row = 0; row < 4; row++){
            for(int column = 0; column < 4; column++){
                canvas.save();
                int layer = canvas.saveLayer(0, 0, canvasWidth, canvasHeight, null, Canvas.ALL_SAVE_FLAG);
                mPaint.setXfermode(null);
                int index = row * 4 + column;
                float translateX = (mItemSize + mItemHorizontalOffset) * column;
                float translateY = (mItemSize + mItemVerticalOffset) * row;
                canvas.translate(translateX, translateY);
                //畫文字
                String text = sLabels[index];
                mPaint.setColor(Color.BLACK);
                float textXOffset = mItemSize / 2;
                float textYOffset = mTextSize + (mItemVerticalOffset - mTextSize) / 2;
                canvas.drawText(text, textXOffset, textYOffset, mPaint);
                canvas.translate(0, mItemVerticalOffset);
                //畫邊框
                mPaint.setStyle(Paint.Style.STROKE);
                mPaint.setColor(0xff000000);
                canvas.drawRect(2, 2, mItemSize - 2, mItemSize - 2, mPaint);
                mPaint.setStyle(Paint.Style.FILL);
                //畫圓
                mPaint.setColor(mCircleColor);
                float left = mCircleRadius + 3;
                float top = mCircleRadius + 3;
                canvas.drawCircle(left, top, mCircleRadius, mPaint);
                mPaint.setXfermode(sModes[index]);
                //畫矩形
                mPaint.setColor(mRectColor);
                float rectRight = mCircleRadius + mRectSize;
                float rectBottom = mCircleRadius + mRectSize;
                canvas.drawRect(left, top, rectRight, rectBottom, mPaint);
                mPaint.setXfermode(null);
                //canvas.restore();
                canvas.restoreToCount(layer);
            }
        }
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mItemSize = w / 4.5f;
        mItemHorizontalOffset = mItemSize / 6;
        mItemVerticalOffset = mItemSize * 0.426f;
        mCircleRadius = mItemSize / 3;
        mRectSize = mItemSize * 0.6f;
    }
}

在這裏插入圖片描述

刮刮卡

public class GuaGuaCardView_SRCOUT extends View {
    private Paint mBitPaint;
    private Bitmap BmpDST,BmpSRC,BmpText;
    private Path mPath;
    private float mPreX,mPreY;
    public GuaGuaCardView_SRCOUT(Context context, AttributeSet attrs) {
        super(context, attrs);

        setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        mBitPaint = new Paint();
        mBitPaint.setColor(Color.RED);
        mBitPaint.setStyle(Paint.Style.STROKE);
        mBitPaint.setStrokeWidth(45);

        BmpText = BitmapFactory.decodeResource(getResources(), R.drawable.guaguaka_text1,null);
        BmpSRC = BitmapFactory.decodeResource(getResources(),R.drawable.guaguaka,null);
        BmpDST = Bitmap.createBitmap(BmpSRC.getWidth(), BmpSRC.getHeight(), Bitmap.Config.ARGB_8888);
        mPath = new Path();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        canvas.drawBitmap(BmpText,0,0,mBitPaint);

        int layerId = canvas.saveLayer(0, 0, getWidth(), getHeight(), null, Canvas.ALL_SAVE_FLAG);

        //先把手指軌跡畫到目標Bitmap上
        Canvas c = new Canvas(BmpDST);
        c.drawPath(mPath,mBitPaint);

        //然後把目標圖像畫到畫布上
        canvas.drawBitmap(BmpDST,0,0,mBitPaint);

        //計算源圖像區域
        mBitPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));
        canvas.drawBitmap(BmpSRC,0,0,mBitPaint);

        mBitPaint.setXfermode(null);
        canvas.restoreToCount(layerId);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                mPath.moveTo(event.getX(),event.getY());
                mPreX = event.getX();
                mPreY = event.getY();
                return true;
            case MotionEvent.ACTION_MOVE:
                float endX = (mPreX+event.getX())/2;
                float endY = (mPreY+event.getY())/2;
                mPath.quadTo(mPreX,mPreY,endX,endY);
                mPreX = event.getX();
                mPreY =event.getY();
                break;
            case MotionEvent.ACTION_UP:
                break;
        }
        postInvalidate();
        return super.onTouchEvent(event);
    }
}

在這裏插入圖片描述

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