Android绘图(二)

来源:互联网 发布:北部战区山东知乎 编辑:程序博客网 时间:2024/05/16 15:24

(《群英传》)整理笔记:

图像处理之色彩特效处理:
(这一块不太懂,先记录下一个例子)

package com.android.utils;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.ColorMatrix;import android.graphics.ColorMatrixColorFilter;import android.graphics.Paint;/** * 设置图像矩阵的代码 * @author Administrator * */public class ImageHelper {    public static Bitmap handleImageEffect(Bitmap bm, float hue, float saturation, float lum) {        Bitmap bmp = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), Bitmap.Config.ARGB_8888);        Canvas canvas = new Canvas(bmp);        Paint paint = new Paint();        ColorMatrix hueMatrix = new ColorMatrix();        hueMatrix.setRotate(0, hue);        hueMatrix.setRotate(1, hue);        hueMatrix.setRotate(2, hue);        ColorMatrix saturationMatrix = new ColorMatrix();        saturationMatrix.setSaturation(saturation);        ColorMatrix lumMatrix = new ColorMatrix();        lumMatrix.setScale(lum, lum, lum, 1);        ColorMatrix imageMatrix = new ColorMatrix();        imageMatrix.postConcat(hueMatrix);        imageMatrix.postConcat(saturationMatrix);        imageMatrix.postConcat(lumMatrix);        paint.setColorFilter(new ColorMatrixColorFilter(imageMatrix));        canvas.drawBitmap(bm, 0, 0, paint);        return bmp;    }    public static 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;    }    public static Bitmap handleImagePixelsOldPhoto(Bitmap bm) {        Bitmap bmp = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), Bitmap.Config.ARGB_8888);        int width = bm.getWidth();        int height = bm.getHeight();        int color = 0;        int r, g, b, a, r1, g1, b1;        int[] oldPx = new int[width * height];        int[] newPx = new int[width * height];        bm.getPixels(oldPx, 0, bm.getWidth(), 0, 0, width, height);        for (int i = 0; i < width * height; i++) {            color = oldPx[i];            a = Color.alpha(color);            r = Color.red(color);            g = Color.green(color);            b = Color.blue(color);            r1 = (int) (0.393 * r + 0.769 * g + 0.189 * b);            g1 = (int) (0.349 * r + 0.686 * g + 0.168 * b);            b1 = (int) (0.272 * r + 0.534 * g + 0.131 * b);            if (r1 > 255) {                r1 = 255;            }            if (g1 > 255) {                g1 = 255;            }            if (b1 > 255) {                b1 = 255;            }            newPx[i] = Color.argb(a, r1, g1, b1);        }        bmp.setPixels(newPx, 0, width, 0, 0, width, height);        return bmp;    }    public static Bitmap handleImagePixelsRelief(Bitmap bm) {        Bitmap bmp = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), Bitmap.Config.ARGB_8888);        int width = bm.getWidth();        int height = bm.getHeight();        int color = 0, colorBefore = 0;        int a, r, g, b;        int r1, g1, b1;        int[] oldPx = new int[width * height];        int[] newPx = new int[width * height];        bm.getPixels(oldPx, 0, bm.getWidth(), 0, 0, width, height);        for (int i = 1; i < width * height; i++) {            colorBefore = oldPx[i - 1];            a = Color.alpha(colorBefore);            r = Color.red(colorBefore);            g = Color.green(colorBefore);            b = Color.blue(colorBefore);            color = oldPx[i];            r1 = Color.red(color);            g1 = Color.green(color);            b1 = Color.blue(color);            r = (r - r1 + 127);            g = (g - g1 + 127);            b = (b - b1 + 127);            if (r > 255) {                r = 255;            }            if (g > 255) {                g = 255;            }            if (b > 255) {                b = 255;            }            newPx[i] = Color.argb(a, r, g, b);        }        bmp.setPixels(newPx, 0, width, 0, 0, width, height);        return bmp;    }}
import com.android.utils.ImageHelper;import android.app.Activity;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.os.Bundle;import android.widget.ImageView;import android.widget.SeekBar;import android.widget.SeekBar.OnSeekBarChangeListener;/** * 色调、饱和度、亮度调整图片 * @author Administrator * */public class MyView3 extends Activity implements OnSeekBarChangeListener{     private static int MAX_VALUE = 255;        private static int MID_VALUE = 127;        private ImageView mImageView;        private SeekBar mSeekbarhue, mSeekbarSaturation, mSeekbarLum;        private float mHue, mStauration, mLum;        private Bitmap bitmap;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.my_view3);         bitmap = BitmapFactory.decodeResource(getResources(),                    R.drawable.qie);            mImageView = (ImageView) findViewById(R.id.imageview);            mSeekbarhue = (SeekBar) findViewById(R.id.seekbarHue);            mSeekbarSaturation = (SeekBar) findViewById(R.id.seekbarSaturation);            mSeekbarLum = (SeekBar) findViewById(R.id.seekbatLum);            mSeekbarhue.setOnSeekBarChangeListener(this);            mSeekbarSaturation.setOnSeekBarChangeListener(this);            mSeekbarLum.setOnSeekBarChangeListener(this);            mSeekbarhue.setMax(MAX_VALUE);            mSeekbarSaturation.setMax(MAX_VALUE);            mSeekbarLum.setMax(MAX_VALUE);            mSeekbarhue.setProgress(MID_VALUE);            mSeekbarSaturation.setProgress(MID_VALUE);            mSeekbarLum.setProgress(MID_VALUE);            mImageView.setImageBitmap(bitmap);    }    @Override    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {        switch (seekBar.getId()) {        case R.id.seekbarHue:            mHue = (progress - MID_VALUE) * 1.0F / MID_VALUE * 180;            break;        case R.id.seekbarSaturation:            mStauration = progress * 1.0F / MID_VALUE;            break;        case R.id.seekbatLum:            mLum = progress * 1.0F / MID_VALUE;            break;    }    mImageView.setImageBitmap(ImageHelper.handleImageEffect(            bitmap, mHue, mStauration, mLum));    }    @Override    public void onStartTrackingTouch(SeekBar seekBar) {    }    @Override    public void onStopTrackingTouch(SeekBar seekBar) {    }}

程序运行后可拖动三个属性条实时改变图像。

(留待以后学习)
【色彩矩阵、颜色矩阵ColorMatrix、常用图像颜色矩阵处理效果(灰度、图像反转、怀旧、去色、高饱和度)、像素点、常用像素点处理效果(底片、老照片、浮雕)】

图像处理之图形特效处理

图像的变形处理包含四类基本变换
Translate:平移变换
Rotate:旋转变换
Scale:缩放变换
Skew:错切变换

像素块分析
drawBitmapMeshh():将图像分成了一个个小块,然后通过改变每一个图像块来修改整个图像。基本上可以实现所有的图像特效。
canvas.drawBitmapMesh(bitmap, meshWidth, meshHeight, verts, vertOffset, colors, colorOffset, paint);
Bitmap:将要扭曲的图像;meshWidth:需要的横向网格数目;meshHeight:需要的纵向网格数目;verts:网格交叉点坐标数组;vertOffset:verts数组中开始跳过的(x, y)坐标对的数目。

示例:旗帜飞扬
核心思想:让图片中每个交织点的横坐标较之前坐标不断变化

import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.util.AttributeSet;import android.view.View;public class DrawBitmapMesh extends View {    private final int WIDTH = 200;    private final int HEIGHT = 200;    private int COUNT = (WIDTH + 1) * (HEIGHT + 1);    private float[] verts = new float[COUNT * 2];    private float[] orig = new float[COUNT * 2];    private Bitmap bitmap;    private float A;    private float k = 1;    public DrawBitmapMesh(Context context) {        super(context);        initView(context);    }    public DrawBitmapMesh(Context context, AttributeSet attrs) {        super(context, attrs);        initView(context);    }    public DrawBitmapMesh(Context context, AttributeSet attrs,                              int defStyleAttr) {        super(context, attrs, defStyleAttr);        initView(context);    }    private void initView(Context context) {        setFocusable(true);        // 第一步:获取交叉点的坐标,保存在orig数组中        bitmap = BitmapFactory.decodeResource(context.getResources(),                R.drawable.test);        float bitmapWidth = bitmap.getWidth();        float bitmapHeight = bitmap.getHeight();        // 通过循环遍历所有的交叉线,并按比例获取其坐标        int index = 0;        for (int y = 0; y <= HEIGHT; y++) {            float fy = bitmapHeight * y / HEIGHT;            for (int x = 0; x <= WIDTH; x++) {                float fx = bitmapWidth * x / WIDTH;                orig[index * 2 + 0] = verts[index * 2 + 0] = fx;                // 为了避免扭曲后被屏幕遮挡,人为将坐标+100为了让图像下移                orig[index * 2 + 1] = verts[index * 2 + 1] = fy + 100;                index += 1;            }        }        A = 50;    }    @Override    protected void onDraw(Canvas canvas) {        flagWave();        // 第四步:将处理后的图像绘制出来。每次绘制的时候通过改变相位来改变偏移量,从而造成动态的效果        k += 0.1F;        canvas.drawBitmapMesh(bitmap, WIDTH, HEIGHT,                verts, 0, null, 0, null);        invalidate();    }    // 第二步:改变交叉点的纵坐标的值,使用sin x 来改变交叉点纵坐标的值,保存到vert数组中    private void flagWave() {        for (int j = 0; j <= HEIGHT; j++) {            for (int i = 0; i <= WIDTH; i++) {                verts[(j * (WIDTH + 1) + i) * 2 + 0] += 0;                // 第三步:让图像动起来。利用函数的周期性                float offsetY =                        (float) Math.sin((float) i / WIDTH * 2 * Math.PI +                                Math.PI * k);                verts[(j * (WIDTH + 1) + i) * 2 + 1] =                        orig[(j * WIDTH + i) * 2 + 1] + offsetY * A;            }        }    }}

Android图像处理值画笔特效处理:

各种各样的画笔:记号笔、毛笔、蜡笔等。
1、PorterDuffXfermode:
PorterDuffXfermode设置的是两个图层交际区域的显示方式,dst是先画的图形,而src是后画的图形,通过控制遮罩层的图形,来控制下面被这招图形的显示效果,最常用的就是通过DST_IN、SRC_IN模式来实现将一个矩形图片变成圆角图片或者圆形图片的效果。

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.util.AttributeSet;import android.view.MotionEvent;import android.view.View;/** * 刮刮卡效果 *  * @author Administrator * */public class ProterDuffXfermode extends View {    private Bitmap mBgBitmap, mFgBitmap;    private Paint mPaint;    private Canvas mCanvas;    private Path mPath;    public ProterDuffXfermode(Context context, AttributeSet attrs) {        super(context, attrs);        init();    }    /**     * 第一步:做一些初始化工作。例如准备好图片,设置好Paint的一些属性     */    private void init() {        mPaint = new Paint();        // 将画笔的透明度置为0,这样才能显示出擦除的效果        mPaint.setAlpha(0);        // 第三步:使用DST_IN模式        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));        mPaint.setStyle(Paint.Style.STROKE);        // 让笔触和连接处更加圆滑一点Paint.Join.ROUND,Paint.Cap.ROUND        mPaint.setStrokeJoin(Paint.Join.ROUND);        mPaint.setStrokeWidth(60);        mPaint.setStrokeCap(Paint.Cap.ROUND);        mPath = new Path();        mBgBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.qie);        mFgBitmap = Bitmap.createBitmap(mBgBitmap.getWidth(), mBgBitmap.getHeight(), Bitmap.Config.ARGB_8888);        mCanvas = new Canvas(mFgBitmap);        mCanvas.drawColor(Color.GRAY);    }    // 第二步:获取用户手指滑动所产生的路径,使用Path保存用户手指划过的路径(贝塞尔曲线会有更好的显示效果)    @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);    }}

2、Shader
着色器、渲染器。用来实现一系列的渐变、渲染效果。
Android中的Shader包括以下几种:
(1)BitmapShader位图:产生的是一个图像,作用是通过Paint对画布进行指定Bitmap的填充。填充的模式:CLAMP拉伸;REPEAT重复;MIRROR镜像。
(2)LinearGradient线性;
(3)RadialGradient光束;
(4)SweepGradient梯度;
(5)ComposeShader混合。

// 用一张图片创建了一支具有图像填充功能的画笔,并使用这支画笔绘制了一个圆形。mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);        mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);        mPaint = new Paint();        mPaint.setShader(mBitmapShader);        canvas.drawCircle(250, 250, 200, mPaint);
// LinearGradient的使用:只需要指定渐变起始的颜色就可以了。        mPaint = new Paint();        mPaint.setShader(new LinearGradient(0, 0, 200, 200, Color.BLUE, Color.YELLOW, Shader.TileMode.REPEAT));        canvas.drawRect(0,0,800,800,mPaint);

但是这些渐变效果不会直接使用在程序里,通常情况下把这种渐变效果作为一个遮罩层来使用。

import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.LinearGradient;import android.graphics.Matrix;import android.graphics.Paint;import android.graphics.PorterDuff;import android.graphics.PorterDuffXfermode;import android.graphics.Shader;import android.util.AttributeSet;import android.view.View;public class DaoYing extends View {    private Bitmap mSrcBitmap, mRefBitmap;    private Paint mPaint;    private PorterDuffXfermode mXfermode;    public DaoYing(Context context) {        super(context);        initRes(context);    }    public DaoYing(Context context, AttributeSet attrs) {        super(context, attrs);        initRes(context);    }    public DaoYing(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        initRes(context);    }    /**     * 第一步:把原图复制一份并进行翻转     *      * @param context     */    private void initRes(Context context) {        mSrcBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.qie);        Matrix matrix = new Matrix();        // 使用matrix.setScale(1F, -1F)方法来实现图片的垂直翻转。水平翻转同理        matrix.setScale(1F, -1F);        mRefBitmap = Bitmap.createBitmap(mSrcBitmap, 0, 0, mSrcBitmap.getWidth(), mSrcBitmap.getHeight(), matrix, true);        mPaint = new Paint();        mPaint.setShader(new LinearGradient(0, mSrcBitmap.getHeight(), 0,                mSrcBitmap.getHeight() + mSrcBitmap.getHeight() / 4, 0XDD000000, 0X10000000, Shader.TileMode.CLAMP));        mXfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);    }    @Override    protected void onDraw(Canvas canvas) {        // 第二步:绘制两张图片即原图和倒影图        canvas.drawColor(Color.BLACK);        canvas.drawBitmap(mSrcBitmap, 0, 0, null);        canvas.drawBitmap(mRefBitmap, 0, mSrcBitmap.getHeight(), null);        mPaint.setXfermode(mXfermode);        // 第三步:绘制渐变效果矩形,并通过Mode.DST_IN模式绘制到倒影图上,形成一个具有过度效果的渐变层        canvas.drawRect(0, mSrcBitmap.getHeight(), mRefBitmap.getWidth(), mSrcBitmap.getHeight() * 2, mPaint);        mPaint.setXfermode(null);    }}
0 0
原创粉丝点击