Android学习之图像的处理

  1. 云栖社区>
  2. 博客>
  3. 正文

Android学习之图像的处理

jkxqj 2014-04-07 15:48:00 浏览637
展开阅读全文

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();
	}
}


网友评论

登录后评论
0/500
评论
jkxqj
+ 关注