使用ACTION_IMAGE_CAPTURE拍摄的图像在某些较新的设备上始终返回1,表示ExifInterface.TAG_ORIENTATION

使用ACTION_IMAGE_CAPTURE活动时遇到方向问题。 我已经使用了TAG_ORIENTATION以便相应地旋转图片。 但是现在我们发现在一些较新的设备上这是行不通的。 事实上,所有方向都返回1。

以下是我们观察过的设备列表;

  • 三星Infuse 4G(2.3.3)
  • 三星Galaxy SII X(2.3.5)
  • 索尼Xperia Arc(2.3.3)

有趣的是,一旦这个图像是图库,它显示正确,如果我select它, TAG_ORIENTATION正确填充。 所以不知何故OS正确填充这些信息,但没有在ActivityResult

什么是最可靠的方法来确定方向? 有人在另一个问题上build议比较高度和宽度,但是当得到这些时,他们根据方向(另一个谜)适当切换,

编辑:这似乎可以连接到另一个操作系统复制在图库中拍摄的图像(它只能保存在我们指定的URL中的图像),这个图像在画廊有ORIENTATION信息在指定位置的那个没有。

这是错误; http://code.google.com/p/android/issues/detail?id=19268

编辑2:我提出了一个新的Android与Android的错误。 我很确定这是一个涉及上述错误的操作系统错误。 http://code.google.com/p/android/issues/detail?id=22822

好吧,这似乎像这个错误的Android不会被固定一段时间。 尽pipe我find了实现ExifInformation的方法,以便两个设备(具有适当的Exif标签,还有不适当的exif标签一起工作)。

所以这个问题是在一些(新的)设备,有一个错误,使图片拍摄保存在您的应用程序文件夹没有适当的exif标签,而一个正确的旋转图像保存在Android默认文件夹(即使不应该)。 。

现在我所做的是logging从应用程序启动相机应用程序的时间。 就活动结果而言,我查询媒体提供商以查看在我保存的时间戳之后是否保存了任何图片。 这意味着,最有可能的操作系统保存在默认文件夹中正确旋转的图片,当然在媒体存储放入一个条目,我们可以使用这一行的旋转信息。 现在要确保我们正在查看正确的图像,我比较这个文件的大小,我有权访问(保存在我自己的应用程序文件夹);

  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); } 

你可以很容易地find如何find像这个问题在Android的相机方向问题的答案exif方向

另外请注意,ExifInterface仅在Api级别5之后才支持。所以如果你想在2.0之前支持手机,那么你可以使用这个方便的库,我为Drew Noakes提供了java的礼貌; 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); 

你也可以这样做:

 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); } 

确实是一个有问题的错误! 我不知道我喜欢build议的解决方法,所以这里是另一个:)

关键是使用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; } 

我最近了解到,如果调整图像大小,通常会丢失EXIF信息。 所以你想给新文件提供旧的EXIF信息。

资源。

我的解决scheme。 testingLG G2手机。 我注意到,当我使用相机,并采取新的图片一切正常。 ExifInterface返回正确的方向。 所以它必须是path中的东西,因为我的path在这行代码中是null:

 exif = new ExifInterface(path); 

但是当我使用绝对path我的应用程序崩溃。 但解决scheme是在这个方法下面,因为它取决于你的sdk版本。 还有一点需要注意的是,我只用绝对path来select画廊的图片,因为如果我用它的相机我的应用程序崩溃。 林编程新,只是失去了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())); } } 

和我的显示图像方法是这样的

 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(); } }