創建多媒體APP 之 捕獲圖像:簡單的拍照

這一節講述如何利用已有的拍照應用獲取一張照片。

假設你實現了大量的天氣服務來繪製一張全球氣象圖,這個圖裏面的天氣圖片都是來自你的客戶端APP拍照獲取,收集圖片只是很小的一部分工作,對於你的APP來說。所以在拍照獲取圖片方面,要儘可能的最簡單化,做最少的工作,不需要完全去重新實現一個相機,絕大部分android設備都會至少有一個拍照應用。這一節裏面就學習,如何利用已經存在的拍照應用獲取照片。

請求拍照權限

如果你的APP要利用拍照獲取圖片,那麼就要在GooglePlay裏面限制,僅僅針對那些有相機的設備才能看到。要聲明你的APP需要相機,只需要在manifest裏面聲明即可,利用<uses-feature>來聲明:

<manifest ... >
    <uses-feature android:name="android.hardware.camera" />
    ...
</manifest ... >


如果你的APP使用了它,但是並不是說必須用camera來獲取一張圖片,那麼在這個標籤裏面加入android:required="false"。這樣做的的話GooglePlay允許那些沒有攝像頭的設備也來下載這個APP。然後你需要在運行的時候,通過hasSystemFeature(PackageManager.FEATURE_CAMERA)去檢測設備的相機是可用。如果相機不可用,那麼你就要隱藏你的APP的拍照特性。

利用相機APP獲取照片

android利用intent來授權另外一個app來做你希望它做的事情。這個過程包括三塊:intent自身的創建,調用方法來通過intent啓動一個外部拍照Activity,處理拍照返回的圖像數據。

下面的的方法就是利用intent來拍一張照片:

private void dispatchTakePictureIntent(int actionCode) {
    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    startActivityForResult(takePictureIntent, actionCode);
}


利用這個代碼,你的APP可以讓另外一個相機應用來執行你要求的拍照動作。當然,如果沒有APP能夠響應這個intent,你的APP會沒有任何效果,拍照會失敗。下面的代碼可以檢測是否有app能夠處理這個intent.

public static boolean isIntentAvailable(Context context, String action) {
    final PackageManager packageManager = context.getPackageManager();
    final Intent intent = new Intent(action);
    List<ResolveInfo> list =
            packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
    return list.size() > 0;
}


如果返回值true,說明至少有一個應用可以處理這個intent.

查看照片

如果你的APP不是僅僅想拍照照片那麼簡單,也許你會想從相機應用得到拍照獲取的照片,然後對它進行一些處理。

android相機應用把照片數據放到一個intent裏面,然後傳遞給了onActivityResult()函數,作爲一個extra數據,是一個簡單Bitmap,使用”data” 這個extra屬性獲取。下面的代碼就是獲取到照片,然後顯示到一個ImageView.

private void handleSmallCameraPhoto(Intent intent) {
    Bundle extras = intent.getExtras();
    mImageBitmap = (Bitmap) extras.get("data");
    mImageView.setImageBitmap(mImageBitmap);
}


注意:從data獲取到的這個縮略圖,很適合做爲一個圖標,不適合做wie其他,想要獲得一個高分辨率的全圖,需要更多的工作。

保存照片

android的相機應用在你可以它一個存儲路徑的時候,會獲取到一張全幅的圖像。你必須要提供一個路徑,包括:存儲盤,文件夾,文件名。

下面的方法是簡單的一種獲取存儲照片路徑的方法,但是僅僅針對android2.2(API 8)和之上的設備版本。

storageDir = new File(
    Environment.getExternalStoragePublicDirectory(
        Environment.DIRECTORY_PICTURES
    ), 
    getAlbumName()
);  


對於早期的API,你要自己提供路徑名稱:

storageDir = new File (
    Environment.getExternalStorageDirectory()
        + PICTURES_DIR
        + getAlbumName()
);


注意: PICTURES_DIR這個是的是Pictures/,是外部或者內部存儲器上標準的用來分享照片的位置。

設置文件名稱

如前面提到的,圖像文件的位置是有設備環境決定的。你要做的就是要選擇一種沒有衝突的照片命名方案。你也許想把文件路徑名字保存起來,供後面使用。下面是一種解決辦法:

private File createImageFile() throws IOException {
    // Create an image file name
    String timeStamp = 
        new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    String imageFileName = JPEG_FILE_PREFIX + timeStamp + "_";
    File image = File.createTempFile(
        imageFileName, 
        JPEG_FILE_SUFFIX, 
        getAlbumDir()
    );
    mCurrentPhotoPath = image.getAbsolutePath();
    return image;
}


添加文件名到另外一個Intent

當有了一個文件保存的位置,那麼就把這個位置通話intent傳遞給拍照應用。

File f = createImageFile();
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f));


把照片添加到圖庫

當通過intent請求拍照到一張圖片的時候,你應該是知道你的圖片被保存到哪裏,因爲已經指定了路徑。對於其他的應用來說,最簡單的方法獲取到你的照片是通過Media Provider來獲取。

下面的代碼就演示瞭如何讓你的照片和系統的多媒體掃描相關聯,來把你的照片添加到Media Provider的數據庫。讓其對android 圖庫類的應用可見或者是其他類似的應用。

private void galleryAddPic() {
    Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
    File f = new File(mCurrentPhotoPath);
    Uri contentUri = Uri.fromFile(f);
    mediaScanIntent.setData(contentUri);
    this.sendBroadcast(mediaScanIntent);
}


編碼一個縮放的圖像

管理多種全尺寸的照片,對於有限的內存來說是很費力的。如果你發現你的程序在顯示一部分圖片之後,內存溢出了,你可以減少那個已經被縮放到符合到比例的jepg展開時所用的內存堆。下面的代碼展示了這個技術:

private void setPic() {
    // Get the dimensions of the View
    int targetW = mImageView.getWidth();
    int targetH = mImageView.getHeight();
  
    // Get the dimensions of the bitmap
    BitmapFactory.Options bmOptions = new BitmapFactory.Options();
    bmOptions.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
    int photoW = bmOptions.outWidth;
    int photoH = bmOptions.outHeight;
  
    // Determine how much to scale down the image
    int scaleFactor = Math.min(photoW/targetW, photoH/targetH);
  
    // Decode the image file into a Bitmap sized to fill the View
    bmOptions.inJustDecodeBounds = false;
    bmOptions.inSampleSize = scaleFactor;
    bmOptions.inPurgeable = true;
  
    Bitmap bitmap = BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
    mImageView.setImageBitmap(bitmap);
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章