Canvas提供了一个drawBitmapMesh(bitmap, meshWidth, meshHeight, verts, vertOffset, colors, colorOffset, paint)方法,该方法可以 对bitmap进行扭曲。用好这个方法,开发者可以在Android应用上开发出“水波震荡”、“风吹旗帜”等各种扭曲效果。

假想在一张图片上有很多网格,如下图。

 

在这张图上,每个网格上的像素与图片上的像素是一一对应的,也就是网格怎么扭动,图像就会怎么动。比如把网格扭成下面这样,图像就跟着扭曲了。

 

但是如何把网格扭成这样呢?在Android中很简单,设置网格顶点所在位置就可以了。但是顶点之间的线不是扭曲的么?不需要自己计算弯曲的方式吗?
不需要。

在DrawBitmapMesh中,只需要定义好这个顶点将要扭曲到哪个坐标点上,然后将顶点扭曲后的坐标告诉DrawBitmapMesh,便会自动计算出周边的线条扭曲形式,并根据结果扭曲图像。

总结上面的,需要做的就是三步:
1、根据图片,生成原始的、四四方方的网格
2、根据上面生成的网格,算出将要扭曲的网格
3、将网格传入drawBitmapMesh

而生成网格的方式,就是定义网格中,每个顶点的X,Y坐标。

回到方法定义上来。Canvas的drawBitmapMesh定义如下:

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

关键参数主要下面四个:
-bitmap: 就是将要扭曲的图像
-meshWidth: 需要的横向网格数目
-meshHeight: 需要的纵向网格数目
-verts: 网格顶点坐标数组。
-vertOffset: verts数组中开始跳过的(x,y)对的数目。

其中,verts是个一维数组,保存所有顶点坐标信息。偶数项保存x坐标,奇数项保存y坐标。比如有有meshWidth*meshHeight个网格,如果vertOffset为0,那么算上两端就有(meshWidth+1)*(meshHeight+1)个顶点,verts数组就应该至少长度为(meshWidth+1)*(meshHeight+1)。

看效果图:                     

代码:

  1 package com.example.mymeshtest;
  2
  3 import android.app.Activity;
  4 import android.content.Context;
  5 import android.graphics.Bitmap;
  6 import android.graphics.BitmapFactory;
  7 import android.graphics.Canvas;
  8 import android.graphics.Color;
  9 import android.os.Bundle;
 10 import android.view.MotionEvent;
 11 import android.view.View;
 12
 13 public class MyMeshTest extends Activity
 14 {
 15
 16     private Bitmap bitmap;
 17
 18
 19     @Override
 20     protected void onCreate(Bundle savedInstanceState)
 21     {
 22         super.onCreate(savedInstanceState);
 23         setContentView(new MyView(this,R.drawable.test));
 24     }
 25
 26     private class MyView extends View
 27     {
 28
 29         //定义两个常量,这两个常量指定该图片横向、纵向上被划分为40格
 30         private final int WIDTH = 40;
 31         private final int HEIGHT = 40;
 32
 33         //记录该图片上包含41*41个顶点
 34         private final int COUNT = (WIDTH +1) * (HEIGHT + 1);
 35
 36         //定义一个数组,保存Bitmap上的41*41个点得坐标
 37         private final float[] orig = new float[COUNT*2];
 38
 39         //定义一个数组,记录Bitmap上的41*41个点经过扭曲后的坐标
 40         //对 图片进行扭曲的关键就是修改该数组里的元素的值
 41         private final float[] verts = new float[COUNT*2];
 42
 43         public MyView(Context context,int drawable_id)
 44         {
 45             super(context);
 46             // TODO Auto-generated constructor stub
 47             setFocusable(true);
 48
 49             //根据指定资源加载图片
 50             bitmap = BitmapFactory.decodeResource(getResources(), drawable_id);
 51
 52             //获取图片的宽和高
 53             float bitmapWidth = bitmap.getWidth();
 54             float bitmapHeight = bitmap.getHeight();
 55             int index = 0;
 56             for (int y = 0; y<= HEIGHT; y++)
 57             {
 58                 float fy = bitmapHeight*y/HEIGHT;
 59                 for (int x = 0; x<= WIDTH; x++)
 60                 {
 61                     float fx = bitmapWidth*x/WIDTH;
 62                     /*初始化orig、verts数组。
 63                     初始化后,orig、verts两个数组均匀地保存了
 64                     41*41个点得x、y坐标*/
 65                     orig[index*2+0] = verts[index*2+0] = fx;
 66                     orig[index*2+1] = verts[index*2+1] = fy;
 67                     index += 1;
 68                 }
 69             }
 70
 71             //设置背景颜色
 72             setBackgroundColor(Color.WHITE);
 73         }
 74
 75         @Override
 76         protected void onDraw(Canvas canvas)
 77         {
 78             /*对bitmap按verts数组进行扭曲
 79             从第一个点(由第5个参数0开始)开始扭曲*/
 80             canvas.drawBitmapMesh(bitmap, WIDTH, HEIGHT, verts, 0, null, 0, null);
 81         }
 82
 83         //工具方法,用于根据触摸事件的位置计算verts数组里各元素的值
 84         private void warp(float cx, float cy)
 85         {
 86             for (int i = 0; i< COUNT * 2; i += 2)
 87             {
 88                 float dx = cx - orig[i +0];
 89                 float dy = cy - orig[i +1];
 90                 float dd = dx*dx + dy*dy;
 91                 //计算每个坐标点与当前点(cx、cy)之间的距离
 92                 float d = (float)Math.sqrt(dd);
 93
 94                 //计算扭曲度,距离当前点(cx,cy)越远,扭曲度越小
 95                 float pull = 80000 / ((float) (dd *d));
 96
 97                 //对verts数组(保存bitmap上41*41个点经过扭曲后的坐标)重新辅助
 98                 if(pull >= 1)
 99                 {
100                     verts[i + 0] = cx;
101                     verts[i + 1] = cy;
102                 }
103                 else
104                 {
105                     //控制各定点向触摸事件发生点偏移
106                     verts[i +0] = orig [i +0] +dx*pull;
107                     verts[i +1] = orig [i +1] +dy*pull;
108                 }
109             }
110             //通知View组建重绘
111             invalidate();
112         }
113         @Override
114         public boolean onTouchEvent(MotionEvent event)
115         {
116             //调用warp方法根据触摸屏事件的坐标点来扭曲verts数组
117             warp(event.getX(),event.getY());
118             return true;
119         }
120
121     }
122
123 }

转载于:https://www.cnblogs.com/merryjd/archive/2013/01/23/2873632.html

Android扭曲图像(水面落叶壁纸初步实现)相关推荐

  1. Android水面落叶动态壁纸源码及分析 附下载地址

    Android自带的水面落叶动态壁纸效果,尝试使用plasma等jni来实现,最终效果仍然不如renderScript实现的好,因为renderScript相关学习资料比较少,不再重头编写rs脚本来实 ...

  2. android设置主题背景为壁纸_如何为每个Android主屏幕添加不同的壁纸 | MOS86

    Android设备有很多不同的主屏幕.问题是,当您选择一个图像作为背景墙纸,它横跨所有3有时候没关系大多数时候,您想要看到的图像的一部分就在屏幕之间的裂缝上. 为了解决这个问题,您可以使用Multip ...

  3. 关于android基础教程一书的初步解读后发现的一些问题

    我是一个比较固执的人..在进行android基础教程一书的初步学习之后,说实话,这本书虽然说为了照顾有需要的童鞋,提供了所有的源代码,就连我也在亲自打了好久的代码之后最后决定放弃,也偷偷懒,进行简单无 ...

  4. Android六边形图像

    Android六边形图像 Glide.with(mContext).asBitmap().load(ranking.get(2).getGame_image().replace(":\\/& ...

  5. ITK:使用Deformation Field扭曲图像

    ITK:使用Deformation Field扭曲图像 内容提要 输出结果 C++实现代码 内容提要 使用WarpImageFilter和变形字段重新采样图像. 输出结果 C++实现代码 #inclu ...

  6. android怎样添加图片锐化功能,如何在android处理图片(图像二值化锐化转换格式).doc...

    如何在android处理图片(图像二值化锐化转换格式) 链接:如何在android处理图片( 图像二值化.锐化.转换格式) /thread-36559-1-1.html package net.wea ...

  7. Android第三方开源水面波浪波形view:WaveView(电量、能量、容量指示)

     Android第三方开源水面波浪波形view:WaveView(电量.能量.容量指示) Github上有一个比较有趣的Android第三方开源波形view:WaveView,这种WaveView ...

  8. android p蓝色壁纸,iPhone和Android的最佳蓝色系壁纸分享

    原标题:iPhone和Android的最佳蓝色系壁纸分享 去年iPhone 12系列的主打颜色是蓝色.如果你有蓝色版iPhone 12,想要定制你的智能手机的主屏幕,那么今天分享的蓝色系美观的壁纸,必 ...

  9. android 7原生动态壁纸,手机里都是定制OS?谷歌Android 7.0原生系统壁纸邀你来尝鲜!...

    原标题:手机里都是定制OS?谷歌Android 7.0原生系统壁纸邀你来尝鲜! 安卓系统的碎片化一直是被人们所诟病,苹果手机IOS系统升级的速度和占比一直都非常高,而安卓手机却相比都非常差,三星,华为 ...

最新文章

  1. NetworkStream.write只能使用一次,后面再使用无效
  2. nodejs web开发入门: Simple-TODO Nodejs 实现版
  3. tamper绕WAF小结
  4. 板材开料最优算法_板材套料软件AutoNest与Tekla Structures协同工作实现设计到加工自动化...
  5. 《Python快速入门》6大数据类型详解
  6. RHCE之DHCP配置详解
  7. “else if”是否比“switch()case”更快? [重复]
  8. Java调用C/C++的过程
  9. Unity Editor编辑器实用扩展
  10. “创业吃过饼,国企养过老,android开发零基础
  11. Unity关于程序集(Assembly )的那些事
  12. 美图秀秀自动化测试工程师笔试面试
  13. 阿里云-云存储OSS
  14. [知识普及贴]中国人不可不知道的知识(怕以后找不到了~~) [经典,值得收藏]
  15. Js 怎么遍历json对象所有key及根据动态key获取值
  16. 使用阿里云服务器的经历~
  17. 基于遗传算法的无人机监视覆盖航路规划算法研究
  18. 评价最高影片JAVAlibrary_三大“百亿影帝”联袂主演,一部比肩《战狼》的王炸影片即将诞生...
  19. UNI-APP开发工具与环境
  20. Python学习:正则表达式匹配手机号,邮箱

热门文章

  1. php+ajax上传文件
  2. 常用git命令总结大全
  3. Unity 优化贴图模型
  4. (HTTP代理与socket5)客户端访问,服务器处理步骤
  5. composite java_组合模式(Composite)——Java
  6. YOLOv5剪枝✂️| 模型剪枝实战篇
  7. JVM 之 JDK安装与配置
  8. 大文件上传组件webupload插件
  9. JSP设置Excel表格换行_Excel单元格内换行简单操作!新手易懂超实用!
  10. linux下磁盘测速工具