Android图片处理事项

这里介绍在Android开发过程中对于图片处理的一些注意事项,并提供一个在用的的图片压缩

Android图片处理注意事项

@(Android)[Image|图片处理|Reduce]

如果只是为了读取图片的宽高属性,要生成一个只有宽高属性的Bitmap

1
2
3
4
5
6
7
8
9
10
11
BitmapFactory.Options newOpts = new BitmapFactory.Options();
//开始读入图片,只读属性,不全部读入内存,此时把options.inJustDecodeBounds 设回true
newOpts.inJustDecodeBounds = true;
//inPurgeable 设为True的话表示使用BitmapFactory创建的Bitmap用于存储Pixel的内存空间在系统内存不足时可以被回收
newOpts.inPurgeable = true;
//inInputShareable与inPurgeable一起使用,如果inPurgeable为false那该设置将被忽略,如果为true,那么它可以决定位图是否能够共享一个指向数据源的引用,或者是进行一份拷贝
newOpts.inInputShareable = true;
Bitmap bitmap = BitmapFactory.decodeFile(srcPath, newOpts);//此时返回bm为空
int w = newOpts.outWidth;
int h = newOpts.outHeight;

三星手机拍照的图片都是横向的

三星手机拍照后图片会有Exif头信息,并且有旋转角度,拍出来的图片都是横屏的,如果想要使用这些图片,需要根据Exif头信息去判断旋转角度,再把图片正过来。
因为这个是三星的硬件写入的,所以你如果自定义拍照,只修改Camera.Parameters.setRotation(int)旋转角度是无效的。

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
private static int readImageExif(String filePtah) {
int orientation = -2;
int res = 0;
try {
ExifInterface exif = new ExifInterface();
exif.readExif(filePtah);
orientation = exif.getTagIntValue(ExifInterface.TAG_ORIENTATION);
Log.e("Exif", "Orientation: " + orientation);
//根据图片头部信息判断需要旋转的角度,
//在三星的手机里,会自动在Exif头信息里写入旋转角度,拍照时设置ratation是无效的
switch (orientation) {
case 3:
res = 180;
break;
case 6:
res = 90;
break;
case 8:
res = 270;
break;
}
} catch (Exception e) {
Log.e("Exif", "No Exif info");
}
return res;
}

图片压缩

图片压缩一定要注意主动回收bitmap

1
2
3
4
if (null != bm && !bm.isRecycled()) {
bm.recycle();
System.gc();
}
图片压缩代码
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/**
* 压缩到1080宽或高
*
* @param srcPath
* @return
*/
public static Bitmap getimage(String srcPath) {
BitmapFactory.Options newOpts = new BitmapFactory.Options();
//开始读入图片,只读属性,不全部读入内存,此时把options.inJustDecodeBounds 设回true了
newOpts.inJustDecodeBounds = true;
//inPurgeable 设为True的话表示使用BitmapFactory创建的Bitmap用于存储Pixel的内存空间在系统内存不足时可以被回收
newOpts.inPurgeable = true;
//inInputShareable与inPurgeable一起使用,如果inPurgeable为false那该设置将被忽略,如果为true,那么它可以决定位图是否能够共享一个指向数据源的引用,或者是进行一份拷贝
newOpts.inInputShareable = true;
Bitmap bitmap = BitmapFactory.decodeFile(srcPath, newOpts);//此时返回bm为空
int w = newOpts.outWidth;
int h = newOpts.outHeight;
//设置要压缩的图片的宽高限制
int hh = IMAGE_MAX_SIZE;//这里设置高度为800f
int ww = IMAGE_MAX_SIZE;//这里设置宽度为480f
//缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
int be = 1;//be=1表示不缩放
if (w > h && w > IMAGE_MAX_SIZE) {//如果宽度大的话根据宽度固定大小缩放
be = (newOpts.outWidth / ww);
} else if (w < h && h > hh) {//如果高度高的话根据宽度固定大小缩放
be = (newOpts.outHeight / hh);
}
if (be <= 0)
be = 1;
//因为三星手机拍照后回自动在图片的Exif信息中写入旋转角度
//虽然在手机里看到是正向的,但其实是横向的
//根据Exif信息判断旋转方向,如果需要旋转,则重新旋转生成一张图片
int rat = readImageExif(srcPath);
if (rat == 0) {
BitmapFactory.Options newOpts2 = new BitmapFactory.Options();
//重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了
newOpts2.inJustDecodeBounds = false;
newOpts2.inPurgeable = true;
newOpts2.inInputShareable = true;
newOpts2.inSampleSize = be;//设置缩放比例
bitmap = BitmapFactory.decodeFile(srcPath, newOpts2);
}else{
BitmapFactory.Options newOpts2 = new BitmapFactory.Options();
newOpts2.inJustDecodeBounds = false;
newOpts2.inPurgeable = true;
newOpts2.inInputShareable = true;
newOpts2.inSampleSize = be;//设置缩放比例
bitmap = BitmapFactory.decodeFile(srcPath, newOpts2);
//根据Exif信息判断旋转方向,如果需要旋转,则重新旋转生成一张图片
Matrix m=new Matrix();
m.postRotate(rat);
//这里的源bitmap要用压缩好的
bitmap = Bitmap.createBitmap(bitmap,0,0,bitmap.getWidth(),bitmap.getHeight(),m,false);
}
return bitmap;
}
保存压缩图片代码
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
41
42
43
/**
* 保存方法
*/
public static String saveCompressedImage(String srcPath) throws IOException {
Bitmap bm = getimage(srcPath);
String filePath = PHOTO_TEMP_DIR;
File dir = new File(filePath);
if (!dir.exists()) {
dir.mkdirs();
}
String fileName = getTempPhotoFilename();
File f = new File(filePath, fileName);
if (f.exists()) {
f.delete();
}
FileOutputStream out = null;
try {
out = new FileOutputStream(f);
bm.compress(Bitmap.CompressFormat.JPEG, 85, out);
return filePath + File.separator + fileName;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//回收Bitmap
if (null != bm && !bm.isRecycled()) {
bm.recycle();
System.gc();
}
try {
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}