Android 拍照或選擇圖片并剪裁
在Android平常開發中拍照、選擇圖片并裁剪幾乎是每個App所必須的功能,因為不同版本Android選擇圖片后返回處理方式不同,再加上不同品牌手機對Android系統的深度定制,導致App在使用Android原生圖片處理上或多或少出現一些問題,像微信、QQ這種用戶受眾范圍廣對平臺兼容性高的App它們都有一套自定義圖片選擇器,今天這篇文章主要整理一下Android使用原生控件拍照、選擇圖片以及拍照后裁剪或者選擇圖片后裁剪相關功能。
選擇圖片
在Android4.4之前一般選擇圖片都是使用下面方式,然后我們通過onActivityResult()方法通過Intent獲得選擇圖片的Uri,使用ContentResolver拿到圖片的絕對路徑就可以了。
Intentintent = new Intent();
intent.setAction(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("image/*");
startActivityForResult(intent, IMAGE_SELECT);
但是在Android4.4以及更高的版本部分手機上面選擇圖片會拿不到正確的Uri,多數手機我們拿到的一個Uri如下:
content://media/external/images/media/258779
在部分Android4.4以上的手機我們拿到的Uri是如下格式:
content://com.android.providers.media.documents/document/image%3A256478
這種格式我們通過ContentResolver就拿不到到媒體數據庫中圖片的絕對路徑了,在Android的4.4及其以上可以使用如下方式:
Intentintent = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,"image/*");
startActivityForResult(intent, IMAGE_SELECT);
經過驗證在低于4.4的版本上面也可以正確獲取到圖片的Uri。
拿到圖片的絕對路徑如何顯示圖片在本篇博客中就不介紹了,可以使用第三方庫,也可以自己使用BitmapFactory.Options來加載圖片防止OOM。
選擇圖片并裁剪
在Android原生應用中裁剪圖片事實上就是使用自帶應用Media Gallery裁剪的,通過Intent來帶回我們想要的數據的。下面是使用Intent剪裁圖片時可以攜帶的屬性:
附加選項 | 數據類型 | 描述 |
---|---|---|
crop | String | 發送裁剪信號 |
aspectX | int | X方向上的比例 |
aspectY | int | Y方向上的比例 |
outputX | int | 裁剪區的寬 |
outputY | int | 裁剪區的高 |
scale | boolean | 是否保留比例 |
return-data | boolean | 是否將數據保留在Bitmap中返回 |
data | Parcelable | 相應的Bitmap數據 |
circleCrop | String | 圓形裁剪區域? |
noFaceDetection | boolean | 是否人臉識別? |
MediaStore.EXTRA_OUTPUT | Uri | 將URI指向相應的file:///…,詳見代碼示例 |
為了得到我們需要的數據有兩個選項是需要重點關注的return-data和MediaStore.EXTRA_OUTPUT,這兩個選項是互不影響的,一般情況下如果我們需要返回的圖片很小可以直接使用return-data返回的數據,return-data將會直接返回一個Bitmap。但是如果要求的圖片很大此時我們要使用MediaStore.EXTRA_OUTPUT,該屬性是將圖片輸入一個指定的Uri,如果對Uri了解的話,應該知道Uri與File相似,裁剪后將數據就保存在了指定Uri所指向的目標文件中。
有
些文章中建議說如果是小圖就使用return-data,大圖就使用MediaStore.EXTRA_OUTPUT返回一個指定Uri,但是多數開發中我們都要同服務器交互,將修改后的圖片上傳至服務器端,所以個人認為不管什么情況下我們直接返回一個Uri最為方面,上傳圖片時可以根據Uri通過ContentResolver獲取圖片路徑,或者直接創建一個文件將裁剪后的數據直接輸入到指定文件中,這種情況下我們可以直接知道自己創建文件的路徑。
裁剪后直接獲取圖片
Intentintent = new Intent(Intent.ACTION_GET_CONTENT, null);
intent.setType("image/*");
intent.putExtra("crop", "true");
intent.putExtra("aspectX", 2);
intent.putExtra("aspectY", 2);
intent.putExtra("outputX", 200);
intent.putExtra("outputY", 100);
intent.putExtra("scale", true);
intent.putExtra("return-data", true);
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
intent.putExtra("noFaceDetection", true); // no face detection
startActivityForResult(intent, IMAGE_CROP);
在onActivityResult方法中獲取返回的Bitmap并顯示方式如下:
Bitmapbitmap = data.getParcelableExtra("data");
imageView.setImageBitmap(bitmap);
裁剪后返回Uri
裁剪后將圖片放入指定Uri的文件路徑,我們可以先創建一個文件,然后將裁剪后的數據輸入該文件:
private FilecreateImageFile() throws IOException {
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss")
.format(new Date());
String imageFileName = "JPEG_" + timeStamp + "_";
Fileimage = File.createTempFile(imageFileName, ".jpg",
Environment.getExternalStorageDirectory());
return image;
}
然后我們裁剪圖片時通過MediaStore.EXTRA_OUTPUT將數據存入指定Uri。
FilephotoFile = createImageFile();
path=photoFile.getAbsolutePath();
Intentintent = new Intent(Intent.ACTION_GET_CONTENT, null);
intent.setType("image/*");
intent.putExtra("crop", "true");
intent.putExtra("aspectX", 2);
intent.putExtra("aspectY", 2);
intent.putExtra("outputX", 200);
intent.putExtra("outputY", 200);
intent.putExtra("scale", true);
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile));
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
intent.putExtra("noFaceDetection", true); // no face detection
startActivityForResult(intent, IMAGE_CROP);
這里我們有一個全局的變量用于存放自己裁剪文件的絕對路徑,拿到圖片絕對路徑如何顯示圖片就很容易了。
Bitmapbm=BitmapFactory.decodeFile(path);
imageView.setImageBitmap(bm);
拍照后顯示圖片
在應用中我們要上傳圖片一般都會有拍照或者從相冊選擇兩個選項,調用相機并返回拍照后的圖片也是每個Android開發者所必須掌握的。但是我們發現現在的手機拍照后都特別大,一個普通的手機分別率是720*1280,但是拍出的照片竟然達到了3264*2448,文件大小接近3M。但是如果讀入內存又有多大呢?若Bitmap類型是ARGB_8888,也就意味著一個像素點占用4個字節的內存,簡單計算一下:3264*2448*4=30.48M,也就是說拍照后我們查看一下圖片就會占用系統30M內存,但是在更早版本的Android手機中系統為每一個應用分配使用的最大內存才有16M,拍個照就會直接導致OOM。但是事實上我們拍照并不會引起OOM,這是因為Android系統會默認返回給我們一張縮略圖,每次拍過照后系統會自動生成一張縮略圖,而且還提供了一個類android.media.ThumbnailUtils,該類專門用于獲取系統中的視頻或圖片文件的縮略圖。
拍照獲取縮略圖
IntenttakePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE, null);
startActivityForResult(takePictureIntent, CODE);
在onActivityResult方法中獲取返回的Bitmap并顯示方式如下:
protected void onActivityResult(int requestCode, int resultCode, Intentdata) {
if (resultCode == RESULT_OK&&requestCode==CODE) {
Bundleextras = data.getExtras();
Bitmapbm = (Bitmap) extras.get("data"); //height為175
imageView.setImageBitmap(bm);
}
}
拍照后存入指定路徑
與上面圖片裁剪實現方式類似,我們可以預先新建一個文件,然后使用MediaStore.EXTRA_OUTPUT將圖片存入該路徑。使用該種方式我們會發現 在onActivityResult方法中獲取不到Intent了,Intent直接返回null。
IntenttakePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE,
null);
FilephotoFile = createImageFile();
if (photoFile != null) {
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,
Uri.fromFile(photoFile));
}
startActivityForResult(takePictureIntent, CODE);
參考資料
Android_照相機Camera_調用系統照相機返回data為空
來自:http://www.sunnyang.com/594.html