很多人在调用图库选择图片时会在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。

为了避免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.         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.             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.             be = (int) (originalWidth / ww);  
  25.         } else if (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.    
  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.        ByteArrayOutputStream baos = new ByteArrayOutputStream();  
  10.        image.compress(Bitmap.CompressFormat.JPEG, 100, baos);//质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中  
  11.        int options = 100;  
  12.        while (baos.toByteArray().length / 1024 > 100) {  //循环判断如果压缩后图片是否大于100kb,大于继续压缩  
  13.            baos.reset();//重置baos即清空baos  
  14.            //第一个参数 :图片格式 ,第二个参数: 图片质量,100为最高,0为最差  ,第三个参数:保存压缩后的数据的流  
  15.            image.compress(Bitmap.CompressFormat.JPEG, options, baos);//这里压缩options%,把压缩后的数据存放到baos中  
  16.            options -= 10;//每次都减少10  
  17.        }  
  18.        ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());//把压缩后的数据baos存放到ByteArrayInputStream中  
  19.        Bitmap bitmap = BitmapFactory.decodeStream(isBm, nullnull);//把ByteArrayInputStream数据生成图片  
  20.        return bitmap;  
  21.    }  

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


在onActivityResult中的代码进行改进:

[java]  view plain  copy  
  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);  

[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.             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.                     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.             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.                 case ExifInterface.ORIENTATION_ROTATE_180:  
  20.                     degree = 180;  
  21.                     break;  
  22.                 case ExifInterface.ORIENTATION_ROTATE_270:  
  23.                     degree = 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.         Bitmap returnBm = null;  
  10.    
  11.         // 根据旋转角度,生成旋转矩阵  
  12.         Matrix matrix = new Matrix();  
  13.         matrix.postRotate(degree);  
  14.         try {  
  15.             // 将原始图片按照旋转矩阵进行旋转,并得到新的图片  
  16.             returnBm = Bitmap.createBitmap(bm, 00, 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.     }  
来自:http://www.cnblogs.com/popqq520/p/5404738.html

更多相关文章

  1. Android Studio Gradle多渠道打包(动态设定App名称,应用图标,背景
  2. Android图片剪裁-调用系统实现,完美适配魅族等机型
  3. Android 添加图片水印(图片+文字)
  4. android上传图片到服务器,求服务器那边和android的Activity的完整
  5. Android 和 PHP 之间进行数据加密传输
  6. Android使用SQLite数据库(1)
  7. Android 之 网络访问服务器,解析JSON数据
  8. Android中上传图片到服务端C#接收图
  9. Android应用程序组件Content Provider在应用程序之间共享数据的

随机推荐

  1. Linux系统利用crontab定时备份Mysql数据
  2. MySQL中limit对查询语句性能的影响
  3. Mysql中关于Incorrect string value的解
  4. mysql触发器实时检测一条语句进行备份删
  5. MySQL触发器trigger的使用
  6. MySQL 如何查找删除重复行
  7. Mysql按特定符号分割成多行和多列的示例
  8. 9种 MySQL数据库优化的技巧
  9. 浅谈MySQL安装starting the server失败的
  10. MySQL表的碎片整理和空间回收的方法