2015-04-30 2 views
4

Я боролся с этой ошибкой в ​​последний месяц или около того. Каждый раз, когда я думаю, что я исправил его, он, кажется, возвращается в той или иной форме.Ориентация изображения - Android

Это старый Android-образчик «Изображение повернуто на 90 градусов». Я прочитал бесчисленные сообщения здесь (StackOverFlow), а также попробовал множество методов, но просто не могу их исправить.

Я по-прежнему получаю изображения, которые вращаются неправильно.

В моем приложении пользователь выбирает свой профиль Picture, который затем устанавливается в ImageView. Изображение выбрано из галереи телефонов

Два дня назад я реализовал следующий код, это сработало для всех изображений, которые я тестировал на моем телефоне. Однако, когда один из моих бета-тестировщиков попробовал это, его образы снова были повернуты. Он прислал мне изображения для тестирования, но они отображались на моем телефоне. Поэтому почему я все больше расстраиваюсь.

Это метод я использую, чтобы получить ориентацию изображения:

// Gets an Images Orientation 
public static int getOrientationEXIF(Context context, Uri uri) { 

    int orientation = 0; 

    try { 

     ExifInterface exif = new ExifInterface(uri.getPath()); 

     orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL); 

     switch (orientation) { 

      case ExifInterface.ORIENTATION_ROTATE_90: 
       orientation = 90; 
       return orientation; 

      case ExifInterface.ORIENTATION_ROTATE_180: 
       orientation = 180; 
       return orientation; 

     } 

    } catch (IOException e) { 
     e.printStackTrace(); 
    } 

    return 0; 
} 

тогда я получаю повернутый Bitmap, используя этот метод:

// Rotate a Bitmap 
public static Bitmap rotate(float rotationValue, String filePath) { 
    Bitmap original= BitmapFactory.decodeFile(filePath); 

    int width = original.getWidth(); 

    int height = original.getHeight(); 

    Matrix matrix = new Matrix(); 

    matrix.postRotate(rotationValue); 

    Bitmap rotated = Bitmap.createBitmap(original, 0, 0, width, height, matrix, true); 

    return rotated; 
} 

Я просто не знаю, что делать больше ,

Я бы очень хотел, что если кто-то может помочь мне понять это

Спасибо заранее


UPDATE

Я просто увидел следующую строку кода в моем журнале после реализации предложенных методов:

JHEAD can't open 'file:/external/images/media/3885' 

Я не уверен, что это означает


UPDATE # 2

Я думаю, что я, возможно, устранил проблему, я получил правильный путь изображений для файла.

+0

Ричард - сделал дополнительное ExifInterface Ориентация на самом деле помочь вам ? Извините за задержку, когда у меня был раунд гольфа ... –

+0

Не стоит беспокоиться :). Кажется, так до сих пор. Мой бета-тестер ушел, поэтому он попросит его проверить его, когда он вернется. Но это определенно помогло с другими проблемами, которые у меня были сегодня. Большое спасибо :). – Richard

+0

Рад видеть здесь. Снова просто обратите внимание, что ориентация камеры будет отличаться для каждого устройства на основе реального оборудования. Некоторые устройства могут иметь более тонкую рамку, которая может привести к повороту камеры в любом направлении 90 или более градусов. –

ответ

3

Вы должны учитывать все ориентации не только 90 или 180. Я использую это

File curFile = new File("path-to-file"); // ... This is an image file from my device. 
    Bitmap rotatedBitmap; 

      try { 
       ExifInterface exif = new ExifInterface(curFile.getPath()); 
       int rotation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL); 
       int rotationInDegrees = exifToDegrees(rotation); 
       Matrix matrix = new Matrix(); 
       if (rotation != 0f) {matrix.preRotate(rotationInDegrees);} 
       rotatedBitmap = Bitmap.createBitmap(bitmap,0,0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); 


      }catch(IOException ex){ 
       Log.e(TAG, "Failed to get Exif data", ex); 
      } 

и:

/** 
* Gets the Amount of Degress of rotation using the exif integer to determine how much 
* we should rotate the image. 
* @param exifOrientation - the Exif data for Image Orientation 
* @return - how much to rotate in degress 
*/ 
private static int exifToDegrees(int exifOrientation) { 
    if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_90) { return 90; } 
    else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_180) { return 180; } 
    else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_270) { return 270; } 
    return 0; 
} 
+0

Большое вам спасибо за ответ, я только что внедрил ваши методы и все еще тестовое изображение, которое я использую, повернут на 90 градусов против часовой стрелки. – Richard

+0

@ Рихард вы попробовали войти в систему exif int, чтобы посмотреть, что образ читает? –

+0

int rotation = 0, int rotationInDegrees = 0. Только что вернулся – Richard

3

Эта проблема действительно отстой! Я замечаю, что это проблема при выборе фотографий, а не в их выборе. Я нашел ответ, похороненный в коде для этой обрезки lib, который, казалось, всегда правильно отображал вещи https://github.com/jdamcd/android-crop во время обрезки (несмотря на то, что иногда он возвращал предметы с неправильной ориентацией).В любом случае, первым начать, выбирая фотографии так, как я выбираю в этом ответе: Pick image from fragment always return resultcode 0 in some devices

Следующая сделать это где вам нужно:

private void setRotationVariables(Uri uri) 
{ 
    m_rotationInDegrees = ImageOrientationUtil.getExifRotation(ImageOrientationUtil 
     .getFromMediaUri(
      this, 
      getContentResolver(), 
      uri)); 
} 

Вот класс:

import android.content.ContentResolver; 
import android.content.Context; 
import android.database.Cursor; 
import android.media.ExifInterface; 
import android.net.Uri; 
import android.os.ParcelFileDescriptor; 
import android.provider.MediaStore; 
import android.support.annotation.Nullable; 
import android.text.TextUtils; 
import java.io.Closeable; 
import java.io.File; 
import java.io.FileDescriptor; 
import java.io.FileInputStream; 
import java.io.FileOutputStream; 
import java.io.IOException; 


public class ImageOrientationUtil 
{ 

private static final String SCHEME_FILE = "file"; 
private static final String SCHEME_CONTENT = "content"; 

public static void closeSilently(@Nullable Closeable c) { 
    if (c == null) return; 
    try { 
     c.close(); 
    } catch (Throwable t) { 
     // Do nothing 
    } 
} 

public static int getExifRotation(File imageFile) { 
    if (imageFile == null) return 0; 
    try { 
     ExifInterface exif = new ExifInterface(imageFile.getAbsolutePath()); 
     // We only recognize a subset of orientation tag values 
     switch (exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED)) { 
      case ExifInterface.ORIENTATION_ROTATE_90: 
       return 90; 
      case ExifInterface.ORIENTATION_ROTATE_180: 
       return 180; 
      case ExifInterface.ORIENTATION_ROTATE_270: 
       return 270; 
      default: 
       return ExifInterface.ORIENTATION_UNDEFINED; 
     } 
    } catch (IOException e) { 
     // Log.e("Error getting Exif data", e); 
     return 0; 
    } 
} 

@Nullable 
public static File getFromMediaUri(Context context, ContentResolver resolver, Uri uri) { 
    if (uri == null) return null; 

    if (SCHEME_FILE.equals(uri.getScheme())) { 
     return new File(uri.getPath()); 
    } else if (SCHEME_CONTENT.equals(uri.getScheme())) { 
     final String[] filePathColumn = { MediaStore.MediaColumns.DATA, MediaStore.MediaColumns.DISPLAY_NAME }; 
     Cursor cursor = null; 
     try { 
      cursor = resolver.query(uri, filePathColumn, null, null, null); 
      if (cursor != null && cursor.moveToFirst()) { 
       final int columnIndex = (uri.toString().startsWith("content://com.google.android.gallery3d")) ? 
        cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME) : 
        cursor.getColumnIndex(MediaStore.MediaColumns.DATA); 
       // Picasa images on API 13+ 
       if (columnIndex != -1) { 
        String filePath = cursor.getString(columnIndex); 
        if (!TextUtils.isEmpty(filePath)) { 
         return new File(filePath); 
        } 
       } 
      } 
     } catch (IllegalArgumentException e) { 
      // Google Drive images 
      return getFromMediaUriPfd(context, resolver, uri); 
     } catch (SecurityException ignored) { 
      // Nothing we can do 
     } finally { 
      if (cursor != null) cursor.close(); 
     } 
    } 
    return null; 
} 

private static String getTempFilename(Context context) throws IOException { 
    File outputDir = context.getCacheDir(); 
    File outputFile = File.createTempFile("image", "tmp", outputDir); 
    return outputFile.getAbsolutePath(); 
} 

@Nullable 
private static File getFromMediaUriPfd(Context context, ContentResolver resolver, Uri uri) { 
    if (uri == null) return null; 

    FileInputStream input = null; 
    FileOutputStream output = null; 
    try { 
     ParcelFileDescriptor pfd = resolver.openFileDescriptor(uri, "r"); 
     FileDescriptor fd = pfd.getFileDescriptor(); 
     input = new FileInputStream(fd); 

     String tempFilename = getTempFilename(context); 
     output = new FileOutputStream(tempFilename); 

     int read; 
     byte[] bytes = new byte[4096]; 
     while ((read = input.read(bytes)) != -1) { 
      output.write(bytes, 0, read); 
     } 
     return new File(tempFilename); 
    } catch (IOException ignored) { 
     // Nothing we can do 
    } finally { 
     closeSilently(input); 
     closeSilently(output); 
    } 
    return null; 
} 

}

+0

Извините, «сделайте это, когда вам нужно» настолько расплывчато. То, что я имел в виду, было по результату активности в результате, связанном с выбором фотографии, вызывает: setRotationVariables (data.getData), где «data» - это имя параметра Intent –

1

Ответ mochilogic очень хороший, но его комментарий верен: извините, «сделайте это, когда вам нужно», настолько расплывчато .. »

Я не могу добавить все это в комментарий к mochilogic ответу, поэтому напишу здесь: Если вам не нравится использовать его в setRotationVariables (data.getData) - это еще один способ использования класса ImageOrientationUtil из его ответа, и это метод:

  private void setRotationVariables(Uri uri) 
      { 
       m_rotationInDegrees = ImageOrientationUtil.getExifRotation   
       (ImageOrientationUtil.getFromMediaUri(
       this, 
       getContentResolver(), 
       uri)); 
       } 

Вы можете отправить Ури из галереи этого метода делают его возвращать правильный поворот в градусах по memebr, как он это делает или по значению, как я сделал:

private static int setRotationVariables(Uri uri) { 
    int rotationInDegrees = ImageOrientationUtil.getExifRotation(ImageOrientationUtil 
      .getFileFromMediaUri(
        appCtx, 
        appCtx.getContentResolver(), 
        uri)); 
    Log.d(TAG, "setRotationVariables:" + "according to original Image Uri Exif details we need to rotate in "+rotationInDegrees + " Degrees"); 
    return rotationInDegrees; 
} 

, а затем на вызывающая функция после масштабирования вашего Uri в растровое изображение, вы можете создать битм ap, используя это вращениеInDegrees с матрицей.

Вы можете увидеть это в моем коде здесь, в этом методе. Я беру Uri, масштабирую его и поворачиваю, а затем возвращаю его как растровое изображение.

но первое - basicaly это то, что вам нужно:

int rotationDegree = setRotationVariables(uri); 

    if (rotationDegree > 0) { 
     Matrix matrix = new Matrix(); 
     matrix.setRotate(rotationDegree); 
     Log.w(TAG, "recreating bitmap with rotation of " + rotationDegree + " degrees"); 
     bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); 
    } 

Это полный код метода, если anyones нужно ..

public static Bitmap getScaledBitmapFromUri(Uri uri) throws FileNotFoundException, IOException { 
      final int TRY_SCALE_TO_THIS_SIZE = 1024; 
      Log.d(TAG, "getScaledBitmapFromUri:: calling  setRotationVariables() to figure rotationDegree"); 
      int rotationDegree = setRotationVariables(uri); 
      Context ctx = MessagingApp.getContext(); 
      InputStream input = ctx.getContentResolver().openInputStream(uri); 

      BitmapFactory.Options onlyBoundsOptions = new BitmapFactory.Options(); 
      onlyBoundsOptions.inJustDecodeBounds = true; 
      onlyBoundsOptions.inDither = true;//optional 
      onlyBoundsOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;//optional 
      BitmapFactory.decodeStream(input, null, onlyBoundsOptions); 
      input.close(); 

      if ((onlyBoundsOptions.outWidth == -1) || (onlyBoundsOptions.outHeight == -1)) 
       return null; 
      int BiggestOriginalSize = (onlyBoundsOptions.outHeight > onlyBoundsOptions.outWidth) ? onlyBoundsOptions.outHeight : onlyBoundsOptions.outWidth; 
      //we will add 1 to Math.round (BiggestOriginalSize/(double)TRY_SCALE_TO_THIS_SIZE) in order to harden the scaling(we need smaller images for this project!) 
    double ratio = (BiggestOriginalSize > TRY_SCALE_TO_THIS_SIZE) ? (1 + Math.round(BiggestOriginalSize/(double) TRY_SCALE_TO_THIS_SIZE)) : 1.0; 
    Log.w(TAG, "getScaledBitmapFromUri:: originalSize: " + BiggestOriginalSize + "PX, TRY_SCALE_TO_THIS_SIZE (if original is bigger):" + TRY_SCALE_TO_THIS_SIZE +"PX"); 

    BitmapFactory.Options bitmapOptions = new BitmapFactory.Options(); 
    bitmapOptions.inSampleSize = getPowerOfTwoForSampleRatio(ratio); //this one will give abstract results (sometimes bigger then TRY_SCALE_TO_THIS_SIZE) 
    Log.w(TAG, format("bitmapOptions.inSampleSize: " + bitmapOptions.inSampleSize)); 
    bitmapOptions.inJustDecodeBounds = false; //check this out!!! maybe delete? 

    bitmapOptions.inDither = true;//optional 
    bitmapOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;//optional 
    //bitmapOptions.rogetrotationInDegrees 
    input = ctx.getContentResolver().openInputStream(uri); 
    Bitmap bitmap = BitmapFactory.decodeStream(input, null, bitmapOptions); 
    //bitmap = findExactInSampleSize(onlyBoundsOptions, TRY_SCALE_TO_THIS_SIZE, bitmap); // this one will never give bigger length then TRY_SCALE_TO_THIS_SIZE 
    if (rotationDegree > 0) { 
     Matrix matrix = new Matrix(); 
     matrix.setRotate(rotationDegree); 
     Log.w(TAG, "recreating bitmap with rotation of " + rotationDegree + " degrees"); 
     bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); 
    } 
    Log.w(TAG, "after decodeStream : bitmap.getWidth(): " + bitmap.getWidth() + "PX, bitmap.getHeight(): " + bitmap.getHeight() +"PX."); 
    input.close(); 
    return bitmap; 
} 
Смежные вопросы