[Android] 圖片裁剪總結——調用系統裁剪


花了兩天時間看了下android的圖片裁剪功能的實現。其實剛開始做這個我挺虛的,以為整個功能都需要自己寫出來,但查了些資料,發現android已經提供了裁剪功能,需要的話自己調用就成了。soga,這下輕松多了。

原文地址請保留http://www.cnblogs.com/rossoneri/p/3976530.html 

首先推薦幾篇博客

Android大圖片裁剪終極解決方案

要想弄明白裁剪功能,這系列博客非常重要,你可以不看我下面總結的,但你一定要看他這系列的幾篇文章。

Android 圖片裁剪功能實現詳解(類似QQ自定義頭像裁剪)

這篇也不錯,比較喜歡他的注釋。雖然也有些誤導,比如說他有一段對setData,setType和setDataAndType方法的區別疑問,他說兩種寫法一樣效果,我就信了,害得我找bug找了兩個小時,一直懷疑別的參數出問題,實際上是這兩個方法的差別。這一點后面會說。

其他的相關博客有很多,但基本上大同小異,包括我這篇。有了上面的兩個博客,就可以大概搞懂這方面的原理了。

我要寫的,就是多寫一些注釋,改變一些寫法,增加點說明,積累點經驗,為了自己以后方便重溫自己做過的東西,而已。

不再浪費你我的時間,開始了。

 


丑得不能忍的分割區


RyanHoo的Demo寫的很詳細。但要學習,我習慣先把代碼簡化,看的邏輯清楚些。我選擇了最適應自己需求的選擇大圖片裁剪的部分代碼

我測試的簡化代碼

 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:tools="http://schemas.android.com/tools"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     tools:context=".MainActivity" >
 6 
 7     <Button
 8         android:id="@+id/button"
 9         android:layout_width="wrap_content"
10         android:layout_height="wrap_content"
11         android:text="click me!" />
12 
13     <ImageView
14         android:id="@+id/imageview"
15         android:layout_width="match_parent"
16         android:layout_height="match_parent"
17         android:scaleType="centerInside" />
18 
19 </LinearLayout>
  1 public class MainActivity extends Activity implements OnClickListener {
  2 
  3     private Uri imageUri;
  4     private static final String IMAGE_FILE_LOCATION = "file:///sdcard/temp.jpg";
  5     private Button btn;
  6     private ImageView iv;
  7 
  8     @Override
  9     protected void onCreate(Bundle savedInstanceState) {
 10         super.onCreate(savedInstanceState);
 11         setContentView(R.layout.activity_main);
 12         btn = (Button) findViewById(R.id.button);
 13         btn.setOnClickListener(this);
 14         imageUri = Uri.parse(IMAGE_FILE_LOCATION);
 15         iv = (ImageView) findViewById(R.id.imageview);
 16     }
 17 
 18     @Override
 19     public boolean onCreateOptionsMenu(Menu menu) {
 20         // Inflate the menu; this adds items to the action bar if it is present.
 21         getMenuInflater().inflate(R.menu.activity_main, menu);
 22         return true;
 23     }
 24 
 25     @Override
 26     public void onClick(View v) {
 27         // TODO Auto-generated method stub
 28 
 29         // 試着改成打開自己寫的圖片瀏覽器
 30         switch (v.getId()) {
 31         case R.id.button:
 32             // 這段代碼使用ACTION_GET_CONTENT和ACTION_PICK效果相同
 33             Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);
 34             // Intent intent = new Intent(Intent.ACTION_PICK, null);
 35 
 36             // 如果使用com.android.camera.action.CROP 則直接打開裁剪照片的activity 那么可以用自己的圖片瀏覽器選擇圖片 傳入參數並使用之
 37             // Intent intent = new Intent("com.android.camera.action.CROP");
 38 
 39             // 如果不設置type,則 ACTION_GET_CONTENT 會彈出異常FATAL EXCEPTION:main android.content.ActivityNotFoundException
 40             // 而 ACTION_PICK 會彈出可用程序列表 但沒有打開圖片相關的程序(在我的兩個設備上是這樣)
 41             intent.setType("image/*");
 42 
 43             // 設置在開啟的Intent中設置顯示的view可裁剪
 44             // 這段代碼里設置成false也能裁剪啊。。。這是為什么?懂的給我講講了
 45             // 這段注釋掉就不會跳轉到裁剪的activity
 46             intent.putExtra("crop", "true");
 47 
 48             // 設置x,y的比例,截圖方框就按照這個比例來截 若設置為0,0,或者不設置 則自由比例截圖
 49             intent.putExtra("aspectX", 2);
 50             intent.putExtra("aspectY", 1);
 51 
 52             // 裁剪區的寬和高 其實就是裁剪后的顯示區域 若裁剪的比例不是顯示的比例,則自動壓縮圖片填滿顯示區域。若設置為0,0 就不顯示。若不設置,則按原始大小顯示
 53             intent.putExtra("outputX", 200);
 54             intent.putExtra("outputY", 100);
 55 
 56             // 不知道有啥用。。可能會保存一個比例值 需要相關文檔啊
 57             intent.putExtra("scale", true);
 58 
 59             // true的話直接返回bitmap,可能會很占內存 不建議
 60             intent.putExtra("return-data", false);
 61             // 上面設為false的時候將MediaStore.EXTRA_OUTPUT即"output"關聯一個Uri
 62             intent.putExtra("output", imageUri);
 63             // 看參數即可知道是輸出格式
 64             intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
 65             // 面部識別 這里用不上
 66             intent.putExtra("noFaceDetection", false);
 67 
 68             // 想從Activity中獲得返回數據,在啟動Activity時候使用startActivityForResult方法
 69             // 1為請求代碼,可以是任意值,個人感覺用資源id會比較清楚,而且不會重復 比如當前控件的R.id.button
 70             startActivityForResult(intent, 1);
 71             break;
 72         default:
 73             break;
 74         }
 75     }
 76 
 77     @Override
 78     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
 79         // TODO Auto-generated method stub
 80         super.onActivityResult(requestCode, resultCode, data);
 81         if (resultCode != Activity.RESULT_OK) {// result is not correct
 82             return;
 83         } else {
 84             switch (requestCode) {
 85             case 1:
 86                 if (imageUri != null) {
 87                     Bitmap bitmap = decodeUriAsBitmap(imageUri);
 88                     // 把解析到的位圖顯示出來
 89                     iv.setImageBitmap(bitmap);
 90                 }
 91                 break;
 92             default:
 93                 break;
 94             }
 95 
 96         }
 97     }
 98 
 99     private Bitmap decodeUriAsBitmap(Uri uri) {
100         Bitmap bitmap = null;
101         try {
102             // 先通過getContentResolver方法獲得一個ContentResolver實例,
103             // 調用openInputStream(Uri)方法獲得uri關聯的數據流stream
104             // 把上一步獲得的數據流解析成為bitmap
105             bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri));
106         } catch (FileNotFoundException e) {
107             e.printStackTrace();
108             return null;
109         }
110         return bitmap;
111     }
112 }

其實用法看前面的博客就已經很清楚了,這里主要部分就是Intent附加數據的具體含義解釋與使用方法,我都盡量寫在代碼的注釋當中了。

 

 


再丑也得忍的分割線


 

我后來想只調用裁剪窗口,而選圖片的時候使用自己寫的圖片選擇器,那么這個參數怎么傳,怎么調用裁剪activity呢?

使用裁剪功能用"com.android.camera.action.CROP"就可以。

傳圖片的話有兩個方法,一個是intent直接傳bitmap數據,另一個是傳uri。

 

 1     private void startCropIntent(String path) throws FileNotFoundException {
 2         Bitmap bmp = BitmapFactory.decodeFile(path);
 5         Intent intent = new Intent("com.android.camera.action.CROP"); 9         // Intent傳輸的bytes不能超過40k。不建議這樣 無法處理大圖
10         intent.putExtra("data", bmp);
11         // intent.setData(uri);
12         // intent.setType("image/*");
13         intent.setDataAndType(imageUri, "image/*");
14         intent.putExtra("crop", "true");
15         intent.putExtra("aspectX", 2);
16         intent.putExtra("aspectY", 1);
17         intent.putExtra("outputX", 300);
18         intent.putExtra("outputY", 150);
19         // 設置為true直接返回bitmap
20         intent.putExtra("return-data", true);
24         startActivityForResult(intent, 1);
25     }
26 
27     @Override
28     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
29         super.onActivityResult(requestCode, resultCode, data);
30         if (resultCode != Activity.RESULT_OK) {// result is not correct
31             return;
32         } else {
33             switch (requestCode) {
34             case 1:
40                 Bundle bundle = data.getExtras();
41                 Bitmap bitmap = bundle.getParcelable("data");
42                 iv.setImageBitmap(bitmap);
43 
44                 break;
45 
46             default:
47                 break;
48             }
49         }
51     }

這里參數path是選擇的圖片的絕對路徑。

這種方法有局限性,因為intent傳遞的數據不超過40k,只能選擇40k以下的圖片裁剪

還是使用uri比較好

 1 private void startCropIntent(String path) throws FileNotFoundException {
 2         Bitmap bmp = BitmapFactory.decodeFile(path);
 3 
 4         File file = new File(path);
 5         Intent intent = new Intent("com.android.camera.action.CROP");
 7         Uri uri = Uri.fromFile(file);// parse(pathUri);13         intent.setDataAndType(uri, "image/*");
14         intent.putExtra("crop", "true");
15         intent.putExtra("aspectX", 2);
16         intent.putExtra("aspectY", 1);
17         intent.putExtra("outputX", 300);
18         intent.putExtra("outputY", 150);
19         // 設置為true直接返回bitmap
20         intent.putExtra("return-data", false);
21         // 上面設為false的時候將MediaStore.EXTRA_OUTPUT關聯一個Uri
22         intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
23         intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
24         startActivityForResult(intent, 1);
25     }
26 
27     @Override
28     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
29         super.onActivityResult(requestCode, resultCode, data);
30         if (resultCode != Activity.RESULT_OK) {// result is not correct
31             return;
32         } else {
33             switch (requestCode) {
34             case 1:
35                 if (imageUri != null) {
36                     Bitmap bitmap = decodeUriAsBitmap(imageUri);
37                     // 把解析到的位圖顯示出來
38                     iv.setImageBitmap(bitmap);
39                 }
44                 break;
45 
46             default:
47                 break;
48             }
49         }
50 
51     }
52 
53     private Bitmap decodeUriAsBitmap(Uri uri) {
54         Bitmap bitmap = null;
55         try {
59             bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri));
60         } catch (FileNotFoundException e) {
61             e.printStackTrace();
62             return null;
63         }
64         return bitmap;
65     }

這里需要注意

intent.setData(uri);intent.setType("image/*");和
intent.setDataAndType(uri, "image/*");是有區別的。

我開始以為兩個方法一樣的,但看了源碼就清楚了。

1  public Intent setDataAndType(Uri data, String type) {
2         mData = data;
3         mType = type;
4         return this;
5     }
1     public Intent setData(Uri data) {
2         mData = data;
3         mType = null;
4         return this;
5     }
1     public Intent setType(String type) {
2         mData = null;
3         mType = type;
4         return this;
5     }

好了,調用系統裁剪就這么些內容,這方面除了文檔太難找,也沒什么難的。

下面就是不調用系統,自己寫一個裁剪圖片的工具了


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM