詳解android 通過(guò)uri獲取bitmap圖片并壓縮
詳解android 通過(guò)uri獲取bitmap圖片并壓縮
很多人在調(diào)用圖庫(kù)選擇圖片時(shí)會(huì)在onActivityResult中用Media.getBitmap來(lái)獲取返回的圖片,如下:
Uri mImageCaptureUri = data.getData(); Bitmap photoBmp = null; if (mImageCaptureUri != null) { photoBmp = MediaStore.Images.Media.getBitmap(ac.getContentResolver(), mImageCaptureUri); }
但是Media.getBitmap這個(gè)方法獲取已知uri圖片的方式并不可取,咱來(lái)看看Media.getBitmap()方法的源碼:
public static final Bitmap getBitmap(ContentResolver cr, Uri url) throws FileNotFoundException, IOException { InputStream input = cr.openInputStream(url); Bitmap bitmap = BitmapFactory.decodeStream(input); input.close(); return bitmap; }
其實(shí)它很簡(jiǎn)單很粗暴,返回的是原始大小的bitmap,當(dāng)圖庫(kù)選擇的圖片很大時(shí)程序極有可能會(huì)報(bào)OOM。
為了避免OOM,咱們需要改進(jìn)該方法,在 BitmapFactory.decodeStream 之前壓縮圖片,以下是我改進(jìn)后的代碼:
在onActivityResult中調(diào)用
Uri mImageCaptureUri = data.getData(); Bitmap photoBmp = null; if (mImageCaptureUri != null) { photoBmp = getBitmapFormUri(ac, mImageCaptureUri); }
/** * 通過(guò)uri獲取圖片并進(jìn)行壓縮 * * @param uri */ public static Bitmap getBitmapFormUri(Activity ac, Uri uri) throws FileNotFoundException, IOException { InputStream input = ac.getContentResolver().openInputStream(uri); BitmapFactory.Options onlyBoundsOptions = new BitmapFactory.Options(); onlyBoundsOptions.inJustDecodeBounds = true; onlyBoundsOptions.inDither = true;//optional onlyBoundsOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;//optional BitmapFactory.decodeStream(input, null, onlyBoundsOptions); input.close(); int originalWidth = onlyBoundsOptions.outWidth; int originalHeight = onlyBoundsOptions.outHeight; if ((originalWidth == -1) || (originalHeight == -1)) return null; //圖片分辨率以480x800為標(biāo)準(zhǔn) float hh = 800f;//這里設(shè)置高度為800f float ww = 480f;//這里設(shè)置寬度為480f //縮放比。由于是固定比例縮放,只用高或者寬其中一個(gè)數(shù)據(jù)進(jìn)行計(jì)算即可 int be = 1;//be=1表示不縮放 if (originalWidth > originalHeight && originalWidth > ww) {//如果寬度大的話(huà)根據(jù)寬度固定大小縮放 be = (int) (originalWidth / ww); } else if (originalWidth < originalHeight && originalHeight > hh) {//如果高度高的話(huà)根據(jù)寬度固定大小縮放 be = (int) (originalHeight / hh); } if (be <= 0) be = 1; //比例壓縮 BitmapFactory.Options bitmapOptions = new BitmapFactory.Options(); bitmapOptions.inSampleSize = be;//設(shè)置縮放比例 bitmapOptions.inDither = true;//optional bitmapOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;//optional input = ac.getContentResolver().openInputStream(uri); Bitmap bitmap = BitmapFactory.decodeStream(input, null, bitmapOptions); input.close(); return compressImage(bitmap);//再進(jìn)行質(zhì)量壓縮 }
/** * 質(zhì)量壓縮方法 * * @param image * @return */ public static Bitmap compressImage(Bitmap image) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); image.compress(Bitmap.CompressFormat.JPEG, 100, baos);//質(zhì)量壓縮方法,這里100表示不壓縮,把壓縮后的數(shù)據(jù)存放到baos中 int options = 100; while (baos.toByteArray().length / 1024 > 100) { //循環(huán)判斷如果壓縮后圖片是否大于100kb,大于繼續(xù)壓縮 baos.reset();//重置baos即清空baos //第一個(gè)參數(shù) :圖片格式 ,第二個(gè)參數(shù): 圖片質(zhì)量,100為最高,0為最差 ,第三個(gè)參數(shù):保存壓縮后的數(shù)據(jù)的流 image.compress(Bitmap.CompressFormat.JPEG, options, baos);//這里壓縮options%,把壓縮后的數(shù)據(jù)存放到baos中 options -= 10;//每次都減少10 } ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());//把壓縮后的數(shù)據(jù)baos存放到ByteArrayInputStream中 Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);//把ByteArrayInputStream數(shù)據(jù)生成圖片 return bitmap; }
OOM的問(wèn)題解決了,但是又碰到另外一個(gè)問(wèn)題,用三星手機(jī)拍照或者選擇照片后返回來(lái)的圖片居然轉(zhuǎn)了90度。??啾频腶ndroid程序員。。接著改。。
講onActivityResult中的代碼進(jìn)行改進(jìn):
Uri originalUri = null; File file = null; if (null != data && data.getData() != null) { originalUri = data.getData(); file = getFileFromMediaUri(ac, originalUri); } Bitmap photoBmp = getBitmapFormUri(ac, Uri.fromFile(file)); int degree = getBitmapDegree(file.getAbsolutePath()); /** * 把圖片旋轉(zhuǎn)為正的方向 */ Bitmap newbitmap = rotateBitmapByDegree(photoBmp, degree);
/** * 通過(guò)Uri獲取文件 * @param ac * @param uri * @return */ public static File getFileFromMediaUri(Context ac, Uri uri) { if(uri.getScheme().toString().compareTo("content") == 0){ ContentResolver cr = ac.getContentResolver(); Cursor cursor = cr.query(uri, null, null, null, null);// 根據(jù)Uri從數(shù)據(jù)庫(kù)中找 if (cursor != null) { cursor.moveToFirst(); String filePath = cursor.getString(cursor.getColumnIndex("_data"));// 獲取圖片路徑 cursor.close(); if (filePath != null) { return new File(filePath); } } }else if(uri.getScheme().toString().compareTo("file") == 0){ return new File(uri.toString().replace("file://","")); } return null; }
/** * 讀取圖片的旋轉(zhuǎn)的角度 * * @param path 圖片絕對(duì)路徑 * @return 圖片的旋轉(zhuǎn)角度 */ public static int getBitmapDegree(String path) { int degree = 0; try { // 從指定路徑下讀取圖片,并獲取其EXIF信息 ExifInterface exifInterface = new ExifInterface(path); // 獲取圖片的旋轉(zhuǎn)信息 int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL); switch (orientation) { case ExifInterface.ORIENTATION_ROTATE_90: degree = 90; break; case ExifInterface.ORIENTATION_ROTATE_180: degree = 180; break; case ExifInterface.ORIENTATION_ROTATE_270: degree = 270; break; } } catch (IOException e) { e.printStackTrace(); } return degree; }
/** * 將圖片按照某個(gè)角度進(jìn)行旋轉(zhuǎn) * * @param bm 需要旋轉(zhuǎn)的圖片 * @param degree 旋轉(zhuǎn)角度 * @return 旋轉(zhuǎn)后的圖片 */ public static Bitmap rotateBitmapByDegree(Bitmap bm, int degree) { Bitmap returnBm = null; // 根據(jù)旋轉(zhuǎn)角度,生成旋轉(zhuǎn)矩陣 Matrix matrix = new Matrix(); matrix.postRotate(degree); try { // 將原始圖片按照旋轉(zhuǎn)矩陣進(jìn)行旋轉(zhuǎn),并得到新的圖片 returnBm = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true); } catch (OutOfMemoryError e) { } if (returnBm == null) { returnBm = bm; } if (bm != returnBm) { bm.recycle(); } return returnBm; }
如有疑問(wèn)請(qǐng)留言或到本站社區(qū)交流討論,感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!
相關(guān)文章
Android開(kāi)發(fā)工程中集成mob短信驗(yàn)證碼功能的方法
這篇文章主要介紹了Android開(kāi)發(fā)工程中集成mob短信驗(yàn)證碼功能的方法,感興趣的小伙伴們可以參考一下2016-05-05Android應(yīng)用程序四大組件之使用AIDL如何實(shí)現(xiàn)跨進(jìn)程調(diào)用Service
Android應(yīng)用程序的四大組件中Activity、BroadcastReceiver、ContentProvider、Service都可以進(jìn)行跨進(jìn)程,Android系統(tǒng)采用了遠(yuǎn)程過(guò)程調(diào)用(RPC)方式來(lái)實(shí)現(xiàn)跨進(jìn)程調(diào)用服務(wù)(Service),對(duì)于Service的跨進(jìn)程調(diào)用需要通過(guò)AIDL來(lái)實(shí)現(xiàn),關(guān)于如何實(shí)現(xiàn)aidl service請(qǐng)看本文介紹2015-10-10Android FaceDetector實(shí)現(xiàn)人臉檢測(cè)功能
這篇文章主要為大家詳細(xì)介紹了Android FaceDetector實(shí)現(xiàn)人臉檢測(cè)功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-05-05Android Widget 桌面組件開(kāi)發(fā)介紹
本篇文章主要介紹了Android中的 widget 桌面組件開(kāi)發(fā)教程,對(duì)AppWidget 框架以及AppWidgetManger類(lèi)進(jìn)行詳細(xì)講解,開(kāi)發(fā)Android widget 開(kāi)發(fā)的朋友可以參考下2016-07-07Android user版通過(guò)adb_enable開(kāi)啟adb 調(diào)試 不提示對(duì)話(huà)框的流程分析
這篇文章主要介紹了Android user版通過(guò)adb_enable開(kāi)啟adb 調(diào)試 不提示對(duì)話(huà)框的流程分析,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-05-05