[Android] 詳細解說Android裁剪(ex頭像),以及照片檔案過大無法返回,改使用uri方法,裁剪Crop,com.android.camera.action.CROP
問題:
前陣子使用Android 裁剪照片的函式,由於Android對於裁剪com.android.camera.action.CROP
沒有寫得很清楚,後來研究了一下才發現有些圖片可以切,有些卻因為檔案過大無法返回,
網路上抄來抄去真的return-data幾乎都是true,
Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);
intent.setType(“image/*”);
intent.putExtra(“crop”, “true”);
但是這用來切頭像 200x200以內的圖片是絕對可行的,因為檔案不大,
但用來切大照片,有可能因為超過傳回內存的容量16MB,絕對會有問題
原因是因為Android允許你使用return-data拿資料回來,再用(Bitmap)extras.getParcelable("data")拿到圖片
但這個方法檔案太大你就掰掰了,除非你限制user的檔案很小.
但通常你要裁剪多半都是照片
解決辦法:
不要讓Intent帶檔案回來給我們,改成我們自己創建檔案,使用uri方法去連結他
以下示範一個切成4比3的圖片
Uri uri2 = null ;
private void crop(Uri uri) {
// 裁剪圖片意圖
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(uri, "image/*");
intent.putExtra("crop", "true");
// 裁剪框的比例,4:3
intent.putExtra("aspectX", 4);
intent.putExtra("aspectY", 3);
// 裁剪後輸出圖片的尺寸大小
//intent.putExtra("outputX", 1080);
//intent.putExtra("outputY", 810); //像這個太大如果使用true,記憶體不夠就會出錯
intent.putExtra("outputFormat", "JPEG");// 圖片格式
//intent.putExtra("noFaceDetection", true);// 取消人臉識別
intent.putExtra("return-data", false);
// 開啟一個帶有返回值的Activity,請求碼為PHOTO_REQUEST_CUT
String localTempImgDir="Hello";
String localTempImgFileName = System.currentTimeMillis()+".jpg";
File f=new File(Environment.getExternalStorageDirectory()
+"/"+localTempImgDir+"/"+localTempImgFileName);
uri2 = Uri.fromFile(f); //用這個uri去做事
//intent.putExtra(MediaStore.Images.Media.ORIENTATION, 0);
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri2);
把他連結到uri2,如此返回時便可使用此uri2做事
//Toast.makeText( photoActivity.this, "targetUri ="+targetUri, Toast.LENGTH_SHORT ).show();
selectedImagePath = f.getAbsolutePath();
Log.w("TAG", "selectedImagePath:" + selectedImagePath);
View1.setText("selectedImagePath:"+selectedImagePath);
mImageUri = Uri.fromFile(f);
strImage = f.getAbsolutePath();
Log.w("TAG", "f.getAbsolutePath():"+ f.getAbsolutePath());
startActivityForResult(intent, PHOTO_REQUEST_CUT);
}
如此便解決了我大圖片一直無法返回,但圖片正確創立,也能正確顯示到圖片的問題!!
成功測試各種 相簿選取/拍照 的裁剪都能正常使用 如下圖
尚未選圖片時
選取挑圖片的程式
此處已挑好圖片以後,再跳出裁剪照片
選取裁剪範圍
成功將檔案由uri找到並set在imageView上
問題解決引用自:
http://www.linuxidc.com/Linux/2012-11/73939p2.htm
Crop String 發送裁剪信號
aspectX int X方向上的比例
aspectY int Y方向上的比例
outputX int 裁剪區的寬
outputY int 裁剪區的高
scale Boolean 是否保留比例
return-data Boolean 是否將資料保留在Bitmap中返回
data Parcelable相應的Bitmap資料
MediaStore.EXTRA_OUTPUT ("output")URI將URI指向相應的file:///...
這裡ex: intent.putExtra(MediaStore.EXTRA_OUTPUT, uri2);
方法1:如果你將return-data設置為“true”,你將會獲得一個與內部資料關聯的Action,並且bitmap以此方式返回:(Bitmap)extras.getParcelable("data")。注意:如果你最終要獲取的圖片非常大,那麼此方法會給你帶來麻煩,所以你要控制outputX和outputY保持在較小的尺寸。鑒於此原因,在我的代碼中沒有使用此方法((Bitmap)extras.getParcelable("data"))。
下麵是CropImage.java的源碼片段:
// Return the cropped image directly or save it to the specified URI.
Bundle myExtras = getIntent().getExtras();
if (myExtras != null && (myExtras.getParcelable("data") != null || myExtras.getBoolean("return-data")))
{
Bundle extras = new Bundle();
extras.putParcelable("data", croppedImage);
setResult(RESULT_OK,(new Intent()).setAction("inline-data").putExtras(extras));
finish();
}
方法2:如果你將return-data設置為“false”,那麼在onActivityResult的Intent資料中你將不會接收到任何Bitmap,相反,你需要將MediaStore.EXTRA_OUTPUT關聯到一個Uri,此Uri是用來存放Bitmap的。
但是還有一些條件,首先你需要有一個短暫的與此Uri相關聯的檔位址,當然這不是個大問題(除非是那些沒有sdcard的設備)。
下麵是CropImage.java關於操作Uri的源碼片段:
if (mSaveUri != null) {
OutputStream outputStream = null;
try {
outputStream = mContentResolver.openOutputStream(mSaveUri);
if (outputStream != null) {
croppedImage.compress(mOutputFormat, 75, outputStream);
}
} catch (IOException ex) {
// TODO: report error to caller
Log.e(TAG, "Cannot open file: " + mSaveUri, ex);
} finally {
Util.closeSilently(outputStream);
}
Bundle extras = new Bundle();
setResult(RESULT_OK, new Intent(mSaveUri.toString()).putExtras(extras));
}