1. 程式人生 > >android開發遊記:CROP 大圖片裁剪原理分析

android開發遊記:CROP 大圖片裁剪原理分析

最近專案中需要加入裁剪圖片的功能,圖片的來源包括相機拍照和相簿手動選擇,使用了系統自帶的裁圖功能Crop,但是實際使用中卻發生了一些意想不到的問題:

  • 裁剪後返回的data為null
  • 裁剪後返回的圖片嚴重失真

這裡總結一下出現問題的原因和解決方案:

呼叫系統裁剪元件的需要設定一些intent引數,通常如下:

Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);
intent.setType("image/*");
intent.putExtra("crop", "true");
intent.putExtra("aspectX"
, 2); intent.putExtra("aspectY", 1); intent.putExtra("outputX", 400); intent.putExtra("outputY", 400); intent.putExtra("scale", true); intent.putExtra("return-data", true); intent.putExtra("outputFormat",Bitmap.CompressFormat.JPEG.toString()); intent.putExtra("noFaceDetection", true); startActivityForResult(intent, 1
);

上面的
intent.putExtra("return-data", true);
指定了是否返回資料
-如果設定為true,則在返回的data中能拿到返回的bitmap資料
-如果設定為false,則不會返回data,相應的會返回給玩家一個uri,這個uri關聯了一張外存裝置中的一張圖片,就是裁剪後的圖片

然而google為什麼要這樣設計看起來多此一舉的功能呢,直接返回data不就好了嗎?
這樣做的主要原因是因為activity間的引數傳遞大小受到嚴格限制,這主要是考慮到手機執行效能,所以做了這樣的設計。如果你裁剪的只是一張小圖片,那麼ok,設定return-data為true,直接從返回的data中取出bitmap就行了,如果你返回的是一張大圖,那麼久萎了,你會發現如果你的
intent.putExtra("outputX", 400);


intent.putExtra("outputY", 400);
這2個引數設定過大,你收到的返回bitmap將會是一個縮圖!
google這樣做是為了保證系統流暢執行,這樣想想也算合理。

那麼,如何裁剪大圖片呢?
只有把return-data設定為false
然後設定一個uri用於儲存圖片到外存裝置

Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);
intent.setType("image/*");
intent.putExtra("crop", "true");
intent.putExtra("aspectX", 2);
intent.putExtra("aspectY", 1);
intent.putExtra("outputX", 400);
intent.putExtra("outputY", 400);
intent.putExtra("scale", true);
intent.putExtra("return-data", false);
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
intent.putExtra("outputFormat",Bitmap.CompressFormat.JPEG.toString());
intent.putExtra("noFaceDetection", true);
startActivityForResult(intent, 1);

然後在 onActivityResult 這樣處理:

switch (requestCode) {
case 1:
    if(uri != null){
        Bitmap bitmap = null;
        try {
            bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        imageView.setImageBitmap(bitmap);
    }
    break;
}

這樣就解決的裁剪大圖的問題

然而,你會發現呼叫系統裁剪元件會消耗大量的記憶體,有時候會殺死你應用的程序,導致你不得不做好應用的被殺恢復工作,在一些低端機上裁圖元件根本打不開,或者直接崩潰;而且返回大圖過大,而你僅僅是想要一張能看得清楚字的圖就ok了,比如說營業許可證證件照,你並不希望圖片過於高清佔用太大的記憶體空間,或者上傳產生過多的流量,使你不得不再次壓縮圖片。總之你會發現這些處理工作過於麻煩。這樣你就需要使用自定義的裁圖元件。

我調查發現市面上主流的應用如qq微信等,都沒有使用系統裁圖,而是自己編寫了一個裁圖元件來解決這些問題。
下一章我就分享一下如何自定義裁剪圖片功能元件