详解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
投稿

猜你喜欢

  • c#实现万年历示例分享 万年历农历查询

    2022-11-08 23:26:57
  • 让C# Excel导入导出 支持不同版本Office

    2023-01-11 05:30:53
  • Android Java调用自己C++类库的实例讲解

    2023-06-16 19:09:17
  • Spring Cloud 网关服务 zuul 动态路由的实现方法

    2022-04-09 20:17:46
  • java中ArrayList和LinkedList的区别详解

    2022-09-05 11:13:48
  • 详解获取Spring MVC中所有RequestMapping以及对应方法和参数

    2023-12-09 21:29:17
  • 深度理解Java访问修饰符

    2021-10-26 17:16:08
  • Android提高之MediaPlayer播放网络视频的实现方法

    2021-07-03 06:25:29
  • Java中IO流文件读取、写入和复制的实例

    2023-08-12 03:23:29
  • Activiti流程引擎对象及配置原理解析

    2023-02-11 22:20:20
  • Spring如何使用注解的方式创建bean

    2022-01-29 03:45:49
  • Android利用Canvas类绘制图形

    2022-09-17 14:22:02
  • JAVA演示阿里云图像识别API,印刷文字识别-营业执照识别

    2022-04-21 15:05:22
  • Java各种排序算法汇总(冒泡,选择,归并,希尔及堆排序等)

    2021-10-05 14:46:23
  • Java计时新姿势StopWatch的使用方法详解

    2022-01-28 00:49:57
  • 详解Spring框架入门

    2023-08-14 12:56:14
  • Java常量池知识点总结

    2023-01-09 10:23:09
  • C#使用Monitor类实现线程同步

    2021-07-20 03:01:14
  • python调用java的Webservice示例

    2021-07-31 13:36:09
  • JavaWeb实现用户登录与注册功能(服务器)

    2022-12-19 13:28:31
  • asp之家 软件编程 m.aspxhome.com