Android相機、相冊獲取圖片,解決相機拍照圖片被壓縮模糊的情況

如題,這個需求本不是一個很複雜的過程,但是卻存在一些隱患,我也是最近在項目中碰到這個問題,將Android通過相機或相冊獲取圖片並最終顯示在界面上做了一個小研究,現將一些結果和附上的一個Demo敘述如下:

做過類似需求的同學都知道,在Activity中通過如下代碼可以啓動相機,然後在重寫的onActivityResult方法中可以獲取到返回的照片數據:

[java] view plaincopy
  1. Intent openCameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);  
  2. startActivityForResult(openCameraIntent, TAKE_PICTURE);  

問題來了,不知大家是否有發現,在onActivityResult方法裏通過Intent的getData方法獲取的數據轉換成bitmap並顯示在界面上,有時候會有取不到數據,或者顯示的bitmap會非常小,如果將bitmap保存到sd卡後會發現,圖片的分辨率很低,並且圖片大小也是經過壓縮的,不管將相機的像素設置多高,最後通過這種方式返回的bitmap總是經過壓縮了的。如果想獲得理想的照片大小和分辨率改如何處理呢?以下是我的處理方法,雖然不是最好,但是幫我解決了這個需求。我先來簡述一下爲什麼返回的圖片是經過了壓縮的。

大家都知道,現在手機像素少則500W或800W,多則4KW(某亞),就拿常見的800W像素的相機拍出來的照片來說,分辨率大概在3200*2400左右,我的測試機型是LG optimus 2x,2.3.7的系統,用800W像素拍出來大概就是這個分辨率,照片大小在2M左右。試想一下,在Android系統中bitmap佔用4個字節,3200*2400*4=?,結果大家自己算算,如果爲了一張圖片,耗用這麼大的內存,肯定是不合理的,並且,官方文檔中有說明,Android系統分配給每個應用的最大內存是16M,所以,系統爲了防止應用內存佔用過大,對於在應用內通過相機拍攝的圖片最終返回來的結果進行了壓縮,壓縮後的圖片變得很小,通過之前說的getData的方式只能滿足比如顯示個頭像這樣的需求,如果要顯示大圖,就會出現模糊的情況。那如何獲取清晰的大圖呢?我的解決思路如下:

1.拍照時,將拍得的照片先保存在本地,通過修改之前的代碼如下:

[java] view plaincopy
  1. Uri imageUri = Uri.fromFile(new File(Environment.getExternalStorageDirectory(),"image.jpg"));  
  2. //指定照片保存路徑(SD卡),image.jpg爲一個臨時文件,每次拍照後這個圖片都會被替換  
  3. openCameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);  

2.在onActivityResult方法中再將圖片取出,並經過縮小處理再顯示在界面上或上傳給服務器(壓縮比例自定義)

[java] view plaincopy
  1. @Override  
  2.     protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
  3.         super.onActivityResult(requestCode, resultCode, data);  
  4.         if (resultCode == RESULT_OK) {  
  5.             switch (requestCode) {  
  6.             case TAKE_PICTURE:  
  7.                 //將保存在本地的圖片取出並縮小後顯示在界面上  
  8.                 Bitmap bitmap = BitmapFactory.decodeFile(Environment.getExternalStorageDirectory()+"/image.jpg");  
  9.                 Bitmap newBitmap = ImageTools.zoomBitmap(bitmap, bitmap.getWidth() / SCALE, bitmap.getHeight() / SCALE);  
  10.                 //由於Bitmap內存佔用較大,這裏需要回收內存,否則會報out of memory異常  
  11.                 bitmap.recycle();  
  12.                   
  13.                 //將處理過的圖片顯示在界面上,並保存到本地  
  14.                 iv_image.setImageBitmap(newBitmap);  
  15.                 ImageTools.savePhotoToSDCard(newBitmap, Environment.getExternalStorageDirectory().getAbsolutePath(), String.valueOf(System.currentTimeMillis()));  
  16.                 break;  
  17.             default:  
  18.                 break;  
  19.             }  
  20.         }  
  21.     }  

由於Android給bitmap分配的內存最大不超過8M,所以對使用完的較大的Bitmap要釋放內存,調用其recycle()方法即可。然後將縮小(縮小方法在Demo源碼中有)後的bitmap顯示在界面上或保存到SD卡,至於之前保存的原圖,可以刪掉,也可以放在那,下次拍照時,這張原圖就會被下一張照片覆蓋,所以SD卡上使用只有一張臨時圖片,佔用也不是很大。


以上講的是拍照獲取圖片,如果是從相冊中獲取圖片又如何處理呢,我的方法如下:

1.打開相冊選取圖片

[java] view plaincopy
  1. Intent openAlbumIntent = new Intent(Intent.ACTION_GET_CONTENT);  
  2.                     openAlbumIntent.setType("image/*");  
  3.                     startActivityForResult(openAlbumIntent, CHOOSE_PICTURE);  

2.在onActivity方法中處理獲取到的圖片,思路和之前類似

[java] view plaincopy
  1. @Override  
  2.     protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
  3.         super.onActivityResult(requestCode, resultCode, data);  
  4.         if (resultCode == RESULT_OK) {  
  5.             switch (requestCode) {  
  6.             case CHOOSE_PICTURE:  
  7.                 ContentResolver resolver = getContentResolver();  
  8.                 //照片的原始資源地址  
  9.                 Uri originalUri = data.getData();   
  10.                 try {  
  11.                     //使用ContentProvider通過URI獲取原始圖片  
  12.                     Bitmap photo = MediaStore.Images.Media.getBitmap(resolver, originalUri);  
  13.                     if (photo != null) {  
  14.                         //爲防止原始圖片過大導致內存溢出,這裏先縮小原圖顯示,然後釋放原始Bitmap佔用的內存  
  15.                         Bitmap smallBitmap = ImageTools.zoomBitmap(photo, photo.getWidth() / SCALE, photo.getHeight() / SCALE);  
  16.                         //釋放原始圖片佔用的內存,防止out of memory異常發生  
  17.                         photo.recycle();  
  18.                           
  19.                         iv_image.setImageBitmap(smallBitmap);  
  20.                     }  
  21.                 } catch (FileNotFoundException e) {  
  22.                     e.printStackTrace();  
  23.                 } catch (IOException e) {  
  24.                     e.printStackTrace();  
  25.                 }    
  26.                 break;  
  27.               
  28.             default:  
  29.                 break;  
  30.             }  
  31.         }  
  32.     }  


運行截圖(個人夏天靚照一張大笑):


這一篇就講述了由一個需求所發現的一個問題,並結合我的解決方法,歡迎有更好方法的同學指出並相互交流!


Demo下載地址:點擊下載


對Android&IOS感興趣的朋友可以加入我們的討論QQ羣,在這裏,我們只討論乾貨:

iOS羣:220223507

Android羣:282552849


覺得文章對你有用,點擊右下角的轉發按鈕分享給更多人!

同時歡迎關注我的新浪微博和我交流:@唐韌_Ryan


《Android拍照、相冊選取、裁剪圖片綜合Demo》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章