考虑到Android7.0以后拍照修改了调用和返回方式,找到了一个看起来还不错的第三方库,实际可能并非如此。
-TakePhoto
在三星Note3和S6上测试,发现竖屏拍照后返回的照片是横屏的,在其它手机上又是正常的。查了资料发现三星手机很多都有这个问题,看到了歪果仁开发者对这个问题近乎骂街的回复,发现这属于三星的一个系统级Bug。竖屏拍照后得到的照片文件就是横屏的,只有应用对这些照片重新处理。
/**
* 读取图片的旋转的角度
*
* @param path 图片绝对路径
* @return 图片的旋转角度
*/
private 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;
}
如上代码可以获取图片文件的旋转角度,可以发现在这些三星手机上的到的返回值都是ExifInterface.ORIENTATION_ROTATE_90,也就是说这些三星手机即便是竖屏拍照,的到的图片文件被顺时针旋转90度后,就变成了横屏文件。
还好查了一下库本身支持设置重新调整角度的配置,在
TakePhotoOptions
/**
* 是对拍的照片进行旋转角度纠正
*/
private boolean correctImage;
public void setCorrectImage(boolean correctImage) {
this.correctImage = correctImage;
}
但是设置后发现问题依然存在,不再通过gradle引入远程代码的方式,下载了TakePhoto的源码,重新以Library module的方式引入到项目中。
调试代码定位到了问题所在
ImageRotateUtil
/**
* 将图片按照某个角度进行旋转
*
* @param bm 需要旋转的图片
* @param degree 旋转角度
* @return 旋转后的图片
*/
private 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) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
if (returnBm == null) {
returnBm = bm;
}
if (bm != returnBm) {
bm.recycle();
}
return returnBm;
}
在如上代码中returnBm重新赋值的时候,也就是将原始图片重新旋转角度得到正确角度的图片这里,这个地方尼玛OOM了。由于库没有做压缩,一张图片在重新做旋转的时候竟然需要60M的内存空间,GGG。
好吧,问题找到了,那就先改来能用吧,
/**
* 纠正照片的旋转角度
* @param path
*/
public void correctImage(Context context,Uri path){
String imagePath=TUriParse.parseOwnUri(context,path);
int degree;
if((degree=getBitmapDegree(imagePath))!=0){
// *** add to fix oom
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inJustDecodeBounds = true; // 设置成了true,不占用内存,只获取bitmap宽高
BitmapFactory.decodeFile(imagePath, opts);
opts.inSampleSize = calculateInSampleSize(opts, 360, 640); // 调用上面定义的方法计算inSampleSize值
opts.inJustDecodeBounds = false;// 使用获取到的inSampleSize值再次解析图片
opts.inPreferredConfig = Bitmap.Config.RGB_565;
opts.inDither = true;
Bitmap bitmap = BitmapFactory.decodeFile(imagePath, opts);
// *** add to fix end
if(bitmap==null)return;
Bitmap resultBitmap=rotateBitmapByDegree(bitmap,degree);
if(resultBitmap==null)return;
try {
resultBitmap.compress(Bitmap.CompressFormat.JPEG,100,new FileOutputStream(new File(imagePath)));
} catch (FileNotFoundException e) {
e.printStackTrace();
}catch (OutOfMemoryError e){
e.printStackTrace();
}
}
}
总的来说就是先压缩图片,编码格式改为Bitmap.Config.RGB_565,减少图片编码大小;设置opts.inSampleSize来压缩图片大小,尽量按照你需要的图片大小来压缩图片,减少OOM发生的可能性。
验证完美。