Android 图片特效处理:drawBitmapMesh——图像扭曲+动感
2015-09-20 17:31
781 查看
最近学了好多绘图啊,图片处理啊之类的,想着学全面一点,就又研究了一下drawBitmapMesh,drawBitmapMesh也是在Canvas画布上进行使用的,它具有能够使图片扭曲变形的效果,感觉有点像哈哈镜,只不过哈哈镜是直接照出来的效果,而drawBitmapMesh是通过改变它所有点的坐标位置改变图像的。
下面来看下drawBitmapMesh实现的核心原理,看下面一张图片,我们将图片进行分割成了许许多多的小方块,形成网格,网格的交叉点就是我们所要获得的坐标点。通过将一张图片分割,获取坐标点,之后改变坐标点,图片就会呈现不同的形状了(这里可能不太好理解,如果有学过ps可能就比较好理解了)。
注:上面的图片我们分成了5*5的网格,这样就会产生6*6个坐标点
思路:
1、确定划分网格数
2、通过划分的网格数,确定变化数组float[] verts与原始数组float[] origs存放坐标点,使用一个数组存xy坐标(偶数位为X坐标,奇数位为Y坐标)。
3、通过for循环获得所有坐标点
4、监听手势,改变verts[]数组值,刷新界面
5、在canvas上绘制改变后的Bitmap
drawBitmapMesh核心原理
我们使用drawBitmapMesh是通过这行代码实现的canvas.drawBitmapMesh(bitmap, meshWidth, meshHeight, verts, vertOffset, colors, colorOffset, paint),可以看出来参数一是一张Bitmap图像,参数二、三分别是扭曲图像分割的点数(继续看你就会理解这里的意思),verts是变化的坐标点,vertOffset是偏移量。我们只能通过改变verts来改变图片的形状。
下面来看下drawBitmapMesh实现的核心原理,看下面一张图片,我们将图片进行分割成了许许多多的小方块,形成网格,网格的交叉点就是我们所要获得的坐标点。通过将一张图片分割,获取坐标点,之后改变坐标点,图片就会呈现不同的形状了(这里可能不太好理解,如果有学过ps可能就比较好理解了)。
注:上面的图片我们分成了5*5的网格,这样就会产生6*6个坐标点
实例:揉动的图片
思路:
1、确定划分网格数
2、通过划分的网格数,确定变化数组float[] verts与原始数组float[] origs存放坐标点,使用一个数组存xy坐标(偶数位为X坐标,奇数位为Y坐标)。
3、通过for循环获得所有坐标点
4、监听手势,改变verts[]数组值,刷新界面
5、在canvas上绘制改变后的Bitmap
[code]public class MydrawBitmapMesh extends View{ private Bitmap mbitmap; //将图片划分成200*200个小格 private static final int WIDTH=200; private static final int HEIGHT=200; //小格相交的总的点数 private int COUNT=(WIDTH+1)*(HEIGHT+1); private float[] verts=new float[COUNT*2]; private float[] origs=new float[COUNT*2]; private float k; public MydrawBitmapMesh(Context context) { super(context); init(); } public MydrawBitmapMesh(Context context, AttributeSet attrs) { super(context, attrs); init(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawBitmapMesh(mbitmap, WIDTH, HEIGHT, verts, 0, null, 0, null); canvas.drawBitmap(mbitmap, 100, 300, null); invalidate(); } @Override public boolean onTouchEvent(MotionEvent event) { touchwrap(event.getX(),event.getY()); return super.onTouchEvent(event); } private void touchwrap(float x, float y) { for(int i=0;i<COUNT*2;i+=2){ //x/y轴每个点坐标与当前x/y坐标的距离 float dx=x-origs[i+0]; float dy=y-origs[i+1]; float dd=dx*dx+dy*dy; //计算每个坐标点与当前点(x、y)之间的距离 float d=(float) Math.sqrt(dd); //计算扭曲度,距离当前点越远的点扭曲度越小 float pull=80000/((float)(dd*d)); //对verts重新赋值 if(pull>=1){ verts[i+0]=x; verts[i+1]=y; }else{ verts[i+0]=origs[i+0]+dx*pull; verts[i+1]=origs[i+1]+dy*pull; } } invalidate(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); } public void init(){ int index=0; mbitmap=BitmapFactory.decodeResource(getResources(),R.drawable.dog); float bitmapwidth=mbitmap.getWidth(); float bitmapheight=mbitmap.getHeight(); for(int i=0;i<HEIGHT+1;i++){ float fy=bitmapwidth/HEIGHT*i; for(int j=0;j<WIDTH+1;j++){ float fx=bitmapheight/WIDTH*j; //偶数位记录x坐标 奇数位记录Y坐标 origs[index*2+0]=verts[index*2+0]=fx; origs[index*2+1]=verts[index*2+1]=fy; index++; } } } }
实例:飘动的图片
思路与上面实例相同,只是verts的改变形式不同而已。[code]public class MydrawBitmapMesh extends View{ private Bitmap mbitmap; //将图片划分成200个小格 private static final int WIDTH=200; private static final int HEIGHT=200; //小格相交的总的点数 private int COUNT=(WIDTH+1)*(HEIGHT+1); private float[] verts=new float[COUNT*2]; private float[] origs=new float[COUNT*2]; private float k; public MydrawBitmapMesh(Context context) { super(context); init(); } public MydrawBitmapMesh(Context context, AttributeSet attrs) { super(context, attrs); init(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); for(int i=0;i<HEIGHT+1;i++){ for(int j=0;j<WIDTH+1;j++){ //x坐标不变 verts[(i*(WIDTH+1)+j)*2+0]+=0; //增加k值是为了让相位产生移动,从而可以飘动起来 float offset=(float)Math.sin((float)j/WIDTH*2*Math.PI+k); //y坐标改变,呈现正弦曲线 verts[(i*(WIDTH+1)+j)*2+1]=origs[(i*(WIDTH+1)+j)*2+1]+offset*50; } } k+=0.4f; canvas.drawBitmapMesh(mbitmap, WIDTH, HEIGHT, verts, 0, null, 0, null); canvas.drawBitmap(mbitmap, 100, 300, null); invalidate(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); } public void init(){ int index=0; mbitmap=BitmapFactory.decodeResource(getResources(),R.drawable.dog); float bitmapwidth=mbitmap.getWidth(); float bitmapheight=mbitmap.getHeight(); for(int i=0;i<HEIGHT+1;i++){ float fy=bitmapwidth/HEIGHT*i; for(int j=0;j<WIDTH+1;j++){ float fx=bitmapheight/WIDTH*j; //偶数位记录x坐标 奇数位记录Y坐标 origs[index*2+0]=verts[index*2+0]=fx; origs[index*2+1]=verts[index*2+1]=fy; index++; } } } }
相关文章推荐
- Android --固定底部
- Android系统进程优先级排序原因
- Android中正确获得View控件的宽和高——使用篇
- 使用ToggleButton
- Android 动画——Frame Animation与Tween Animation
- java4Android(21)类集框架->Collection and Iterator(hasNext方法和next方法)
- Android JNI环境要SQLite加密模块简介
- Android 寻找xutils上传图片失败办法的路径
- Android 裁剪图片为圆形图片
- Android Layout 优化
- android AsyncTask介绍
- Android中四种通知--notification
- 浅析Android-ViewPagerIndicator
- android studio 中的编码问题
- Android Studio常用快捷键
- Android之viewstub用法详解及实现延迟加载
- Android 动画之三 Property Animation—— 属性(Property)动画 【Animator提供基类】
- Fragment 深究
- Android服务之Service(其一)
- Android应用开发Camera系列(一):SurfaceView实现相机预览demo--新手上路