Android多媒體開發 Pro Android Media 第一章 Android影象程式設計入門 2
阿新 • • 發佈:2019-02-04
採集更大的影象
為了解決大小限制,從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中