zoukankan      html  css  js  c++  java
  • Android扭曲图像(水面落叶壁纸初步实现)

    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 }
  • 相关阅读:
    windows 10下ELK环境快速搭建实践
    Windows 10下搭建以太坊私有链环境
    线程状态转换图
    JAVA中IO技术:BIO、NIO、AIO
    MySQL MDL锁的阻塞问题 & online ddl的插队现象【转发】
    MySQL InnoDB MVCC 能否完全解决幻读?
    Linux 计算 存储 网络 统计命令
    MySQL B+ tree & B tree & Hash
    mmap学习总结
    Linux内存分配小结--malloc、brk、mmap【转】
  • 原文地址:https://www.cnblogs.com/merryjd/p/2873632.html
Copyright © 2011-2022 走看看