詳解android 通過uri獲取bitmap圖片并壓縮
詳解android 通過uri獲取bitmap圖片并壓縮
很多人在調(diào)用圖庫選擇圖片時會在onActivityResult中用Media.getBitmap來獲取返回的圖片,如下:
Uri mImageCaptureUri = data.getData();
Bitmap photoBmp = null;
if (mImageCaptureUri != null) {
photoBmp = MediaStore.Images.Media.getBitmap(ac.getContentResolver(), mImageCaptureUri);
}
但是Media.getBitmap這個方法獲取已知uri圖片的方式并不可取,咱來看看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;
}
其實它很簡單很粗暴,返回的是原始大小的bitmap,當圖庫選擇的圖片很大時程序極有可能會報OOM。
為了避免OOM,咱們需要改進該方法,在 BitmapFactory.decodeStream 之前壓縮圖片,以下是我改進后的代碼:
在onActivityResult中調(diào)用
Uri mImageCaptureUri = data.getData();
Bitmap photoBmp = null;
if (mImageCaptureUri != null) {
photoBmp = getBitmapFormUri(ac, mImageCaptureUri);
}
/**
* 通過uri獲取圖片并進行壓縮
*
* @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為標準
float hh = 800f;//這里設置高度為800f
float ww = 480f;//這里設置寬度為480f
//縮放比。由于是固定比例縮放,只用高或者寬其中一個數(shù)據(jù)進行計算即可
int be = 1;//be=1表示不縮放
if (originalWidth > originalHeight && originalWidth > ww) {//如果寬度大的話根據(jù)寬度固定大小縮放
be = (int) (originalWidth / ww);
} else if (originalWidth < originalHeight && originalHeight > hh) {//如果高度高的話根據(jù)寬度固定大小縮放
be = (int) (originalHeight / hh);
}
if (be <= 0)
be = 1;
//比例壓縮
BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
bitmapOptions.inSampleSize = be;//設置縮放比例
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);//再進行質(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
//第一個參數(shù) :圖片格式 ,第二個參數(shù): 圖片質(zhì)量,100為最高,0為最差 ,第三個參數(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的問題解決了,但是又碰到另外一個問題,用三星手機拍照或者選擇照片后返回來的圖片居然轉(zhuǎn)了90度。。苦逼的android程序員。。接著改。。
講onActivityResult中的代碼進行改進:
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);
/**
* 通過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ù)庫中找
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 圖片絕對路徑
* @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;
}
/**
* 將圖片按照某個角度進行旋轉(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)矩陣進行旋轉(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;
}
如有疑問請留言或到本站社區(qū)交流討論,感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!
相關文章
Android開發(fā)工程中集成mob短信驗證碼功能的方法
這篇文章主要介紹了Android開發(fā)工程中集成mob短信驗證碼功能的方法,感興趣的小伙伴們可以參考一下2016-05-05
Android應用程序四大組件之使用AIDL如何實現(xiàn)跨進程調(diào)用Service
Android應用程序的四大組件中Activity、BroadcastReceiver、ContentProvider、Service都可以進行跨進程,Android系統(tǒng)采用了遠程過程調(diào)用(RPC)方式來實現(xiàn)跨進程調(diào)用服務(Service),對于Service的跨進程調(diào)用需要通過AIDL來實現(xiàn),關于如何實現(xiàn)aidl service請看本文介紹2015-10-10
Android FaceDetector實現(xiàn)人臉檢測功能
這篇文章主要為大家詳細介紹了Android FaceDetector實現(xiàn)人臉檢測功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-05-05
Android user版通過adb_enable開啟adb 調(diào)試 不提示對話框的流程分析
這篇文章主要介紹了Android user版通過adb_enable開啟adb 調(diào)試 不提示對話框的流程分析,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-05-05

