使用ACTION_IMAGE_CAPTURE
活动时,我遇到了方向问题。我使用了TAG_ORIENTATION
,因此我会相应地旋转图片。但现在我们发现在一些较新的设备上这不起作用。事实上,它为所有方向返回1.
以下是我们观察到的设备列表;
有趣的是,一旦此图像是图库,它就会正确显示,如果我选择它,则TAG_ORIENTATION
会正确填充。所以OS
以某种方式正确填写了这些信息,而不是ActivityResult
。
确定方向的最可靠方法是什么?有人在另一个问题上建议比较高度和宽度,但在获得这些时,它们会根据方向正确切换(另一个谜)
编辑:似乎这可以连接到操作系统复制画廊中拍摄的图像的另一个错误(它只能将图像保存在我们指定的URL中),事实是画廊中的这个图像有ORIENTATION
信息,而指定位置的信息则没有。
这是错误; http://code.google.com/p/android/issues/detail?id=19268
EDIT-2:我已经向Android提交了一个新错误。我很确定这是与上述错误相关的操作系统错误。 http://code.google.com/p/android/issues/detail?id=22822
答案 0 :(得分:53)
好的伙计们,似乎这个Android的bug将暂时无法修复。虽然我找到了一种实现ExifInformation的方法,以便两个设备(具有正确Exif标记的设备,以及不正确的exif标签一起工作)..
所以问题出现在一些(较新的)设备上,有一个错误,使得拍摄的照片保存在您的app文件夹中没有正确的exif标签,而正确旋转的图像保存在android默认文件夹中(即使它不应该定)..
现在我做的是,我记录从我的应用程序启动相机应用程序的时间。在活动结果上,我查询媒体提供商,看看在我保存的这个时间戳之后是否保存了任何图片。这意味着,很可能操作系统将正确旋转的图片保存在默认文件夹中,当然在媒体商店中放入一个条目,我们可以使用此行中的轮换信息。现在为了确保我们正在查看正确的图像,我将此文件的大小与我可以访问的文件(保存在我自己的应用程序文件夹中)进行比较;
int rotation =-1;
long fileSize = new File(filePath).length();
Cursor mediaCursor = content.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new String[] {MediaStore.Images.ImageColumns.ORIENTATION, MediaStore.MediaColumns.SIZE }, MediaStore.MediaColumns.DATE_ADDED + ">=?", new String[]{String.valueOf(captureTime/1000 - 1)}, MediaStore.MediaColumns.DATE_ADDED + " desc");
if (mediaCursor != null && captureTime != 0 && mediaCursor.getCount() !=0 ) {
while(mediaCursor.moveToNext()){
long size = mediaCursor.getLong(1);
//Extra check to make sure that we are getting the orientation from the proper file
if(size == fileSize){
rotation = mediaCursor.getInt(0);
break;
}
}
}
现在,如果此时的旋转仍为-1,那么这意味着这是具有正确旋转信息的手机之一。此时,我们可以对返回到onActivityResult的文件使用常规exif方向
else if(rotation == -1){
rotation = getExifOrientationAttribute(filePath);
}
您可以轻松找到如何找到exif方向,例如此问题中的答案Camera orientation issue in Android
另请注意,只有在Api等级5之后才支持ExifInterface。因此,如果您想在2.0之前支持手机,那么您可以使用我找到的这个方便的库,用于Java提供的Drew Noakes; http://www.drewnoakes.com/code/exif/
祝你的形象旋转好运!
编辑:因为有问题,我使用的意图和我的开始是这样的Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
//mediaFile is where the image will be saved
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mediaFile));
startActivityForResult(intent, 1);
答案 1 :(得分:7)
你也可以这样:
Matrix matrix = new Matrix();
// rotate the Bitmap (there a problem with exif so we'll query the mediaStore for orientation
Cursor cursor = getApplicationContext().getContentResolver().query(selectedImage,
new String[] { MediaStore.Images.ImageColumns.ORIENTATION }, null, null, null);
if (cursor.getCount() == 1) {
cursor.moveToFirst();
int orientation = cursor.getInt(0);
matrix.preRotate(orientation);
}
答案 2 :(得分:7)
确实是一个有问题的错误!我不确定我是否喜欢建议的解决方法,所以这是另一个:)
关键是使用EXTRA_OUTPUT
并在捕获图像时查询它!显然,这只有在您允许自己指定文件名时才有效。
protected void takePictureSequence() {
try {
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.TITLE, UUID.randomUUID().toString() + ".jpg");
newPhotoUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, newPhotoUri);
startActivityForResult(intent, ActivityResults.TAKE_NEW_PICTURE_RESULT);
} catch (Exception e) {
Toast.makeText(this, R.string.could_not_initalize_camera, Toast.LENGTH_LONG).show();
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == ActivityResults.TAKE_NEW_PICTURE_RESULT) {
if (resultCode == RESULT_OK) {
try {
String[] projection = { MediaStore.Images.Media.DATA };
CursorLoader loader = new CursorLoader(this, newPhotoUri, projection, null, null, null);
Cursor cursor = loader.loadInBackground();
int column_index_data = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
// Rotation is stored in an EXIF tag, and this tag seems to return 0 for URIs.
// Hence, we retrieve it using an absolute path instead!
int rotation = 0;
String realPath = cursor.getString(column_index_data);
if (realPath != null) {
rotation = ImageHelper.getRotationForImage(realPath);
}
// Now we can load the bitmap from the Uri, using the correct rotation.
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public int getRotationForImage(String path) {
int rotation = 0;
try {
ExifInterface exif = new ExifInterface(path);
rotation = (int)exifOrientationToDegrees(exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL));
} catch (IOException e) {
e.printStackTrace();
}
return rotation;
}
答案 3 :(得分:2)
我最近学到的是,如果您调整图像大小,通常会丢失其EXIF信息。所以你想给新文件提供旧的EXIF信息。
答案 4 :(得分:0)
我的解决方案。在LG G2手机上测试过。我注意到,当我使用相机拍摄新照片时,一切正常。 ExifInterface返回正确的方向。所以它必须是路径中的东西,因为我的路径在这行代码中为空:
exif = new ExifInterface(path);
但是当我使用绝对路径我的应用程序崩溃。但解决方案是在下面的方法中,因为它取决于您的sdk版本。还有一点需要注意,我只使用绝对路径来选择画廊图片,因为如果我将它用于相机我的应用程序崩溃了。我是编程新手,刚刚失去2天来解决这个问题。希望它会帮助别人。
public String getRealPathFromURI(Uri uri) {
if(Build.VERSION.SDK_INT >= 19){
String id = uri.getLastPathSegment().split(":")[1];
final String[] imageColumns = {MediaStore.Images.Media.DATA };
final String imageOrderBy = null;
Uri tempUri = getUri();
Cursor imageCursor = getContentResolver().query(tempUri, imageColumns,
MediaStore.Images.Media._ID + "="+id, null, imageOrderBy);
if (imageCursor.moveToFirst()) {
return imageCursor.getString(imageCursor.getColumnIndex(MediaStore.Images.Media.DATA));
}else{
return null;
}
}else{
String[] projection = { MediaStore.MediaColumns.DATA };
Cursor cursor = getContentResolver().query(uri, projection, null, null, null);
if (cursor != null) {
int column_index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
} else
return null;
}
}
所以我在onActivityResult方法中得到了我的ExifInterface
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == GALLERY_IMAGE_REQUEST && resultCode == RESULT_OK && data != null) {
try {
exif = new ExifInterface(getRealPathFromURI(data.getData()));
} catch (IOException e) {
e.printStackTrace();
}
showImage(data.getData());
} else if (requestCode == CAMERA_IMAGE_REQUEST && resultCode == RESULT_OK) {
try {
exif = new ExifInterface(Uri.fromFile(getCameraFile()).getPath());
} catch (IOException e) {
e.printStackTrace();
}
showImage(Uri.fromFile(getCameraFile()));
}
}
我的show image方法看起来像这样
public void showImage(Uri uri) {
if (uri != null) {
try {
Bitmap bitmap = scaleBitmapDown(MediaStore.Images.Media.getBitmap(getContentResolver(), uri), IMAGE_SIZE);
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
bitmap = rotateBitmap(bitmap, orientation);
if (whatPlayer.equals("Player1")) {
mImagePlayer1.setImageBitmap(bitmap);
bitmapPlayer1 = bitmap; //*save picture in static variable so other activity can use this
}
if (whatPlayer.equals("Player2")) {
mImagePlayer2.setImageBitmap(bitmap);
bitmapPlayer2 = bitmap;
}
} catch (IOException e) {
Log.d(TAG, "Image picking failed because " + e.getMessage());
Toast.makeText(this, R.string.image_picker_error, Toast.LENGTH_LONG).show();
}
} else {
Log.d(TAG, "Image picker gave us a null image.");
Toast.makeText(this, R.string.image_picker_error, Toast.LENGTH_LONG).show();
}
}