关于Android手机拍照预览、剪裁界面出现照片九十度旋转的问题
原创Devter 最后发布于2018-09-10 11:00:38 阅读数 751 收藏
展开
案场还原:
最近做的项目,测试机小米6X及本人的努比亚Z11测试拍照环节均正常,但在领导的三星手机及Oppo FindX上就出现了奇葩现象,拍照完预览照片、剪裁照片出现了九十度的旋转,如果这时候你用模拟器,比如Genymotion也能发现此问题,预览及剪裁出现旋转。
原因排查:
通过搜索大量墙里墙内资料,原因大概总结为以下几点,自我理解,若有不对,还望指正:
Android原生系统设定的拍照界面是Landscape也就是横屏模式,因此即使你调用拍照的Activity是竖屏模式,拍照画面也是竖屏模式,但到了预览和剪裁就默认切换成了横屏的画面。
可能是某些手机厂商深度定制系统的结果,比如三星反其道而行,系统设定拍照旋转,简直是反人类,反社会!
有网友也反应可能与Activity启动模式有关,建议设置当前启动模式为Standard,但我不是这个原因,因为默认模式就是Standard。
对于以上原因,可是尝试在配置文件中设定:
<activity
android:name=".activity.ProfileActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:exported="true"
android:launchMode="standard"
android:screenOrientation="portrait" />
1
2
3
4
5
6
But,这些对我来说都不起作用
4 .代码问题
解决:
强制将旋转后的照片转回来
最重要的也就是从ExifInterface这个多媒体相关类中读取照片被旋转的角度,然后使用Matrix强制转回来。代码如下
/**
* 获取原始图片的角度(***解决三星手机拍照后图片是横着的问题***)
* 读取照片exif信息中的旋转角度
*
* @param path 照片路径
* @return角度
*/
private int getPictureDegree(String path) {
int degree = 0;
/**
* 方法一
*/
// boolean hasRotation = false;
// String[] orientationColumn = {MediaStore.Images.Media.ORIENTATION};
// Cursor cursor = context.getContentResolver().query(cameraUri, orientationColumn, null, null, null);
// Log.e(TAG, "cursor: " + cursor + " " );
// if (cursor.getCount() != 1) {
// cursor.close();
// return -1;
// }
// if (cursor.moveToFirst()){
// degree = cursor.getInt(cursor.getColumnIndex(orientationColumn[0]));
// hasRotation = true;
// }
// cursor.close();
// cursor = null;
// Log.e(TAG, "getPictureDegree: " + degree );
/**
* 方法二
*/
try {
ExifInterface exifInterface = new ExifInterface(path);
int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
Log.e(TAG, "原图被旋转角度: ========== " + orientation );
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();
}
/**
* 方法三
*/
// int degree = 0;
// android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
// android.hardware.Camera.getCameraInfo(0, info);
// degree = info.orientation;
// Log.e(TAG, "CameraInfo: " + info.orientation );
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
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
58
59
60
61
62
然后转回来:
Matrix matrix = new Matrix();
int degree = getPictureDegree(cameraImagePath);
matrix.postRotate(degree); /*翻转90度*/
1
2
3
这里需要说明一下获取照片被旋转角度getPictureDegree这个方法,有三种获取角度的方式
使用数据库Cursor读取信息context.getContentResolver().query(cameraUri, orientationColumn, null, null, null)但我读不到String[] orientationColumn = {MediaStore.Images.Media.ORIENTATION};相关的信息,报空指针异常,因此放弃。
直接读取硬件摄像头CameraInfo相关信息再进行旋转,这个方法也有硬伤,在正常的测试机上预览剪裁本来不会旋转,结果你用你用摄像机竖屏拍照,得到的info.orientation是九十度,然后进行旋转,本来正常的拍照也被颠倒了,因此同样放弃该方式。
使用ExifInterface读取,关于该类的详细说明请百度。国内多数开发者遇见此坑都推荐运用此方式读取旋转角度,但我遇见一个更奇葩的问题,通过 int orientation=exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)读取到的角度永远为0!!!!!!!!
此问题搞得我焦头烂额,欲哭无泪。经过一番Google,Stack Overflow上的开发者建议切换为第一种Cursor读取信息,但我刚才也讲了,方法报空指针,有待商榷。
现在所有的问题都集中在一点,明明旋转了的照片读取到的旋转角度却是0度!!
好吧,一天两天过去,终于找到了一种思路
还别说,之前我还真的是在读取角度信息之前做了图片压缩处理,然后才进行旋转操作
/**
* 旋转
* @return
*/
private Bitmap toturn() {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
// 简单的压缩
options.inSampleSize = 4; //把原图按1/4的比例压缩
options.inJustDecodeBounds = false; // 压缩完后便可以将inJustDecodeBounds设置为false
// 把流转化为Bitmap图片
Bitmap bitmap = BitmapFactory.decodeFile(cameraImagePath, options);
Matrix matrix = new Matrix();
int degree = getPictureDegree(cameraImagePath);
matrix.postRotate(degree); /*翻转90度*/
int width = bitmap.getWidth();
int height = bitmap.getHeight();
Bitmap returnBm = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
if (returnBm == null) {
returnBm = bitmap;
}
if (bitmap != returnBm) {
bitmap.recycle();
}
Log.e(TAG, "returnBm: " + returnBm );
return returnBm;
}
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
好吧,皇天不负有心人,先旋转再压缩之后,运行,终于解决了,在这也要感谢链接的博主。
有时候我们找bug,就跟买房一样,大海捞针,也是看运气。
附上我所有的拍照相关代码
private Uri cameraUri;
// 裁剪后图片的宽(X)和高(Y),480 X 480的正方形。
private static int output_X = 480;
private static int output_Y = 480;
private Uri imageUriCrop; //剪裁后的图片uri
/**
* 拍照
*/
public void fromCamera(){
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
File dir = new File(ConstantManager.cameraPath);//创建文件夹
if (!dir.exists()) dir.mkdirs();
Intent openCameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
cameraFile = new File(dir, String.valueOf(System.currentTimeMillis()) + ".jpg");//指定照片路径
if (!cameraFile.exists()) {
try {
cameraFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
cameraImagePath = cameraFile.getPath();
if (Build.VERSION.SDK_INT >= 24) {
cameraUri = FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".provider", cameraFile);
} else {
cameraUri = Uri.fromFile(cameraFile);
}
// Log.e(TAG, "cameraUri: " + cameraUri );
openCameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, cameraUri);
openCameraIntent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 0);
((Activity) context).startActivityForResult(openCameraIntent, 0x008);
} else {
view.showMsg("没有储存卡");
}
}
/**
* 图片剪裁
*
* @param system
* @param in
*/
public void crop(boolean system, Intent in,@Nullable File cameraFile) {
Intent intent = new Intent("com.android.camera.action.CROP");
//设置数据源
Uri uri;
if (system) { //从系统相册选择
if (in != null && in.getData() != null) {
uri = createSingleCropUri("crop_image.jpg"); //剪裁后的图库图片名
intent.setDataAndType(in.getData(), "image/*");
} else {
return;
}
} else { //从相机拍照选择
if (Build.VERSION.SDK_INT >= 24) {
//添加这一句表示对目标应用临时授权该Uri所代表的文件
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
/**
* Android 7.0要求设置数据源使用ContentUri,输出使用正常的Uri
*/
Uri contentUri = getImageContentUri(context,cameraFile);
intent.setDataAndType(contentUri,"image/*"); //设置剪裁后的图片数据源
uri = createSingleCropUri(cameraFile.getName()); //剪裁后的照片名
} else {
intent.setDataAndType(Uri.fromFile(cameraFile), "image/*"); //设置剪裁后的图片数据源
uri = createSingleCropUri(cameraFile.getName()); //剪裁后的照片名
}
}
Log.e(TAG, "crop: " + uri );
intent.putExtra("crop", "true");// 设置裁剪
intent.putExtra("aspectX", 1);// aspectX , aspectY :宽高的比例,为浮点数则不会固定裁剪框比例
intent.putExtra("aspectY", 1);
intent.putExtra("outputX", output_X);// 定义输出图片大小,不定义则按裁剪框大小定义,但裁剪耗时会加长
intent.putExtra("outputY", output_Y);
intent.putExtra("return-data", true);
intent.putExtra("scale", true);//保留比例
intent.putExtra("return-data", false);//是否返回data
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);//输出路径,剪裁后的图片
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());//编码格式
intent.putExtra("noFaceDetection", true);
((Activity) context).startActivityForResult(intent, 0x009);
}
private Uri createSingleCropUri(String fileName) {
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
File dir = new File(ConstantManager.cameraPath);//创建文件夹
if (!dir.exists()) dir.mkdirs();
File cropFile = new File(dir, fileName);//指定裁剪路径,多图情况下裁剪路径不能唯一,否则文件会被覆盖
imageUriCrop = Uri.fromFile(cropFile);
}
return imageUriCrop;
}
/**
* 安卓7.0裁剪根据文件路径获取uri
*/
public static Uri getImageContentUri(Context context, File imageFile) {
String filePath = imageFile.getAbsolutePath();
Cursor cursor = context.getContentResolver().query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
new String[]{MediaStore.Images.Media._ID},
MediaStore.Images.Media.DATA + "=? ",
new String[]{filePath}, null);
if (cursor != null && cursor.moveToFirst()) {
int id = cursor.getInt(cursor
.getColumnIndex(MediaStore.MediaColumns._ID));
Uri baseUri = Uri.parse("content://media/external/images/media");
return Uri.withAppendedPath(baseUri, "" + id);
} else {
if (imageFile.exists()) {
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DATA, filePath);
return context.getContentResolver().insert(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
} else {
return null;
}
}
}
/**
* 获取原始图片的角度(***解决三星手机拍照后图片是横着的问题***)
* 读取照片exif信息中的旋转角度
*
* @param path 照片路径
* @return角度
*/
private int getPictureDegree(String path) {
int degree = 0;
/**
* 方法一
*/
// boolean hasRotation = false;
// String[] orientationColumn = {MediaStore.Images.Media.ORIENTATION};
// Cursor cursor = context.getContentResolver().query(cameraUri, orientationColumn, null, null, null);
// Log.e(TAG, "cursor: " + cursor + " " );
// if (cursor.getCount() != 1) {
// cursor.close();
// return -1;
// }
// if (cursor.moveToFirst()){
// degree = cursor.getInt(cursor.getColumnIndex(orientationColumn[0]));
// hasRotation = true;
// }
// cursor.close();
// cursor = null;
// Log.e(TAG, "getPictureDegree: " + degree );
/**
* 方法二
*/
try {
ExifInterface exifInterface = new ExifInterface(path);
int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
Log.e(TAG, "原图被旋转角度: ========== " + orientation );
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();
}
/**
* 方法三
*/
// int degree = 0;
// android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
// android.hardware.Camera.getCameraInfo(0, info);
// degree = info.orientation;
// Log.e(TAG, "CameraInfo: " + info.orientation );
return degree;
}
/**
* 旋转
* @return
*/
private Bitmap toturn() {
Matrix matrix = new Matrix();
int degree = getPictureDegree(cameraImagePath);
matrix.postRotate(degree); /*翻转90度*/
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
// 简单的压缩
options.inSampleSize = 4; //把原图按1/4的比例压缩
options.inJustDecodeBounds = false; // 压缩完后便可以将inJustDecodeBounds设置为false
// 把流转化为Bitmap图片
Bitmap bitmap = BitmapFactory.decodeFile(cameraImagePath, options);
int width = bitmap.getWidth();
int height = bitmap.getHeight();
Bitmap returnBm = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
// if (returnBm == null) {
// returnBm = bitmap;
// }
// if (bitmap != returnBm) {
// bitmap.recycle();
// }
// Log.e(TAG, "returnBm: " + returnBm );
return returnBm;
}
/**
* 保存旋转后的Bitmap图片在SD卡中
* 如果没有SD卡则存在手机中
* @return 保存成功时返回图片的路径,失败时返回null
*/
public String savePhotoToSD() {
Bitmap mbitmap = toturn();
FileOutputStream outStream = null;
String fileName = String.valueOf(System.currentTimeMillis()) + ".jpg";
File file = new File(ConstantManager.cameraPath );
String filePath = file + "/" +fileName;
// 判断文件是否已经存在,不存在则创建
if ( !file.exists() ) {
file.mkdirs();
}
try {
outStream = new FileOutputStream(filePath);
// 把数据写入文件,100表示不压缩
mbitmap.compress(Bitmap.CompressFormat.JPEG, 100, outStream);
Log.e(TAG, "旋转处理后的图片: " + filePath );
return filePath;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
try {
if (outStream != null) {
outStream.close();
}
if (mbitmap != null) {
mbitmap.recycle();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
Activity中回调处理:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.e(TAG, "resultCode: " + resultCode);
if (resultCode == this.RESULT_OK) {
Log.e(TAG, "requestcode: " + requestCode);
switch (requestCode) {
case 0x007:
presenter.crop(true, data, null);
break;
case 0x008:
File imageFile = new File(presenter.savePhotoToSD());
presenter.crop(false, data, imageFile);
break;
case 0x009:
presenter.uploadImage(userId, entity);
break;
default:
break;
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
————————————————
版权声明:本文为CSDN博主「Devter」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u013214588/java/article/details/82586691