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

Android学习之图像的处理

2014-04-07 15:48 531 查看
Android系统提供了Matrix对象控制图形进行平移、旋转、缩放、倾斜等操作,对View组件也可以进行平移、旋转、缩放等。

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.drawable.BitmapDrawable;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.View;

public class MyView extends View
{
// 初始的图片资源
private Bitmap bitmap;
// Matrix 实例
private Matrix matrix = new Matrix();
// 设置倾斜度
private float sx = 0.0f;
// 位图宽和高
private int width, height;
// 缩放比例
private float scale = 1.0f;
// 判断缩放还是旋转
private boolean isScale = false;
public MyView(Context context , AttributeSet set)
{
super(context , set);
// 获得位图
bitmap = ((BitmapDrawable) context.getResources().getDrawable(R.drawable.a)).getBitmap();
// 获得位图宽
width = bitmap.getWidth();
// 获得位图高
height = bitmap.getHeight();
// 使当前视图获得焦点
this.setFocusable(true);
}
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
// 重置Matrix
matrix.reset();
if (!isScale)
{
// 旋转Matrix
matrix.setSkew(sx, 0);
}
else
{
// 缩放Matrix
matrix.setScale(scale, scale);
}
// 根据原始位图和Matrix创建新图片
Bitmap bitmap2 = Bitmap.createBitmap(bitmap, 0, 0, width, height,matrix, true);
// 绘制新位图
canvas.drawBitmap(bitmap2, matrix, null);
}
public boolean onKeyDown(int keyCode, KeyEvent event)
{
switch(keyCode)
{
// 按键A向左倾斜
case KeyEvent.KEYCODE_A:
isScale = false;
sx += 0.1;
postInvalidate();
break;
// 按键D向右倾斜
case KeyEvent.KEYCODE_D:
isScale = false;
sx -= 0.1;
postInvalidate();
break;
// 按键W放大
case KeyEvent.KEYCODE_W:
isScale = true;
if (scale < 2.0)
scale += 0.1;
postInvalidate();
break;
// 按键S缩小
case KeyEvent.KEYCODE_S:
isScale = true;
if (scale > 0.5)
scale -= 0.1;
postInvalidate();
break;
}
return super.onKeyDown(keyCode, event);
}
}


Canvas提供了一个drawBitmapMesh方法对Bitmap对象进行扭曲,其效果相当于PS里的滤镜,可以做出水波荡漾、红旗飘飘等扭曲效果。

drawBitmapMesh(Bitmap bitmap, int meshWidth,int meshHeight,float[] verts,int vertOffset,int[] colors,int colorOffset,Paint paint)

其中bitmap为需要扭曲的图源,meshWidth和meshHeight分别是横向和纵向上把bitmap分成多少格,

verts是一个长度为(meshWidth+1)*(meshHeight+1)

vertOffset控制verts数组从第几个数组元素开始才对bitmap进行扭曲

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;

public class WarpTest extends Activity
{
private Bitmap bitmap;
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(new MyView(this, R.drawable.jinta));
}
private class MyView extends View
{
// 定义两个常量,这两个常量指定该图片横向、纵向上都被划分为20格。
private final int WIDTH = 20;
private final int HEIGHT = 20;
// 记录该图片上包含441个顶点
private final int COUNT = (WIDTH + 1) * (HEIGHT + 1);
// 定义一个数组,保存Bitmap上的21 * 21个点的座标
private final float[] verts = new float[COUNT * 2];
// 定义一个数组,记录Bitmap上的21 * 21个点经过扭曲后的座标
// 对图片进行扭曲的关键就是修改该数组里元素的值。
private final float[] orig = new float[COUNT * 2];
public MyView(Context context, int drawableId)
{
super(context);
setFocusable(true);
// 根据指定资源加载图片
bitmap = BitmapFactory.decodeResource(getResources(), drawableId);
// 获取图片宽度、高度
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、verts数组。 初始化后,orig、verts
// 两个数组均匀地保存了21 * 21个点的x,y座标
orig[index * 2 + 0] = verts[index * 2 + 0] = fx;
orig[index * 2 + 1] = verts[index * 2 + 1] = fy;
index += 1;
}
}
// 设置背景色
setBackgroundColor(Color.WHITE);
}
protected void onDraw(Canvas canvas)
{
//对bitmap按verts数组进行扭曲
//从第一个点(由第5个参数0控制)开始扭曲
canvas.drawBitmapMesh(bitmap, WIDTH, HEIGHT, verts
, 0, null, 0,null);
}
// 工具方法,用于根据触摸事件的位置计算verts数组里各元素的值
private void warp(float cx, float cy)
{
for (int i = 0; i < COUNT * 2; i += 2)
{
float dx = cx - orig[i + 0];
float dy = cy - orig[i + 1];
float dd = dx * dx + dy * dy;
// 计算每个座标点与当前点(cx、cy)之间的距离
float d = (float) Math.sqrt(dd);
// 计算扭曲度,距离当前点(cx、cy)越远,扭曲度越小
float pull = 80000 / ((float) (dd * d));
// 对verts数组(保存bitmap上21 * 21个点经过扭曲后的座标)重新赋值
if (pull >= 1)
{
verts[i + 0] = cx;
verts[i + 1] = cy;
}
else
{
// 控制各顶点向触摸事件发生点偏移
verts[i + 0] = orig[i + 0] + dx * pull;
verts[i + 1] = orig[i + 1] + dy * pull;
}
}
// 通知View组件重绘
invalidate();
}
public boolean onTouchEvent(MotionEvent event)
{
// 调用warp方法根据触摸屏事件的座标点来扭曲verts数组
warp(event.getX(), event.getY());
return true;
}
}
}




使用Shader填充图形

Shader本身是一个抽象类,它提供了如下实现类

BitmapShader  使用位图平铺的渲染效果

LinearGradient 使用线性渐变来填充图形

RadialGradient 使用圆形渐变来填充图形

WseepGradient 使用角度渐变来填充图形

ComposeShader 使用组合渲染效果来填充图形









import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapShader;
import android.graphics.Color;
import android.graphics.ComposeShader;
import android.graphics.LinearGradient;
import android.graphics.PorterDuff;
import android.graphics.RadialGradient;
import android.graphics.Shader;
import android.graphics.SweepGradient;
import android.graphics.Shader.TileMode;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class ShaderTest extends Activity
implements OnClickListener
{
// 声明位图渲染对象
private Shader[] shaders = new Shader[5];
// 声明颜色数组
private int[] colors;
MyView myView;
// 自定义视图类
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
myView = (MyView)findViewById(R.id.my_view);
// 获得Bitmap实例
Bitmap bm = BitmapFactory.decodeResource(getResources()
, R.drawable.water);
// 设置渐变的颜色组,也就是按红、绿、蓝的方式渐变
colors = new int[] { Color.RED, Color.GREEN, Color.BLUE };
// 实例化BitmapShader,x坐标方向重复图形,y坐标方向镜像图形
shaders[0] = new BitmapShader(bm, TileMode.REPEAT,
TileMode.MIRROR);
// 实例化LinearGradient
shaders[1] = new LinearGradient(0, 0, 100, 100
, colors, null, TileMode.REPEAT);
// 实例化RadialGradient
shaders[2] = new RadialGradient(100, 100, 80, colors, null,
TileMode.REPEAT);
// 实例化SweepGradient
shaders[3] = new SweepGradient(160, 160, colors, null);
// 实例化ComposeShader
shaders[4] = new ComposeShader(shaders[1], shaders[2],
PorterDuff.Mode.DARKEN);
Button bn1 = (Button)findViewById(R.id.bn1);
Button bn2 = (Button)findViewById(R.id.bn2);
Button bn3 = (Button)findViewById(R.id.bn3);
Button bn4 = (Button)findViewById(R.id.bn4);
Button bn5 = (Button)findViewById(R.id.bn5);
bn1.setOnClickListener(this);
bn2.setOnClickListener(this);
bn3.setOnClickListener(this);
bn4.setOnClickListener(this);
bn5.setOnClickListener(this);
}
public void onClick(View source)
{
switch(source.getId())
{
case R.id.bn1:
myView.paint.setShader(shaders[0]);
break;
case R.id.bn2:
myView.paint.setShader(shaders[1]);
break;
case R.id.bn3:
myView.paint.setShader(shaders[2]);
break;
case R.id.bn4:
myView.paint.setShader(shaders[3]);
break;
case R.id.bn5:
myView.paint.setShader(shaders[4]);
break;
}
// 重绘界面
myView.invalidate();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: