java android image bitmap exif

java - Orientación de imagen-Android



bitmap exif (3)

¡Este problema realmente apesta! Noté que esto es un problema al elegir fotos en lugar de tomarlas. Encontré la respuesta oculta en el código para esta biblioteca de recorte que parecía mostrar siempre las cosas correctamente https://github.com/jdamcd/android-crop mientras recortaba (a pesar de que a veces devolvía cosas con una orientación incorrecta después). De todos modos, primero comience eligiendo la foto de la manera que elijo en esta respuesta: Elegir imagen del fragmento siempre devuelve el código de resultado 0 en algunos dispositivos

Luego haga esto donde necesite:

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

Aquí está la clase:

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

}

He estado luchando con este error por intervalos durante el último mes más o menos. Cada vez que creo que lo he solucionado, parece volver de alguna forma.

Es el viejo error de Android "Imagen girada 90 grados". He leído innumerables publicaciones aquí (StackOverFlow) y he probado numerosos métodos, pero parece que no puedo solucionarlo.

Todavía recibo imágenes que se rotan incorrectamente.

En mi aplicación, un usuario elige su imagen de perfil, que luego se configura en un ImageView. La imagen se elige de la Galería de teléfonos

Hace dos días implementé el siguiente código, esto funcionó para todas las imágenes con las que lo probé en mi teléfono. Sin embargo, cuando uno de mis probadores Beta lo intentó, sus imágenes volvieron a girar. Me envió las imágenes para que las probara pero se veían bien en mi teléfono. Por eso me siento cada vez más frustrado.

Este es el método que estoy usando para obtener la orientación de Imágenes:

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

Luego obtengo un mapa de bits girado usando este método:

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

Ya no estoy seguro de qué hacer.

Realmente me gustaría que alguien pudiera ayudarme a resolver esto

Gracias de antemano

ACTUALIZAR

Acabo de ver la siguiente línea de código en mi registro después de implementar los métodos sugeridos:

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

No estoy seguro de lo que esto significa

ACTUALIZACIÓN # 2

Creo que he solucionado el problema, obtuve la ruta de imagen adecuada para el archivo.


Debe tener en cuenta todas las orientaciones, no solo 90 o 180. Estoy usando esto

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

y:

/** * 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; }


La respuesta mochilógica es muy buena, pero su comentario también es correcto: lo siento, "hacer esto donde sea necesario" es tan vago ... "

No puedo agregar todo esto en el comentario a la respuesta mochilogic, así que escribiré esto aquí: si no le gusta usarlo en setRotationVariables (data.getData), esta es otra forma de usar la clase ImageOrientationUtil de su respuesta y este método:

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

Puede enviar Uri desde la galería a este método para que devuelva la rotación correcta en grados por memebr como lo hace o por valor como lo hice yo:

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

y luego en la función de llamada después de escalar su Uri a mapa de bits, puede crear un mapa de bits usando esta rotaciónInDegrees con una matriz.

puedes verlo en mi código aquí en este método. Tomo Uri y lo escalo y lo giro y luego lo devuelvo como mapa de bits.

pero primero, básicamente esto es lo que necesitas:

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

Este es el código de método completo si alguien lo necesita.

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