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;
}
好了,问题搞定!
android 通过uri获取bitmap图片并压缩的更多相关文章
- Android 通过Uri获取Bitmap对象
(转自:http://blog.sina.com.cn/s/blog_5de73d0b0100zfm8.html) private Bitmap getBitmapFromUri(Uri uri) { ...
- Android之获取本地图片并压缩方法
这两天在做项目时,做到上传图片功能一块时,碰到两个问题,一个是如何获取所选图片的路径,一个是如何压缩图片,在查了一些资料和看了别人写的后总算折腾出来了,在此记录一下. 首先既然要选择图片,我们就先要获 ...
- android开发之——获取相册图片和路径
Android开发获取相册图片的方式网上有很多种,这里说一个Android4.4后的方法,因为版本越高,一些老的api就会被弃用,新的api和老的api不兼容,导致出现很多问题. 比如:managed ...
- android开发 两张bitmap图片合成一张图片
场景:对android4.4解码gif(解码文章见前面一篇)后的图片进行每帧处理,android4.3 解码出来的每帧都很完整,但是到android4.4版本就不完整了,每帧都是在第一帧的基础上把被改 ...
- 通过url获取bitmap
//通过Uri获取BitMap public static Bitmap getBitmapFromUri(Uri uri,Context context) { Bitmap bitmap = nul ...
- Android根据图片Uri获取图片path绝对路径的几种方法【转】
在Android 编程中经常会用到Uri转化为文件路径,如我们从相册选择图片上传至服务器,一般上传前需要对图片进行压缩,这时候就要用到图片的绝对路径. 下面对我开发中uri转path路径遇到的问题进行 ...
- Android之Glide获取图片Path和Glide获取图片Bitmap
今天主要研究了Glide获取图片Path.Bitmap用法,相信也困扰了大家很久,我在网上也找了很久,基本没有,后来研究了下,也参考了下api文档,总结了以下几个方式: 1. 获取Bitmap: 1) ...
- Android 拍照后保证保证图片不失真,进行压缩
今天在网上找了一下参考,得出把图片压缩至KB 其他不想多说.直接上代码 拍完照后调用下面代码 BitmapUtils.compressBitmap(photoPath, photoPath, 640) ...
- (转)Android学习-使用Async-Http实现图片压缩并上传功能
(转)Android学习-使用Async-Http实现图片压缩并上传功能 文章转载自:作者:RyaneLee链接:http://www.jianshu.com/p/940fc7ba39e1 让我头疼一 ...
随机推荐
- linux系统的初化始配置
一.网络的初始化 1.ip地址的修改(临时生效) 使用ifconfig命令 ifconfig 网卡名 ip地址 子网掩码 [root@localhost /]# ifconfig eno1677773 ...
- C# RSA加密解密
1.解析密钥 /// <summary> /// 把二进制密钥解析成RSACryptoServiceProvider /// </summary> /// <param ...
- SQL Server数据阻塞原因
阻塞形成原因 是由于SQL Server是高并发的,同一时间会有很多用户访问,为了保证数据一致性和数据安全,引入了锁的机制.同一时间只有拿到钥匙的用户能够访问,而其他用户需要等待. 死锁形成四大必要条 ...
- 使用 jsoup 对 HTML 文档进行解析和操作
jsoup 简介 Java 程序在解析 HTML 文档时,相信大家都接触过 htmlparser 这个开源项目,我曾经在 IBM DW 上发表过两篇关于 htmlparser 的文章,分别是:从 HT ...
- 使用PowerShell来修改文件访问,创建,修改时间属性
Function Set-FileTimeStamps { Param ( [Parameter(mandatory=$true)] [string[]]$path, [datetime]$date ...
- Selenium安装失败WebDriverException: Message: 'gechodriver' executable needs to be in PATH
在搭建Python+Selenium自动化测试时,用python通过WebDriver驱动Firefox浏览器时,一直无法执行测试用例. 报错信息:WebDriverException: Messag ...
- UWP学习记录8-设计和UI之控件和模式5
UWP学习记录8-设计和UI之控件和模式5 1.日历.日期和时间控件 日期和时间控件提供了标准的本地化方法,可供用户在应用中查看并设置日期和时间值. 有四个日期和时间控件可供选择,选择的依据如下: 日 ...
- maven权威指南学习笔记(五)—— POM
1. 简介 Archetype插件通过 pom.xml 文件创建了一个项目.这就是项目对象模型 (POM),一个项目的声明性描述. 当Maven运行一个目标的时候,每个目标都会访问定 义在项目POM里 ...
- OpenGL帧缓存对象(FBO:Frame Buffer Object)(转载)
原文地址http://www.songho.ca/opengl/gl_fbo.html 但有改动. OpenGL Frame BufferObject(FBO) Overview: 在OpenGL渲染 ...
- linux线程
线程:轻量级进程,在资源.数据方面不需要进行复制 不间断地跟踪指令执行的路径被称为执行路线 进程的结构:task_struck:地址空间 线程:轻量级的进程 在同一个进程中创建的线程,在共享进程的地址 ...