原作者博客地址: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;
}
|