1. 程式人生 > >Android之圖片選擇與裁剪

Android之圖片選擇與裁剪

對於現在的應用來說,基本都有使用者模組,當然也就涉及到了使用者頭像的修改問題。修改頭像我們一般採用兩種方式:呼叫系統相機進行拍照或從相簿中選擇圖片進行上傳。但是由於Rom定製市場的混亂,導致了出現此問題在解決時需要重點考慮了相容性,下面給出一種通用解決方案。

啟動相機進行拍照

需要注意的是,Android系統為了防止傳送原圖出現OOM,拍照後預設返回的是縮圖,為了解決這種問題,我們在啟動相機的時候要先設定照片的儲存路徑,即傳遞MediaStore.EXTRA_OUTPUT引數,這樣拍照完成後我們就可以根據之前設定的路徑讀取原圖了。

1
2
3
4
5
6
// 設定圖片的輸出路徑
File file = new File(Environment.getExternalStorageDirectory() + "/temp_icon.jpg");
iconUri = Uri.fromFile(file); Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); intent.putExtra(MediaStore.EXTRA_OUTPUT, iconUri); startActivityForResult(intent, REQUEST_CODE_TAKE_PHOTO);

開啟相簿選擇圖片

選擇圖片操作其實沒什麼難度,選擇完成後預設返回的就是圖片的儲存路徑。

1
2
3
Intent intent = new Intent(Intent.ACTION_PICK, null);
intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*"); startActivityForResult(intent, REQUEST_CODE_CHOOSE_IMAGE);

裁剪圖片

和拍照的情況一樣,Android為了防止傳送大圖片出現OOM,在截圖的過程中預設傳遞的也是縮圖,這樣裁減後的圖片會非常模糊。所以採用URi的方式傳遞來原圖的路徑。需要注意的是,如果傳遞原圖,那麼拍照時需要設定照片的輸出路徑,也就是在呼叫相機時傳遞MediaStore.EXTRA_OUTPUT引數,同時為了防止某些手機預設傳遞原圖的問題(如小米4),在傳遞大圖片時將return-data置為false;對於某些手機或平板,輸入Uri和輸出Uri不能相等,否則裁減後的圖片大小變為0kb,如平板Teclast P80h.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
 * 裁減圖片操作
 * @param uri
 */
private void startCropImage(Uri uri) {
    Intent intent = new Intent("com.android.camera.action.CROP");
    intent.setDataAndType(uri, "image/*");
    // 使圖片處於可裁剪狀態
    intent.putExtra("crop", "true");
    // 裁剪框的比例(根據需要顯示的圖片比例進行設定)
    intent.putExtra("aspectX", 3);
    intent.putExtra("aspectY", 2);
    // 讓裁剪框支援縮放
    intent.putExtra("scale", true);
    // 裁剪後圖片的大小(注意和上面的裁剪比例保持一致)
    intent.putExtra("outputX", AndroidPlatformUtil.dpToPx(this, 120));
    intent.putExtra("outputY", AndroidPlatformUtil.dpToPx(this, 80));
    // 傳遞原圖路徑
    File cropFile = new File(Environment.getExternalStorageDirectory() + "crop_image.jpg");
    cropImageUri = Uri.fromFile(cropFile);
    intent.putExtra(MediaStore.EXTRA_OUTPUT, cropImageUri);
    // 設定裁剪區域的形狀,預設為矩形,也可設定為原形
    //intent.putExtra("circleCrop", true);
    // 設定圖片的輸出格式
    intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
    // return-data=true傳遞的為縮圖,小米手機預設傳遞大圖,所以會導致onActivityResult呼叫失敗
    intent.putExtra("return-data", false);
    // 是否需要人臉識別
    intent.putExtra("noFaceDetection", true);
    startActivityForResult(intent, REQUEST_CODE_CROP_IMAGE);
}

獲取傳遞的圖片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
    super.onActivityResult(requestCode, resultCode, intent);
    if(intent != null) {
        switch (requestCode) {
        	  // 將拍攝的照片進行裁剪(注意,這裡需要傳遞的是照片的路徑,而不是intent.getData(), 因為intent.getData()返回的是縮圖的資料)
            case REQUEST_CODE_TAKE_PHOTO:
                startCropImage(iconUri);
                break;
            // 將選擇的圖片進行裁剪
            case REQUEST_CODE_CHOOSE_IMAGE:
                if (intent.getData() != null) {
                    iconUri = intent.getData();
                    startCropImage(iconUri);
                }
                break;
            // 將裁剪後的圖片進行上傳
            case REQUEST_CODE_CROP_IMAGE:
                // 上傳圖片操作
                break;
            default:
                break;

        }
    } else {
    	// 解決某些手機intent為空的情況
        if (requestCode == REQUEST_CODE_TAKE_PHOTO && iconUri != null) {
            startCropImage(iconUri);
        }
    }
}

總結

通過上面的四步,圖片的選擇與裁剪就完成了。總的來說,需要注意的只有一點,無論是拍照還是選選擇圖片到裁剪的過程,只有傳遞圖片的路徑才能從根本上實現此問題。否則將出現各種相容性問題。還有一點需要提醒的是:裁剪是真正決定所要展示圖片的比例和大小的。