android 通过uri获取bitmap图片并压缩

原作者博客地址:http://www.cnblogs.com/popqq520/p/5404738.html

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

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

 

但是Media.getBitmap这个方法获取已知uri图片的方式并不可取,咱来看看Media.getBitmap()方法的源码:

1
2
3
4
5
6
7
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中调用

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

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/**
      * 通过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
         //缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
         int  be =  1 ; //be=1表示不缩放
         if  (originalWidth > originalHeight && originalWidth > ww) { //如果宽度大的话根据宽度固定大小缩放
             be = ( int ) (originalWidth / ww);
         else  if  (originalWidth < originalHeight && originalHeight > hh) { //如果高度高的话根据宽度固定大小缩放
             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); //再进行质量压缩
     }

 

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

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

讲onActivityResult中的代码进行改进:

1
2
3
4
5
6
7
8
9
10
11
12
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());
   /**
    * 把图片旋转为正的方向
    */
   Bitmap newbitmap = rotateBitmapByDegree(photoBmp, degree);

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
      * 通过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 ); // 根据Uri从数据库中找
             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 ;
         }

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/**
      * 读取图片的旋转的角度
      *
      * @param path 图片绝对路径
      * @return 图片的旋转角度
      */
     public  static  int  getBitmapDegree(String path) {
         int  degree =  0 ;
         try  {
             // 从指定路径下读取图片,并获取其EXIF信息
             ExifInterface exifInterface =  new  ExifInterface(path);
             // 获取图片的旋转信息
             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;
     }

 

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值