1. 程式人生 > >Android uri轉Bitmap

Android uri轉Bitmap

很多人在呼叫相簿選擇圖片時會在onActivityResult中用Media.getBitmap來獲取返回的圖片,如下:

  1. Uri mImageCaptureUri = data.getData();  
  2. Bitmap photoBmp = null;  
  3. if (mImageCaptureUri != null) {  
  4.     photoBmp = MediaStore.Images.Media.getBitmap(ac.getContentResolver(), mImageCaptureUri);  
  5. }  

但是Media.getBitmap這個方法獲取已知uri圖片的方式並不可取,咱來看看Media.getBitmap()方法的原始碼:

  1. publicstaticfinal Bitmap getBitmap(ContentResolver cr, Uri url)  
  2.         throws FileNotFoundException, IOException {  
  3.     InputStream input = cr.openInputStream(url);  
  4.     Bitmap bitmap = BitmapFactory.decodeStream(input);  
  5.     input.close();  
  6.     return bitmap;  
  7. }  

其實它很簡單很粗暴,返回的是原始大小的bitmap,當相簿選擇的圖片很大時程式極有可能會報OOM。

為了避免OOM,咱們需要改進該方法,在 BitmapFactory.decodeStream 之前壓縮圖片,以下是我改進後的程式碼:

在onActivityResult中呼叫

  1. Uri mImageCaptureUri = data.getData();  
  2. Bitmap photoBmp = null;  
  3. if (mImageCaptureUri != null) {  
  4. photoBmp = getBitmapFormUri(ac, mImageCaptureUri);  
  5. }  

  1. /** 
  2.      * 通過uri獲取圖片並進行壓縮 
  3.      * 
  4.      * @param uri
     
  5.      */
  6.     publicstatic Bitmap getBitmapFormUri(Activity ac, Uri uri) throws FileNotFoundException, IOException {  
  7.         InputStream input = ac.getContentResolver().openInputStream(uri);  
  8.         BitmapFactory.Options onlyBoundsOptions = new BitmapFactory.Options();  
  9.         onlyBoundsOptions.inJustDecodeBounds = true;  
  10.         onlyBoundsOptions.inDither = true;//optional
  11.         onlyBoundsOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;//optional
  12.         BitmapFactory.decodeStream(input, null, onlyBoundsOptions);  
  13.         input.close();  
  14.         int originalWidth = onlyBoundsOptions.outWidth;  
  15.         int originalHeight = onlyBoundsOptions.outHeight;  
  16.         if ((originalWidth == -1) || (originalHeight == -1))  
  17.             returnnull;  
  18.         //圖片解析度以480x800為標準
  19.         float hh = 800f;//這裡設定高度為800f
  20.         float ww = 480f;//這裡設定寬度為480f
  21.         //縮放比。由於是固定比例縮放,只用高或者寬其中一個數據進行計算即可
  22.         int be = 1;//be=1表示不縮放
  23.         if (originalWidth > originalHeight && originalWidth > ww) {//如果寬度大的話根據寬度固定大小縮放
  24.             be = (int) (originalWidth / ww);  
  25.         } elseif (originalWidth < originalHeight && originalHeight > hh) {//如果高度高的話根據寬度固定大小縮放
  26.             be = (int) (originalHeight / hh);  
  27.         }  
  28.         if (be <= 0)  
  29.             be = 1;  
  30.         //比例壓縮
  31.         BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();  
  32.         bitmapOptions.inSampleSize = be;//設定縮放比例
  33.         bitmapOptions.inDither = true;//optional
  34.         bitmapOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;//optional
  35.         input = ac.getContentResolver().openInputStream(uri);  
  36.         Bitmap bitmap = BitmapFactory.decodeStream(input, null, bitmapOptions);  
  37.         input.close();  
  38.         return compressImage(bitmap);//再進行質量壓縮
  39.     }  

  1. /** 
  2.     * 質量壓縮方法 
  3.     * 
  4.     * @param image 
  5.     * @return 
  6.     */
  7.    publicstatic Bitmap compressImage(Bitmap image) {  
  8.        ByteArrayOutputStream baos = new ByteArrayOutputStream();  
  9.        image.compress(Bitmap.CompressFormat.JPEG, 100, baos);//質量壓縮方法,這裡100表示不壓縮,把壓縮後的資料存放到baos中
  10.        int options = 100;  
  11.        while (baos.toByteArray().length / 1024 > 100) {  //迴圈判斷如果壓縮後圖片是否大於100kb,大於繼續壓縮
  12.            baos.reset();//重置baos即清空baos
  13.            //第一個引數 :圖片格式 ,第二個引數: 圖片質量,100為最高,0為最差  ,第三個引數:儲存壓縮後的資料的流
  14.            image.compress(Bitmap.CompressFormat.JPEG, options, baos);//這裡壓縮options%,把壓縮後的資料存放到baos中
  15.            options -= 10;//每次都減少10
  16.        }  
  17.        ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());//把壓縮後的資料baos存放到ByteArrayInputStream中
  18.        Bitmap bitmap = BitmapFactory.decodeStream(isBm, nullnull);//把ByteArrayInputStream資料生成圖片
  19.        return bitmap;  
  20.    }  

OOM的問題解決了,但是又碰到另外一個問題,用三星手機拍照或者選擇照片後返回來的圖片居然轉了90度,接著改。

在onActivityResult中的程式碼進行改進:

  1. Uri originalUri = null;  
  2.       File file = null;  
  3.       if (null != data && data.getData() != null) {  
  4.           originalUri = data.getData();  
  5.           file = getFileFromMediaUri(ac, originalUri);  
  6.       }  
  7.  Bitmap photoBmp = getBitmapFormUri(ac, Uri.fromFile(file));  
  8.   int degree = getBitmapDegree(file.getAbsolutePath());  
  9.   /** 
  10.    * 把圖片旋轉為正的方向 
  11.    */
  12.   Bitmap newbitmap = rotateBitmapByDegree(photoBmp, degree);  

  1. /** 
  2.      * 通過Uri獲取檔案 
  3.      * @param ac 
  4.      * @param uri 
  5.      * @return 
  6.      */
  7.     publicstatic File getFileFromMediaUri(Context ac, Uri uri) {  
  8.         if(uri.getScheme().toString().compareTo("content") == 0){  
  9.             ContentResolver cr = ac.getContentResolver();  
  10.             Cursor cursor = cr.query(uri, nullnullnullnull);// 根據Uri從資料庫中找
  11.             if (cursor != null) {  
  12.                 cursor.moveToFirst();  
  13.                 String filePath = cursor.getString(cursor.getColumnIndex("_data"));// 獲取圖片路徑
  14.                 cursor.close();  
  15.                 if (filePath != null) {  
  16.                     returnnew File(filePath);  
  17.                 }  
  18.             }  
  19.         }elseif(uri.getScheme().toString().compareTo("file") == 0){  
  20.             returnnew File(uri.toString().replace("file://",""));  
  21.         }  
  22.             returnnull;  
  23.         }  


  1. /** 
  2.      * 讀取圖片的旋轉的角度 
  3.      * 
  4.      * @param path 圖片絕對路徑 
  5.      * @return 圖片的旋轉角度 
  6.      */
  7.     publicstaticint getBitmapDegree(String path) {  
  8.         int degree = 0;  
  9.         try {  
  10.             // 從指定路徑下讀取圖片,並獲取其EXIF資訊
  11.             ExifInterface exifInterface = new ExifInterface(path);  
  12.             // 獲取圖片的旋轉資訊
  13.             int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION,  
  14.                     ExifInterface.ORIENTATION_NORMAL);  
  15.             switch (orientation) {  
  16.                 case ExifInterface.ORIENTATION_ROTATE_90:  
  17.                     degree = 90;  
  18.                     break;  
  19. 相關推薦

    Android uriBitmap

    很多人在呼叫相簿選擇圖片時會在onActivityResult中用Media.getBitmap來獲取返回的圖片,如下: Uri mImageCaptureUri = data.getData();   Bitmap photoBmp = null;   if (

    android view Bitmap 生成截圖

    directory ora ESS 使用 stack return android 簡易 ref 文章鏈接:https://mp.weixin.qq.com/s/FQmYfT-KYiDbp-0HzK_Hpw 項目中經常會用到分享的功能,有分享鏈接也有分享圖片,其中分享圖

    根據Android Uri獲取Bitmap物件實現

    通常我們在選取圖片的時候在onActivityResult回撥中呼叫intent.getData()拿到uri物件。下面來講解如何根據這個uri獲取到Bitmap物件。 首先,在Android的API中有一個MediaStore.Images.Media類,這個類有一個getBitmap靜態方法用

    Android uri真實路徑。

    在華為手機上選擇圖片的時候。拿到一個這樣的路徑:(華為手機進開啟相簿-》下載內容-》browser-》圖片收藏-》選擇圖片) content://com.android.providers.downloads.documents/document/raw:/storage/

    Android--Uri實際路徑詳解

    通過Uri得到實際路徑,網上方法有很多,但我前幾天試了一下,發現返回的值都是null,後來才發現,Uri的格式在Android4.4之後有了很大的改動。 content://media/extenral/images/media/17766(4.4前)

    Android 小筆記 Uri獲取絕對路徑 、路徑Bitmap、獲取螢幕截圖

    1. Uri獲取絕對路徑 public static String getRealPathFromURI(Context mContext, Uri contentUri) { St

    android 路徑地址與Uri的相互轉換 uristring

    一個android檔案的Uri地址一般如下: content://media/external/images/media/62026 這是一張圖片的Uri,那麼我們如何根據這個Uri獲得其在檔案系統中的路徑呢? 其實很簡單,直接上程式碼: /** * Try t

    Android 自定義ViewBitmap

    最近在最CAD圖,需要建立完對相應的裝置然後儲存一份截圖,思前想後還是把自定義的View轉為Bitmap 的方法,我自定義的是SurfaceView 上程式碼吧: /** * view轉Bitmap * @param mGraphyView SurfaceV

    android】應用圖示DrawableBitmap,適配安卓8.0

    相信大家在載入應用圖示的時候,經常會將得到的Drawable轉成Bitmap,程式碼如下: Drawable drawable = mPackageManager.getApplicationIcon(packageName); return ((BitmapDrawable) drawabl

    Android儲存ViewBitmap併到本地相簿實時更新

    最開始我想的是截圖儲存更方便,但很醜,於是查了下資料。不到30分鐘就弄出來了,很順利,還是感謝那些開源分享的大神們 遇到沒做過的,先思考,再動手找解決辦法。哈哈。下面是我專案中的的程式碼,可以參考 private void save(final LinearLayou

    Android網路URL圖片地址Bitmap並且儲存到本地

    一、網路URL圖片地址轉Bitmap public Bitmap getBitmap(String imgUrl) { InputStream inputStream=null;

    Android開發】View Bitmap

    public static Bitmap loadBitmapFromView(View v) { int w = v.getWidth(); int h = v.getHeight(); Bitmap bmp = Bitmap.createBitmap(w,

    Android 中 資原始檔圖片 Bitmap 和 Drawable 以及相互轉換的方法

    Android 圖片轉換的方法總結: 一、Bitmap 轉換成 Drawable 對 Bitmap 進行強制轉換 Drawable drawable = new BitmapDrawable(bmp); 二、Drawable 轉換成 Bitmap 方法一 通過 BitmapFa

    Android 根據網路圖片URLBitmap物件

    /** * 根據圖片的url路徑獲得Bitmap物件 * @param url * @return */ private Bitmap returnBitmap(String url) {

    android 通過uri獲取bitmap圖片並壓縮

    很多人在呼叫相簿選擇圖片時會在onActivityResult中用Media.getBitmap來獲取返回的圖片,如下: Uri mImageCaptureUri = data.getData(); Bitmap photoBmp = null; if (mImageCap

    從零開始學android&lt;Bitmap圖形組件.四十七.&gt;

    alt getheight drawtext layout pla cin mas 簡單 制圖 android.graphics.Bitmap(位圖)是Android手機中專門提供的用於操作圖片資源的操作類,使用此類能夠直接從資源文件之中進行圖片資源的讀取。而且對這些圖

    Android百度地圖Sha1獲取正確姿勢?

    views num adl 定位 提示 合作 動態 例如 登錄 場景一 由於近期項目鐘要用到定位功能因此肯定須要用到地圖以及地位功能,相信大家也知道眼下國內比較出名的地圖像百度、高德、騰訊等這些還是用到比較多的。於是思考了一下決定還是用百

    Android系統選擇本地視頻的功能

    選擇 打開文件 result 打開圖片 provide ati 迷你 nal 名稱   今天在項目開發的過程中產品要求添加選擇本地視頻的功能,於是就翻閱和查找各種資料,進行功能的開發,但是在開發過程中發現,各種不同的品牌的手機跳轉至系統選擇本地視頻的功能結果不太一樣,所以我

    Android各種系統設置界面-總結

    圖片 有一種 div ref hive email 安全 www. too 來自:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2017/0921/8536.html View btn1 = th

    Android手動回收bitmap,引發Canvas: trying to use a recycled bitmap處理

    contex highlight 比較 spa 代碼 soft use itl port 在做Android的開發的時候,在ListView 或是 GridView中需要加載大量的圖片,為了避免加載過多的圖片引起OutOfMemory錯誤,設置了一個圖片緩存列表 Map&l