Android第十三站 众多豪华控件 图片处理进阶

来源:互联网 发布:ubuntu启动后显示grub 编辑:程序博客网 时间:2024/04/28 11:35

目录

4.22 加载手机磁盘里的图片文件

4.23 动态放大缩小ImageView里的图片

运用Matrix对象来缩放图片文件

4.24 动态旋转图片

BitmapMatrix旋转ImageView

 

4.22 加载手机磁盘里的图片文件

范例说明

Android程序中,只要将图片文件存放在 /res/drawable/ 目录下,即可以通过R.drawable.id来取得图片id,并使用图片。如果不是存放在这个目录下面的图片文件,例如,用户想要从存储卡中读取刚拍的照片,又该如何实现呢?Android API中提供了BitmapAndroid.graphics.BitmapBitmapFactoryAndroid.graphics.BitmapFactory)对象,可以读取存储卡或手机文件系统里的图片文件。

实现本范例前需先准备两张图片,分别存放在“/res/drawable/”文件夹与手机文件系统的另一个文件夹中。以本范例而言,两张图片文件的路径分别为 /res/drawable/ex04_22_1.png/data/data/irdc. ex04_22_2.png。范例中会先将drawable目录里的图片文件显示于ImageView中,再设计一个Button,当用户单击Button后,将ImageView里的图片换成另一张存在手机文件系统里的图形文件。

src/irdc.ex04_22/EX04_22.java

程序中以BitmapFactory.decodeFile(fileName)来取得Bitmap对象,再将Bitmap对象以setImage Bitmap()来设置给ImageView

 

package irdc.ex04_22;

 

/* import程序略 */

 

public class EX04_22 extends Activity

{

  /*声明对象变量*/

  private ImageView mImageView;

  private Button mButton;

  private TextView mTextView;

  private String fileName="/data/data/irdc.ex04_22/ex04_22_2.png";

 

  /** Called when the activity is first created. */

  @Override

  public void onCreate(Bundle savedInstanceState)

  {

    super.onCreate(savedInstanceState);

    /*加载main.xml Layout */

    setContentView(R.layout.main);

   

    /* 取得Button对象,并添加onClickListener */

    mButton = (Button)findViewById(R.id.mButton);

    mButton.setOnClickListener(new Button.OnClickListener()

    {

      public void onClick(View v)

      {

      /* 取得对象 */

        mImageView = (ImageView)findViewById(R.id.mImageView);

        mTextView=(TextView)findViewById(R.id.mTextView);

        /* 检查文件是否存在 */

        File f=new File(fileName);  

        if(f.exists())

        {

          /* 产生Bitmap对象,并放入mImageView */

          Bitmap bm = BitmapFactory.decodeFile(fileName);

          mImageView.setImageBitmap(bm);

          mTextView.setText(fileName);

        }

        else

        { 

          mTextView.setText("文件不存在");

        }

      }

    });

  }

}

扩展学习

BitmapFactoryandroid.graphics.BitmapFactory)是Android API提供的对象,可以将图片文件转换成Bitmapandroid.graphics.Bitmap)对象,范例中使用的decodeFile()可以将手机文件系统中的图片文件转换成Bitmap对象。另外,BitmapFactory也提供了其他的方法,如decodeResource()可以将 /res/drawable/内预先存入的图片文件转换成Bitmap对象,decodeStream()方法则可将InputStream转换成Bitmap对象。

 

 

 

4.23 动态放大缩小ImageView里的图片

运用Matrix对象来缩放图片文件

 

本范例将运用Martixandroid.graphics.Matrix)对象的postScale()方法来实现在手机上缩放图片的功能,在实现本范例前,需先在/res/drawable/中放入一张图片。以本范例而言,图片文件路径为/res/drawable/ex04_23.png,程序会预先将图片加载到ImageView Widget中,并设计两个Button,一个有放大的功能、一个有缩小的功能,以显示图片放大缩小的效果。为了避免ImageView在放大的过程中,无止境地超过屏幕的尺寸,程序将在放大阶段控制图片的最大宽高。

主程序设计

程序中的small()方法会将图片缩小为原尺寸的4/5big()方法会将图片放大为原尺寸的1.25倍,当放大按钮的onClick事件被触发时,会运行big()方法;缩小按钮的onClick事件被触发时,则运行small()方法。

序中以Matrix对象搭配BitmapcreateBitmap()方法来对图片进行缩放,并利用DisplayMetrics对象来取得屏幕显示大小,用以控制图片放大后的尺寸不会超过屏幕显示的区域。

import android.app.Activity;

import android.graphics.Bitmap;

import android.graphics.BitmapFactory;

import android.graphics.Matrix;

import android.os.Bundle;

import android.util.DisplayMetrics;

import android.view.View;

import android.widget.AbsoluteLayout;

import android.widget.Button;

import android.widget.ImageView;

 

public class ex4_23 extends Activity {

     /* 相关变量声明 */

      private ImageView mImageView;

      private Button mButton01;

      private Button mButton02;

      private AbsoluteLayout layout1;

      private Bitmap bmp;

      private int id=0;

      private int displayWidth;

      private int displayHeight;

      private float scaleWidth=1;

      private float scaleHeight=1;

     

      /** Called when the activity is first created. */

      @Override

      public void onCreate(Bundle savedInstanceState)

      {

        super.onCreate(savedInstanceState);

        /*加载main.xml Layout */

 

        setContentView(R.layout.main);

       

        /* 取得屏幕分辨率大小 */

        DisplayMetrics dm=new DisplayMetrics();

        getWindowManager().getDefaultDisplay().getMetrics(dm);

        displayWidth=dm.widthPixels;

        /* 屏幕高度须扣除下方Button高度 */

        displayHeight=dm.heightPixels-80;

        /* 初始化相关变量 */

        bmp=BitmapFactory.decodeResource(getResources(),R.drawable.ex04_23);

        mImageView = (ImageView)findViewById(R.id.myImageView);

        layout1 = (AbsoluteLayout)findViewById(R.id.layout1);

        mButton01 = (Button)findViewById(R.id.myButton1);

        mButton02 = (Button)findViewById(R.id.myButton2);

       

        /* 缩小按钮onClickListener */

        mButton01.setOnClickListener(new Button.OnClickListener()

        {

          @Override

          public void onClick(View v)

          {

            small();

          }

        });

       

        /* 放大按钮onClickListener */

        mButton02.setOnClickListener(new Button.OnClickListener()

        {

          @Override

          public void onClick(View v)

          {

            big();

          }

        });   

      }

     

      /* 图片缩小的method */

      private void small()

      {

        int bmpWidth=bmp.getWidth();

        int bmpHeight=bmp.getHeight();

        /* 设置图片缩小的比例 */

       double scale=0.8; 

       /* 计算出这次要缩小的比例 */

        scaleWidth=(float) (scaleWidth*scale);

        scaleHeight=(float) (scaleHeight*scale);

       

        /* 产生reSize后的Bitmap对象 */

        Matrix matrix = new Matrix(); 

        matrix.postScale(scaleWidth, scaleHeight);

        Bitmap resizeBmp = Bitmap.createBitmap(bmp,0,0,bmpWidth,bmpHeight,matrix,true);

        

        if(id==0)

        {

         /* 如果是第一次按,就删除原来默认的ImageView */

          layout1.removeView(mImageView);

        }

        else

        {

        /* 如果不是第一次按,就删除上次放大缩小所产生的ImageView */

          layout1.removeView((ImageView)findViewById(id));

        }

        /* 产生新的ImageView,放入reSizeBitmap对象,再放入Layout */

        id++;

        ImageView imageView = new ImageView(ex4_23.this); 

        imageView.setId(id);

        imageView.setImageBitmap(resizeBmp);

        layout1.addView(imageView);

        setContentView(layout1);

       

        /* 因为图片放到最大时放大按钮会disable,所以在缩小时把它重设为enable */

        mButton02.setEnabled(true);

      }

     

      /* 图片放大的method */

      private void big()

      {  

        int bmpWidth=bmp.getWidth();

        int bmpHeight=bmp.getHeight();

        /* 设置图片放大的比例 */

        double scale=1.25; 

        /* 计算这次要放大的比例 */

        scaleWidth=(float)(scaleWidth*scale);

        scaleHeight=(float)(scaleHeight*scale);

       

        /* 产生reSize后的Bitmap对象 */

        Matrix matrix = new Matrix(); 

        matrix.postScale(scaleWidth, scaleHeight);

        Bitmap resizeBmp = Bitmap.createBitmap(bmp,0,0,bmpWidth,bmpHeight,matrix,true);

         

        if(id==0)

        {

        /* 如果是第一次按,就删除原来设置的ImageView */

          layout1.removeView(mImageView);

        }

        else

        {

        /* 如果不是第一次按,就删除上次放大缩小所产生的ImageView */

          layout1.removeView((ImageView)findViewById(id));

        }

        /* 产生新的ImageView,放入reSizeBitmap对象,再放入Layout */

        id++;

        ImageView imageView = new ImageView(ex4_23.this); 

        imageView.setId(id);

        imageView.setImageBitmap(resizeBmp);

        layout1.addView(imageView);

        setContentView(layout1);

       

        /* 如果再放大会超过屏幕大小,就把Button disable */

        if(scaleWidth*scale*bmpWidth>displayWidth||scaleHeight*scale*bmpHeight>displayHeight)

        {

          mButton02.setEnabled(false);

        }

      }

    }

因为在Android中不允许ImageView在产生后,动态修改其长度与宽度,所以为了实现图片放大、缩小的功能,使用的方式是当用户在单击放大或缩小的按钮时,除了将图片作放大或缩小的动作外,并将原来Layout中的ImageView删除,重新产生一个新的ImageView,指定图片给它后,再放入Layout里。用户看起来,就好像是同一张图片在放大或缩小。

在放大、缩小图片文件时使用的Martix对象,除了可以用来作图片的缩放外,还有非常实用的旋转效果,我们将会在后面的范例中示范。

4.24 动态旋转图片

BitmapMatrix旋转ImageView

要旋转ImageView其实很简单,先将前一次ImageView里的图片放入暂存Bitmap,接着再利用Bitmap.createBitmap来创建新的Bitmap对象,在创建新的Bitmap对象的同时,搭配Matrix对象里的setRotate()方法动态旋转新创建的Bitmap。然后,再将旋转好的Bitmap对象,以新构造的方式创建新的Bitmap对象,最后再“放入”ImageView中显示,就可以达到旋转ImageView的效果,这个范例的学习重点则在于如何操作BitmapFactory.decodeResource()方法来使用Matrix对图像的控制,为了让旋转能够通过事件来进行,所以在Layout中配置了两个Button Widget,以及一个ImageView Widget。当单击“向左旋转”按钮时,画面的小河马就会向左倾斜;当单击“向右旋转”按钮时,画面的小河马就会向右倾斜。

范例程序

程序设置了两个按钮,分别处理向左及向右旋转的语句,而为了防止旋转角度超过数值范围,所以默认参考值(ScaleAngle)向左最多为5、向右则最多为5,再利用Matrix对象里的matrix.setRotate()方法,将5*ScaleAngle的计算结果传入作为参数,使其产生每次至少5°的变化,在20°20°之间。

Bitmap.createBitmap()方法所扮演的角色为产生暂存的Bitmap,使之每一次(单击按钮时)都“复制”来自原始图“mySourceBmp”的数据,自坐标(0,0-(原图宽,原图高)复制成为新图,而由于createBitmap()方法的第六个参数可指定Matrix对象,这也就是本范例程序旋转画面的唯一关键。

 

import android.app.Activity;

import android.graphics.Bitmap;

import android.graphics.BitmapFactory;

import android.graphics.Matrix;

import android.graphics.drawable.BitmapDrawable;

import android.os.Bundle;

import android.view.View;

import android.widget.Button;

import android.widget.ImageView;

import android.widget.TextView;

 

 

public class ex4_24 extends Activity {

    private Button mButton1;

      private Button mButton2;

      private TextView mTextView1;

      private ImageView mImageView1;

      private int ScaleTimes;

      private int ScaleAngle;

     

      /** Called when the activity is first created. */

      @Override

      public void onCreate(Bundle savedInstanceState)

      {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

       

        mButton1 =(Button) findViewById(R.id.myButton1);

        mButton2 =(Button) findViewById(R.id.myButton2);

        mTextView1 = (TextView) findViewById(R.id.myTextView1);

        mImageView1 = (ImageView) findViewById(R.id.myImageView1);

        ScaleTimes = 1;

        ScaleAngle = 1;

       

        final Bitmap mySourceBmp = BitmapFactory.decodeResource(getResources(), R.drawable.hippo);

       

        final int widthOrig = mySourceBmp.getWidth();

        final int heightOrig = mySourceBmp.getHeight();

       

        /* 程序刚运行,加载默认的Drawable */

 

        mImageView1.setImageBitmap(mySourceBmp);

       

        /* 向左旋转按钮 */

 

        mButton1.setOnClickListener(new Button.OnClickListener()

        {

          @Override

          public void onClick(View v)

          {

            // TODO Auto-generated method stub

            ScaleAngle--;

            if(ScaleAngle<-5)

            {

              ScaleAngle = -5;

            }

           

            /* ScaleTimes=1,维持1:1的宽高比例*/

 

            int newWidth = widthOrig * ScaleTimes;

            int newHeight = heightOrig * ScaleTimes;

           

            float scaleWidth = ((float) newWidth) / widthOrig;

            float scaleHeight = ((float) newHeight) / heightOrig;

           

            Matrix matrix = new Matrix();

            /* 使用Matrix.postScale设置维度 */

 

            matrix.postScale(scaleWidth, scaleHeight);

           

            /* 使用Matrix.postRotate方法旋转Bitmap*/

 

            //matrix.postRotate(5*ScaleAngle);

            matrix.setRotate(5*ScaleAngle);

           

            /* 创建新的Bitmap对象 */

 

            Bitmap resizedBitmap = Bitmap.createBitmap(mySourceBmp, 0, 0, widthOrig, heightOrig, matrix, true);

            /**/

            BitmapDrawable myNewBitmapDrawable = new BitmapDrawable(resizedBitmap);

            mImageView1.setImageDrawable(myNewBitmapDrawable);

            mTextView1.setText(Integer.toString(5*ScaleAngle));

          }     

        });

       

        /* 向右旋转按钮 */

 

        mButton2.setOnClickListener(new Button.OnClickListener()

        {

          @Override

          public void onClick(View v)

          {

            // TODO Auto-generated method stub

            ScaleAngle++;

            if(ScaleAngle>5)

            {

              ScaleAngle = 5;

            }

           

            /* ScaleTimes=1,维持1:1的宽高比例*/

 

            int newWidth = widthOrig * ScaleTimes;

            int newHeight = heightOrig * ScaleTimes;

           

            /* 计算旋转的Matrix比例 */

 

            float scaleWidth = ((float) newWidth) / widthOrig;

            float scaleHeight = ((float) newHeight) / heightOrig;

           

            Matrix matrix = new Matrix();

            /* 使用Matrix.postScale设置维度 */

 

            matrix.postScale(scaleWidth, scaleHeight);

           

            /* 使用Matrix.postRotate方法旋转Bitmap*/

 

            //matrix.postRotate(5*ScaleAngle);

            matrix.setRotate(5*ScaleAngle);

 

            /* 创建新的Bitmap对象 */

 

            Bitmap resizedBitmap = Bitmap.createBitmap(mySourceBmp, 0, 0, widthOrig, heightOrig, matrix, true);

            /**/

            BitmapDrawable myNewBitmapDrawable = new BitmapDrawable(resizedBitmap);

            mImageView1.setImageDrawable(myNewBitmapDrawable);

            mTextView1.setText(Integer.toString(5*ScaleAngle));

          }

        });

      }

    }

扩展学习

Matrix类的设计,不仅是二维空间的结构,事实上,它原始的设计是3´3的矩阵,由于Matrix类并不需要构造器,因此在声明Matrix对象之后,可以调用reset()方法或set()方法产生新的矩阵,如同本范例的setRotate一样。

来看看,我们在这个范例程序中,也放上了添加注释的语句matrix.postRotate(5*ScaleAngle)经测试后,无论是使用postRotate()方法或setRotate()方法,效果都是相同的,但较困惑的是Google的官方SDK文件中,所描述的postRotate()方法的原型如下:

boolean postRotate(float degrees, float px, float py)

经测试postRotate()方法并没有第二、第三个参数需要传递,这是在Android SDK 1.0_r2才发现的,未来可能会因为改版而有所改变。

另外,Matrix还有一个常用的postScale()方法,可通过矩阵的方式用以指定其缩放大小,其原型如下:

public boolean postScale(float sx, float sy, float px, float py)

使用的公式为:M' = S(sx, sy, px, py)* M,示意的片段程序如下。

final Bitmap mySourceBmp =

BitmapFactory.decodeResource(getResources(), R.drawable.hippo)

Matrix mx = new Matrix();

mx.postScale

(

  (float)20/mySourceBmp.getWidth(),

  (float)20/mySourceBmp.getHeight()

);

mySourceBmp = Bitmap.createBitmap

(bm, 0, 0, bm.getWidth(), bm.getHeight(), mx, true);

mImageView1.setImageBitmap(mySourceBmp);