Изображения, сделанные с помощью ACTION IMAGE CAPTURE, всегда возвращают 1 для ExifInterface.Ориентация тегов на некоторых новых устройствах
у меня была проблема с ориентацией при работе с ACTION_IMAGE_CAPTURE
активности. Я использовал TAG_ORIENTATION
Так что я бы повернуть изображение соответственно. Но теперь мы обнаружили, что на некоторых новых устройствах это не работает. Фактически он возвращает 1 для всех ориентаций.
вот список устройств, на которых мы наблюдали это;
- Samsung Infuse 4G (2.3.3)
- Samsung Galaxy SII X (2.3.5)
- Sony Xperia Arc (2.3.3)
интересно то, что как только это изображение является галереей, оно отображается правильно, и если я его выберу,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
5 ответов
Ok ребята, похоже, что эта ошибка для android не будет исправлена в течение некоторого времени. Хотя я нашел способ реализовать ExifInformation так, чтобы оба устройства (с правильным тегом Exif, а также неправильными тегами exif работали вместе)..
таким образом, проблема на некоторых (более новых) устройствах, есть ошибка, которая делает снимок, сохраненный в папке приложения без надлежащих тегов exif, в то время как правильно повернутое изображение сохраняется в папке android по умолчанию (хотя это не должно быть.).
Теперь, что я делаю, я записываю время, когда я запускаю приложение камеры из моего приложения. Затем в результате действия я запрашиваю поставщика мультимедиа, чтобы узнать, были ли сохранены какие-либо изображения после этой временной метки. Это означает, что, скорее всего, OS сохранила правильно повернутое изображение в папке по умолчанию и, конечно, поместила запись в хранилище мультимедиа, и мы можем использовать информацию о вращении из этой строки. Теперь, чтобы убедиться, что мы смотрим на изображение справа, я сравниваю размер этого файла тот, к которому у меня есть доступ (сохранен в моей собственной папке приложения);
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, то это означает, что это один из телефонов с правильной информацией о вращении. На этом этапе мы можем использовать обычную ориентацию exif для файла, возвращенного в наш onActivityResult
else if(rotation == -1){
rotation = getExifOrientationAttribute(filePath);
}
вы можете легко узнать, как найти EXIF ориентации, как ответ в этом вопросе проблема ориентации камеры в Android
также обратите внимание, что ExifInterface поддерживается только после уровня Api 5.. Поэтому, если вы хотите поддерживать телефоны до 2.0, вы можете использовать эту удобную библиотеку, которую я нашел для java благодаря Дрю Ноуксу;http://www.drewnoakes.com/code/exif/
удачи с вращающимся изображением!
EDIT: потому что его спросили, намерение, которое я использовал, и как я начал, было таким
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);
}
действительно проблемная ошибка! Я не уверен, что мне нравится предложенный обходной путь, так что вот еще:)
ключ должен использовать 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.
мое решение для этого. Протестировано на LG G2 mobile. Я заметил, что когда я использую камеру и делаю новый снимок, все работает нормально. ExifInterface возвращает правильную ориентацию. Поэтому это должно быть что-то в пути, потому что мой путь был нулевым в этой строке кода:
exif = new ExifInterface(path);
но когда я использовал абсолютный путь, мое приложение разбилось. Но решение в этом методе ниже, потому что это зависит от версии SDK. Еще одно замечание: я использовал абсолютный путь только для выбора галереи изображений, потому что если я использовал его для камеры, мое приложение разбилось. Im новый в программировании и просто потерял 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;
}
}
поэтому я получаю свой ExifInterface в методе onActivityResult
@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();
}
}