很多人在调用图库选择图片时会在onActivityResult中用Media.getBitmap来获取返回的图片,如下:



[java]  view plain  copy


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()方法的源码:



[java]  view plain  copy


1. public static final 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。

BitmapFactory.decodeStream 之前压缩图片,以下是我改进后的代码:

在onActivityResult中调用


[java]  view plain  copy


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


[java]  view plain  copy


1. /**
2.      * 通过uri获取图片并进行压缩
3.      *
4.      * @param uri
5.      */  
6. public static Bitmap getBitmapFormUri(Activity ac, Uri uri) throws FileNotFoundException, IOException {  
7.         InputStream input = ac.getContentResolver().openInputStream(uri);  
8. new BitmapFactory.Options();  
9. true;  
10. true;//optional  
11. //optional  
12. null, onlyBoundsOptions);  
13.         input.close();  
14. int originalWidth = onlyBoundsOptions.outWidth;  
15. int originalHeight = onlyBoundsOptions.outHeight;  
16. if ((originalWidth == -1) || (originalHeight == -1))  
17. return null;  
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. int) (originalWidth / ww);  
25. else if (originalWidth < originalHeight && originalHeight > hh) {//如果高度高的话根据宽度固定大小缩放  
26. int) (originalHeight / hh);  
27.         }  
28. if (be <= 0)  
29. 1;  
30. //比例压缩  
31. new BitmapFactory.Options();  
32. //设置缩放比例  
33. true;//optional  
34. //optional  
35.         input = ac.getContentResolver().openInputStream(uri);  
36. null, bitmapOptions);  
37.         input.close();  
38.    
39. return compressImage(bitmap);//再进行质量压缩  
40.     }


[java]  view plain  copy


1. /**
2.     * 质量压缩方法
3.     *
4.     * @param image
5.     * @return
6.     */  
7. public static Bitmap compressImage(Bitmap image) {  
8.    
9. new ByteArrayOutputStream();  
10. 100, baos);//质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中  
11. int options = 100;  
12. while (baos.toByteArray().length / 1024 > 100) {  //循环判断如果压缩后图片是否大于100kb,大于继续压缩  
13. //重置baos即清空baos  
14. //第一个参数 :图片格式 ,第二个参数: 图片质量,100为最高,0为最差  ,第三个参数:保存压缩后的数据的流  
15. //这里压缩options%,把压缩后的数据存放到baos中  
16. 10;//每次都减少10  
17.        }  
18. new ByteArrayInputStream(baos.toByteArray());//把压缩后的数据baos存放到ByteArrayInputStream中  
19. null, null);//把ByteArrayInputStream数据生成图片  
20. return bitmap;  
21.    }

OOM的问题解决了,但是又碰到另外一个问题,用三星手机拍照或者选择照片后返回来的图片居然转了90度,接着改。

在onActivityResult中的代码进行改进:


[java]  view plain  copy


1. Uri originalUri = null;  
2. 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);


[java]  view plain  copy



1. /**
2.      * 通过Uri获取文件
3.      * @param ac
4.      * @param uri
5.      * @return
6.      */  
7. public static File getFileFromMediaUri(Context ac, Uri uri) {  
8. if(uri.getScheme().toString().compareTo("content") == 0){  
9.             ContentResolver cr = ac.getContentResolver();  
10. null, null, null, null);// 根据Uri从数据库中找  
11. if (cursor != null) {  
12.                 cursor.moveToFirst();  
13. "_data"));// 获取图片路径  
14.                 cursor.close();  
15. if (filePath != null) {  
16. return new File(filePath);  
17.                 }  
18.             }  
19. else if(uri.getScheme().toString().compareTo("file") == 0){  
20. return new File(uri.toString().replace("file://",""));  
21.         }  
22. return null;  
23.         }

[java]  view plain  copy


1. /**
2.      * 读取图片的旋转的角度
3.      *
4.      * @param path 图片绝对路径
5.      * @return 图片的旋转角度
6.      */  
7. public static int getBitmapDegree(String path) {  
8. int degree = 0;  
9. try {  
10. // 从指定路径下读取图片,并获取其EXIF信息  
11. 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. 90;  
18. break;  
19. case ExifInterface.ORIENTATION_ROTATE_180:  
20. 180;  
21. break;  
22. case ExifInterface.ORIENTATION_ROTATE_270:  
23. 270;  
24. break;  
25.             }  
26. catch (IOException e) {  
27.             e.printStackTrace();  
28.         }  
29. return degree;  
30.     }


[java]  view plain  copy


1. /**
2.      * 将图片按照某个角度进行旋转
3.      *
4.      * @param bm     需要旋转的图片
5.      * @param degree 旋转角度
6.      * @return 旋转后的图片
7.      */  
8. public static Bitmap rotateBitmapByDegree(Bitmap bm, int degree) {  
9. null;  
10.    
11. // 根据旋转角度,生成旋转矩阵  
12. new Matrix();  
13.         matrix.postRotate(degree);  
14. try {  
15. // 将原始图片按照旋转矩阵进行旋转,并得到新的图片  
16. 0, 0, bm.getWidth(), bm.getHeight(), matrix, true);  
17. catch (OutOfMemoryError e) {  
18.         }  
19. if (returnBm == null) {  
20.             returnBm = bm;  
21.         }  
22. if (bm != returnBm) {  
23.             bm.recycle();  
24.         }  
25. return returnBm;  
26.     }