您的位置:首页 > 移动开发 > Android开发

Android绘图(二)

2015-12-29 18:44 615 查看
(《群英传》)整理笔记:

图像处理之色彩特效处理:

(这一块不太懂,先记录下一个例子)

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);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: