Android多媒体开发 Pro Android Media 第一章 Android图像编程入门 2

采集更大的图像

为了解决大小限制,从Android 1.5开始,在大多数机器上,我们传入一个extra到激活相机应用的Intent中。此extra的名字在MediaStore类中定义为EXTRA_OUTPUT。它的值(extra以名称-值对的形式存在)以URI的形式,为相机应用指定了拍摄的图像保存的地方。

下面的代码段要求相机应用将图像保存到设备的SD卡,文件名为myfavoritepicture.png。

String imageFilePath = Environment.getExternalStorageDirectory().getAbsolutePath()
    + "/myfavoritepicture.jpg"; 
File imageFile = new File(imageFilePath);  
Uri imageFileUri = Uri.fromFile(imageFile);  
Intent i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);  
i.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, imageFileUri);  
startActivityForResult(i, CAMERA_RESULT); 
注意:上述创建图像文件URI的代码段可以简化如下:
imageFileUri =  Uri.parse("file:///sdcard/myfavoritepicture.jpg"); 
虽然在实践中,所示的方法设备无关性更强,而且当SD卡的命名规则或者URI的语法因本地系统改变时,仍然能够兼容。

显示大图像

加载和显示图像涉及大量使用内存。例如,HTC G1手机拥有一个320万像素的摄像头。320M像素的摄像头,拍摄的图像通常为2048x1536像素。显示32位的这样大小的图像需要多达100663kb,大约13MB的内存。虽然不能肯定我们的应用就会耗尽内存,但是它显然使内存耗尽的可能性大大增加了。

Android给我们提供了一个名为BitmapFactory的工具类,它提供了一系列的静态方法从各种源加载位图图像。我们的需求是从文件加载图像,并把它显示在我们最初的activity中。幸运的是,BitmapFactory提供的加载方法都接受BitmapFactory.Options类,它允许我们定义将位图读入到内存的方式。具体来说,我们可以设置BitmapFactory加载图像的采样大小。指定BitmapFactory.Options类的inSampleSize参数,得到的位图图像将为原图大小inSampleSize分之一。例如,像我在这里做的,inSampleSize设置为8,将生成一个原图1/8大小的图像。

BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();  
bmpFactoryOptions.inSampleSize = 8;  
Bitmap bmp = BitmapFactory.decodeFile(imageFilePath, bmpFactoryOptions);  
imv.setImageBitmap(bmp);

这是一个快速加载大图像的方法,但是没有考虑图像的原始大小以及屏幕的大小。如果我们缩放图像使之适应我们的屏幕,那就更好了。

下面的代码段说明了如何使用屏幕的大小确定加载图像时的采样值。当我们采用这些方法时,图像能够确保尽可能的填充屏幕。然而,如果图像的任一维度只显示100像素,则这个值将用来替换屏幕的维度。获取显示屏维度的代码如下:

Display currentDisplay = getWindowManager().getDefaultDisplay();  
int dw = currentDisplay.getWidth();  
int dh = currentDisplay.getHeight(); 

需要计算,才能得出图像的尺寸。为此,我们使用BitmapFactory和BitmapFactory.Options来帮忙。将BitmapFactory.Options.inJustDecodeBounds的值设置为true。这会告知BitmapFactory只需给出图像大小信息,无需解码图像本身。当我们使用这个方法时,BitmapFactory将给BitmapFactory.Options.outHeight和BitmapFactory.Options.outWidth两个变量赋值。

//加载图像的外形尺寸,而非图像本身 
BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();  
bmpFactoryOptions.inJustDecodeBounds = true; 
Bitmap bmp = BitmapFactory.decodeFile(imageFilePath, bmpFactoryOptions);  
int heightRatio = (int)Math.ceil(bmpFactoryOptions.outHeight/(float)dh);  

int widthRatio = (int)Math.ceil(bmpFactoryOptions.outWidth/(float)dw);  
Log.v("HEIGHTRATIO",""+heightRatio);  
Log.v("WIDTHRATIO",""+widthRatio); 

用图像的高度和宽度分别除以显示屏的高度和宽度,得到高度比和宽度比。然后,我们其中较大的那个作为缩放的比值。将这个比值赋给BitmapFactory.Options.inSampleSize变量,就可以得到一个加载到内存,大小接近我们所需的图像—在本例中,接近屏幕大小。

//如果两个比值都大于1,
//那么图像的某一边大于屏幕 
if (heightRatio > 1 && widthRatio > 1)  {  
    if (heightRatio > widthRatio)  { 
        //高度比较大,以它进行缩小
        bmpFactoryOptions.inSampleSize = heightRatio;  
    }  
    else  {  
        //宽度比较大,以它进行缩小
        bmpFactoryOptions.inSampleSize = widthRatio;  
    }  
}  
// 真正解码图像
bmpFactoryOptions.inJustDecodeBounds = false;  
bmp = BitmapFactory.decodeFile(imageFilePath, bmpFactoryOptions);

这里是通过Intent使用内置相机应用,并显示所得图片的完整例子代码。图1-3 显示了此示例产生的,满屏大小的图像。

package com.apress.proandroidmedia.ch1.sizedcameraintent;  
import java.io.File;  
import android.app.Activity;  
import android.content.Intent;  
import android.graphics.Bitmap;  
import android.graphics.BitmapFactory;  
import android.net.Uri;  
import android.os.Bundle;  
import android.os.Environment;  
import android.util.Log;  
import android.view.Display;  
import android.widget.ImageView;  

public class SizedCameraIntent extends Activity {  
    final static int CAMERA_RESULT = 0;  
    ImageView imv;  String imageFilePath;  

    @Override  public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.main);  
        imageFilePath = Environment.getExternalStorageDirectory().getAbsolutePath() 
            + "/myfavoritepicture.jpg";  
        File imageFile = new File(imageFilePath);  
        Uri imageFileUri = Uri.fromFile(imageFile);  
        Intent i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);  
        i.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, imageFileUri);  
        startActivityForResult(i,CAMERA_RESULT);  
    }  

    protected void onActivityResult(int requestCode, int resultCode, Intent intent) {  
        super.onActivityResult(requestCode, resultCode, intent);  
        if (resultCode == RESULT_OK)  {  
            //取得ImageView的引用 
            imv = (ImageView) findViewById(R.id.ReturnedImageView);
  
            Display currentDisplay = getWindowManager().getDefaultDisplay();  
            int dw = currentDisplay.getWidth();  
            int dh = currentDisplay.getHeight(); 

            //加载图片的尺寸信息,而非图像本身
            BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();  
            bmpFactoryOptions.inJustDecodeBounds = true;  
            Bitmap bmp = BitmapFactory.decodeFile(imageFilePath, bmpFactoryOptions); 
 
            int heightRatio = (int)Math.ceil(bmpFactoryOptions.outHeight/(float)dh);  
            int widthRatio = (int)Math.ceil(bmpFactoryOptions.outWidth/(float)dw);
            Log.v("HEIGHTRATIO",""+heightRatio);  
            Log.v("WIDTHRATIO",""+widthRatio); 

            // 如果两个比值都大于1,
            // 那么图像的某一边大于屏幕 
            if (heightRatio > 1 && widthRatio > 1)  {  
                if (heightRatio > widthRatio)  { 
                    // 高度比较大,以它进行缩小
                    bmpFactoryOptions.inSampleSize = heightRatio; 
                }  
                else  { 
                    // 宽度比较大,以它进行缩小
                    bmpFactoryOptions.inSampleSize = widthRatio;  
                }
             }  

             // 真正解码图像
             bmpFactoryOptions.inJustDecodeBounds = false;  
             bmp = BitmapFactory.decodeFile(imageFilePath, bmpFactoryOptions); 

             // 显示图像 
             imv.setImageBitmap(bmp);  
         }  
    }  
}

上述代码需要下面的 layout/main.xml文件:

<?xml version="1.0" encoding="utf-8"?>  
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:orientation="vertical"  
    android:layout_width="fill_parent"  
    android:layout_height="fill_parent" >
 
    <ImageView android:id="@+id/ReturnedImageView" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content">
    </ImageView>  
</LinearLayout> 

图1-3. 返回的满屏大小图像显示在ImageView中


Android多媒体开发 Pro Android Media 第一章 Android图像编程入门 2

上一篇:Android自动化测试(Jenkins+Robotium+Ant+Junit)[PART one]


下一篇:Android学习笔记入门 : 02Service