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

作者:木偶然 时间:2021-07-10 11:57:08 

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

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


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
   //缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
   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);//再进行质量压缩
 }


/**
 * 质量压缩方法
 *
 * @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中的代码进行改进:


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);

/**
  * 通过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;
   }

/**
  * 读取图片的旋转的角度
  *
  * @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;
 }

/**
  * 将图片按照某个角度进行旋转
  *
  * @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;
 }

如有疑问请留言或到本站社区交流讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

来源:http://www.cnblogs.com/popqq520/p/5404738.html

标签:android,uri,bitmap
0
投稿

猜你喜欢

  • intellij idea创建第一个动态web项目的步骤方法

    2023-04-16 15:47:20
  • 带着问题读CLR via C#(笔记二)类型基础

    2022-01-31 07:31:08
  • Android编程实现图片的颜色处理功能示例

    2022-10-08 23:15:25
  • java明文密码三重加密方法

    2022-09-01 05:59:26
  • SpringBoot实现Mysql使用MD5进行密码加密的示例

    2022-11-24 23:14:16
  • C#实现为视频添加水印

    2022-02-16 05:30:07
  • Java中的静态绑定和动态绑定详细介绍

    2023-01-18 19:54:06
  • Java利用数组随机抽取幸运观众如何实现

    2022-03-20 11:51:02
  • 一文带你了解SpringBoot的启动原理

    2023-11-28 20:44:42
  • java Swing组件setBounds()简单用法实例分析

    2023-11-23 13:35:54
  • java简单列出文件夹下所有文件的方法

    2022-12-23 19:25:05
  • Java中判断对象是否为空的方法的详解

    2022-01-09 07:41:14
  • springMVC+velocity实现仿Datatables局部刷新分页方法

    2022-06-20 01:05:22
  • Java中File类方法详解以及实践

    2021-09-13 05:58:16
  • Java实现RedisUtils操作五大集合(增删改查)

    2023-07-13 06:33:14
  • mybatis-plus 如何判断参数是否为空并作为查询条件

    2022-09-14 22:05:03
  • Android实现桌面悬浮窗、蒙板效果实例代码

    2022-12-15 18:09:42
  • Android使用WebView实现截图分享功能

    2023-04-17 08:03:48
  • 解析SpringBoot中使用LoadTimeWeaving技术实现AOP功能

    2023-04-19 00:21:47
  • 老生常谈Java字符串进阶(必看篇)

    2023-11-12 21:19:35
  • asp之家 软件编程 m.aspxhome.com