学习笔记《Android群英传》——第六章 Android绘图机制与处理技巧

学习笔记《Android群英传》——第六章 Android绘图机制与处理技巧

章节目录


知识点

1.dp、sp转换为px的工具类


import android.content.Context;

/**
 * dp、sp转换为px的工具类
 */

public class DisplayUtil {

    /**
     * 将px值转换为dip或dp值,保证尺寸大小不变
     * @param context
     * @param pxValue
     * @return
     */
    public  static int px2dip(Context context,float pxValue){
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int)(pxValue/scale + 0.5f);
    }

    /**
     * 将dip或dp值转换为px值,保证尺寸大小不变
     * @param context
     * @param dipValue
     * @return
     */
    public static int dip2px(Context context,float dipValue){
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int)(dipValue * scale + 0.5f);
    }

    /**
     * 将px值转换为sp值,保证文字大小不变
     * @param context
     * @param pxValue
     * @return
     */
    public static int px2sp(Context context,float pxValue){
        final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
        return (int)(pxValue/fontScale + 0.5f);
    }

    /**
     * 将sp值转换为px值,保证文字大小不变
     * @param context
     * @param spValue
     * @return
     */
    public static int sp2px(Context context,float spValue){
        final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
        return (int)(spValue * fontScale + 0.5f);
    }
}

2.SurfaceView模板

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

/**
 * SurfaceView模板;
 * SurfaceView与View的区别:
 * 1.View主要适用于主动更新的情况下,而SurfaceView主要适用于被动更新,例如频繁地刷新;
 * 2.View在主线程中对画面进行刷新,而SurfaceView通常通过一个子线程来进行页面的刷新;
 * View在绘图时,没有使用双缓冲机制,而SurfaceView在底层实现机制中就已经实现了双缓冲机制。
 */

public class SurfaceViewTemplate extends SurfaceView
             implements SurfaceHolder.Callback,Runnable{

    //SurfaceHolder
    private SurfaceHolder mSurfaceHolder;
    //用于绘图的Canvas
    private Canvas mCanvas;
    //子线程标志位
    private boolean mIsDrawing;

//    private Path mPath;
//    private Paint mPaint;
//    private int x = 0;
//    private int y = 0;

    public SurfaceViewTemplate(Context context) {
        super(context);
        initView();
    }

    public SurfaceViewTemplate(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

    public SurfaceViewTemplate(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }

    private void initView(){
        mSurfaceHolder = getHolder();
        mSurfaceHolder.addCallback(this);
        setFocusable(true);
        setFocusableInTouchMode(true);
        this.setKeepScreenOn(true);
//        mSurfaceHolder.setFormat(PixelFormat.OPAQUE);

//        mPath = new Path();
//        mPaint = new Paint();
//        mPaint.setColor(Color.BLACK);
    }

    @Override
    public void surfaceCreated(SurfaceHolder surfaceHolder) {
        mIsDrawing = true;
        new Thread(this).start();
    }

    @Override
    public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
        mIsDrawing = false;
    }

    @Override
    public void run() {
        while(mIsDrawing){
            draw();
//            x += 1;
//            y = (int)(100 * Math.sin(x * 2 * Math.PI /180) + 400);
//            mPath.lineTo(x,y);
        }
    }

    private void draw(){
        try {
            mCanvas = mSurfaceHolder.lockCanvas();
            //绘制。。。
//            mCanvas.drawColor(Color.WHITE);
//            mCanvas.drawPath(mPath,mPaint);
        }catch (Exception e){
        }finally {
            if(mCanvas != null){
                mSurfaceHolder.unlockCanvasAndPost(mCanvas);
            }
        }
    }
}

3.刮刮卡效果——画笔特效处理


import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

/**
 * 刮刮卡效果
 */

public class XfermodeView extends View{

    private Bitmap mBgBitmap,mFgBitmap;
    private Paint mPaint;
    private Canvas mCanvas;
    private Path mPath;

    public XfermodeView(Context context) {
        super(context);
        init();
    }

    public XfermodeView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public XfermodeView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init(){
        mPaint = new Paint();
        //在使用PorterDuffXfermode进行图层混合时,并不是简单地只进行图层的计算,
        //同时也会去计算透明通道的值
        mPaint.setAlpha(0);
        //使用DST_IN模式将路径绘制到前面覆盖的图层上面
        mPaint.setXfermode(
                new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeWidth(50);
        mPaint.setStrokeCap(Paint.Cap.ROUND);

        mPath = new Path();
        mBgBitmap = BitmapFactory.decodeResource(getResources(),
                R.drawable.image);
        mFgBitmap = Bitmap.createBitmap(mBgBitmap.getWidth(),
                mBgBitmap.getHeight(), Bitmap.Config.ARGB_8888);
        mCanvas = new Canvas(mFgBitmap);
        mCanvas.drawColor(Color.GRAY);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                mPath.reset();
                mPath.moveTo(event.getX(),event.getY());
                break;
            case MotionEvent.ACTION_MOVE:
                mPath.lineTo(event.getX(),event.getY());
                break;
        }
        mCanvas.drawPath(mPath,mPaint);
        invalidate();
        return true;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawBitmap(mBgBitmap,0,0,null);
        canvas.drawBitmap(mFgBitmap,0,0,null);
    }
}

4.颜色矩阵(ColorMatrix)的使用和像素点处理效果

1.xml布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ImageView
        android:id="@+id/image_view"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="2"/>
    <GridLayout
        android:id="@+id/grid_layout"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="3"
        android:columnCount="5"
        android:rowCount="4"/>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <Button
            android:id="@+id/btn_change"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="改变"/>
        <Button
            android:id="@+id/btn_reset"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="重置"/>
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <Button
            android:id="@+id/btn_gray"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="灰度"/>
        <Button
            android:id="@+id/btn_reverse"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="反转"/>
        <Button
            android:id="@+id/btn_nostalgia"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="怀旧"/>
        <Button
            android:id="@+id/btn_discoloration"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="去色"/>
        <Button
            android:id="@+id/btn_high_saturation"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="高饱和度"/>
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <Button
            android:id="@+id/btn_negative"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="底片"/>
        <Button
            android:id="@+id/btn_old_image"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="老照片"/>
    </LinearLayout>
</LinearLayout>

2.activity


/**
 * 颜色矩阵(ColorMatrix)的使用、像素点处理效果
 */

public class ActColorMatrix extends AppCompatActivity {

    @BindView(R.id.image_view)
    ImageView imageView;
    @BindView(R.id.grid_layout)
    GridLayout gridLayout;
    @BindView(R.id.btn_change)
    Button btnChange;
    @BindView(R.id.btn_reset)
    Button btnReset;
    @BindView(R.id.btn_gray)
    Button btnGray;
    @BindView(R.id.btn_reverse)
    Button btnReverse;
    @BindView(R.id.btn_nostalgia)
    Button btnNostalgia;
    @BindView(R.id.btn_discoloration)
    Button btnDiscoloration;
    @BindView(R.id.btn_high_saturation)
    Button btnHighSaturation;
    @BindView(R.id.btn_negative)
    Button btnNegative;
    @BindView(R.id.btn_old_image)
    Button btnOldImage;

    private Bitmap bitmap;
    private int mEtWidth;
    private int mEtHeight;
    private EditText[] editTexts = new EditText[20];
    private float[] colorMatrices = new float[20];
    /*第一行将会影响红色,第二行影响绿色,第三行影响蓝色,最后一行操作的是Alpha值;
      默认的ColorMatrix如下面所示,它是不会改变图像的:
      1,0,0,0,0,
      0,1,0,0,0,
      0,0,1,0,0,
      0,0,0,1,0*/

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_act_color_matrix);
        ButterKnife.bind(this);

        bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image);
        imageView.setImageBitmap(bitmap);

        //无法在onCreate()方法中获得视图的宽高值,
        //所以通过View的post方法,在视图创建完毕后获得其宽高值
        gridLayout.post(new Runnable() {
            @Override
            public void run() {
                //获取宽高信息
                mEtWidth = gridLayout.getWidth() / 5;
                mEtHeight = gridLayout.getHeight() / 4;
                addEts();
                initMatrix();
            }
        });
    }

    //添加EditText
    private void addEts() {
        for (int i = 0; i < 20; i++) {
            EditText editText = new EditText(ActColorMatrix.this);
            editTexts[i] = editText;
            gridLayout.addView(editText, mEtWidth, mEtHeight);
        }
    }

    //初始化颜色矩阵为初始状态
    private void initMatrix() {
        for (int i = 0; i < 20; i++) {
            if (i % 6 == 0) {
                editTexts[i].setText(String.valueOf(1));
            } else {
                editTexts[i].setText(String.valueOf(0));
            }
        }
    }

    //获取矩阵值
    private void getMatrix() {
        for (int i = 0; i < 20; i++) {
            colorMatrices[i] = Float.valueOf(editTexts[i].getText().toString());
        }
    }

    //将矩阵值设置到图像
    private void setImageMatrix() {
        Bitmap bmp = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(),
                Bitmap.Config.ARGB_8888);
        ColorMatrix colorMatrix = new ColorMatrix();
        colorMatrix.set(colorMatrices);
        Canvas canvas = new Canvas(bmp);
        Paint paint = new Paint();
        paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
        canvas.drawBitmap(bitmap, 0, 0, paint);
        imageView.setImageBitmap(bmp);
    }

    //特效(ColorMatrices)
    private void specialEffect(int type) {
        switch (type) {
            case 1://灰度
                colorMatrices = new float[]{0.33f, 0.59f, 0.11f, 0, 0,
                        0.33f, 0.59f, 0.11f, 0, 0,
                        0.33f, 0.59f, 0.11f, 0, 0,
                        0, 0, 0, 1, 0};
                break;
            case 2://反转
                colorMatrices = new float[]{-1, 0, 0, 1, 1,
                        0, -1, 0, 1, 1,
                        0, 0, -1, 1, 1,
                        0, 0, 0, 1, 0};
                break;
            case 3://怀旧
                colorMatrices = new float[]{0.393f, 0.769f, 0.189f, 0, 0,
                        0.349f, 0.686f, 0.168f, 0, 0,
                        0.272f, 0.534f, 0.131f, 0, 0,
                        0, 0, 0, 1, 0};
                break;
            case 4://去色
                colorMatrices = new float[]{1.5f, 1.5f, 1.5f, 0, -1,
                        1.5f, 1.5f, 1.5f, 0, -1,
                        1.5f, 1.5f, 1.5f, 0, -1,
                        0, 0, 0, 1, 0};
                break;
            case 5://高饱和度
                colorMatrices = new float[]{1.438f, -0.122f, -0.016f, 0, -0.03f,
                        -0.062f, 1.378f, -0.016f, 0, 0.05f,
                        -0.062f, -0.122f, 1.483f, 0, -0.02f,
                        0, 0, 0, 1, 0};
                break;
        }
        for (int i = 0; i < 20; i++) {
            editTexts[i].setText(String.valueOf(colorMatrices[i]));
        }
    }

    //底片(像素点)
    private Bitmap handleImageNegative(Bitmap bm) {
        int width = bm.getWidth();
        int height = bm.getHeight();
        int color;
        int r, g, b, a;

        Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);

        int[] oldPx = new int[width * height];
        int[] newPx = new int[width * height];
        bm.getPixels(oldPx, 0, width, 0, 0, width, height);
        for (int i = 0; i < width * height; i++) {
            color = oldPx[i];
            r = Color.red(color);
            g = Color.green(color);
            b = Color.blue(color);
            a = Color.alpha(color);

            r = 255 - r;
            g = 255 - g;
            b = 255 - b;

            if (r > 255) {
                r = 255;
            } else if (r < 0) {
                r = 0;
            }
            if (g > 255) {
                g = 255;
            } else if (g < 0) {
                g = 0;
            }
            if (b > 255) {
                b = 255;
            } else if (b < 0) {
                b = 0;
            }
            newPx[i] = Color.argb(a, r, g, b);
        }
        bmp.setPixels(newPx, 0, width, 0, 0, width, height);
        return bmp;
    }

    //老照片(像素点)
    private Bitmap handleImageOld(Bitmap bm) {
        int width = bm.getWidth();
        int height = bm.getHeight();
        int color;
        int r, g, b, a;

        Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);

        int[] oldPx = new int[width * height];
        int[] newPx = new int[width * height];
        bm.getPixels(oldPx, 0, width, 0, 0, width, height);
        for (int i = 0; i < width * height; i++) {
            color = oldPx[i];
            r = Color.red(color);
            g = Color.green(color);
            b = Color.blue(color);
            a = Color.alpha(color);

            r = (int) (0.393 * r + 0.769 * g + 0.189 * b);
            g = (int) (0.349 * r + 0.686 * g + 0.168 * b);
            b = (int) (0.272 * r + 0.534 * g + 0.131 * b);

            if (r > 255) {
                r = 255;
            } else if (r < 0) {
                r = 0;
            }
            if (g > 255) {
                g = 255;
            } else if (g < 0) {
                g = 0;
            }
            if (b > 255) {
                b = 255;
            } else if (b < 0) {
                b = 0;
            }
            newPx[i] = Color.argb(a, r, g, b);
        }
        bmp.setPixels(newPx, 0, width, 0, 0, width, height);
        return bmp;
    }

    @OnClick({R.id.btn_change, R.id.btn_reset,
            R.id.btn_gray, R.id.btn_reverse, R.id.btn_nostalgia,
            R.id.btn_discoloration, R.id.btn_high_saturation,
            R.id.btn_negative, R.id.btn_old_image})
    public void onViewClicked(View view) {
        switch (view.getId()) {
            case R.id.btn_change://作用矩阵效果
                getMatrix();
                setImageMatrix();
                break;
            case R.id.btn_reset://重置矩阵效果
                initMatrix();
                getMatrix();
                setImageMatrix();
                break;
            case R.id.btn_gray://灰度
                specialEffect(1);
                setImageMatrix();
                break;
            case R.id.btn_reverse://反转
                specialEffect(2);
                setImageMatrix();
                break;
            case R.id.btn_nostalgia://怀旧
                specialEffect(3);
                setImageMatrix();
                break;
            case R.id.btn_discoloration://去色
                specialEffect(4);
                setImageMatrix();
                break;
            case R.id.btn_high_saturation://高饱和度
                specialEffect(5);
                setImageMatrix();
                break;
            case R.id.btn_negative://底片
                imageView.setImageBitmap(handleImageNegative(bitmap));
                break;
            case R.id.btn_old_image://老照片
                imageView.setImageBitmap(handleImageOld(bitmap));
                break;
        }
    }
}

猜你喜欢

转载自blog.csdn.net/an_nal/article/details/79523448