Datos de Android EXIF siempre 0, ¿cómo cambiarlos?
image camera (5)
Como puede ver, la información de The EXIF no es confiable en Android (especialmente en dispositivos Samsung).
Sin embargo, la base de datos SQL del teléfono que contiene las referencias al objeto Media es confiable. Yo te propondría ir por este camino.
Obteniendo la orientación del uri:
private static int getOrientation(Context context, Uri photoUri) {
Cursor cursor = context.getContentResolver().query(photoUri,
new String[]{MediaStore.Images.ImageColumns.ORIENTATION}, null, null, null);
if (cursor.getCount() != 1) {
cursor.close();
return -1;
}
cursor.moveToFirst();
int orientation = cursor.getInt(0);
cursor.close();
cursor = null;
return orientation;
}
Luego inicialice el Bitmap
girado:
public static Bitmap rotateBitmap(Context context, Uri photoUri, Bitmap bitmap) {
int orientation = getOrientation(context, photoUri);
if (orientation <= 0) {
return bitmap;
}
Matrix matrix = new Matrix();
matrix.postRotate(orientation);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);
return bitmap;
}
Si desea cambiar la orientación de la imagen, pruebe el siguiente fragmento de código:
public static boolean setOrientation(Context context, Uri fileUri, int orientation) {
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.ORIENTATION, orientation);
int rowsUpdated = context.getContentResolver().update(fileUri, values, null, null);
return rowsUpdated > 0;
}
Si configura la orientación de la imagen, luego se ajustará constantemente a la orientación correcta. Es necesario hacer uso de ExifInterface
más adelante, porque la imagen ya está girada de manera adecuada.
Si este método no es satisfactorio, entonces podrías probar este método
Tengo una aplicación que captura fotos con la Camera
nativa y luego las carga en un servidor. Mi problema es que todas las fotos tienen un valor de orientación EXIF de 0, y esto desordena la visualización en otros lugares.
¿Cómo puedo cambiar la orientación EXIF? No estoy buscando una manera de corregirlo para cada circunstancia, solo cámbielo a un valor diferente.
Estoy usando un Samsung Galaxy Note 4
Probé esta solución que establece la orientación de la cámara antes de tomar fotos: Configuración de Android Photo EXIF Orientación
Camera c = Camera.open();
c.setDisplayOrientation(90);
Camera.Parameters params = mCamera.getParameters();
params.setRotation(0); // tried 0, 90, 180
c.setParameters(params);
pero no influye en los datos EXIF resultantes, siempre es 0
También probé estas soluciones donde se gira la imagen después de tomarla: valor de etiqueta de orientación EXIF siempre 0 para la imagen tomada con la aplicación de cámara de retrato de Android
y mientras esto rota la foto, la orientación EXIF sigue siendo siempre 0.
También intenté configurar los datos EXIF directamente: cómo guardar los datos Exif después de la compresión de mapa de bits en Android
private Camera.PictureCallback mPicture = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
final File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE, "");
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
ExifInterface exif = new ExifInterface(pictureFile.toString());
exif.setAttribute(ExifInterface.TAG_ORIENTATION, "3");
exif.saveAttributes();
fos.write(data);
fos.close();
//upload photo..
}
}
}
pero la orientación EXIF sigue siendo 0 después de la carga.
También he mirado estas soluciones:
Datos exif TAG_ORIENTATION siempre 0
¿Cómo escribir datos exif a imagen en Android?
¿Cómo configurar la orientación de la imagen de la cámara?
pero todos implican corregir la orientación girando, lo que no influye en los datos EXIF, o establecer los datos EXIF directamente que no parecen funcionar.
¿Cómo puedo cambiar los datos de orientación EXIF del archivo de 0 a 3?
ACTUALIZAR:
Aquí está mi código de carga:
Bitmap sBitmap = null;
final File sResizedFile = getOutputMediaFile(MEDIA_TYPE_IMAGE, "_2");
try {
sBitmap = BitmapFactory.decodeStream(new FileInputStream(pictureFile), null, options);
} catch (FileNotFoundException e) {
Log.e("App", "[MainActivity] unable to convert pictureFile to bitmap");
e.printStackTrace();
return;
}
// ... compute sw and sh int values
Bitmap sOut = Bitmap.createScaledBitmap(sBitmap, sw, sh, false);
Bitmap rotatedBitmap = rotateBitmap(sOut, 3);
FileOutputStream sfOut;
try {
sfOut = new FileOutputStream(sResizedFile);
rotatedBitmap.compress(Bitmap.CompressFormat.JPEG, 70, sfOut);
sfOut.flush();
sfOut.close();
sBitmap.recycle();
sOut.recycle();
rotatedBitmap.recycle();
} catch (Exception e) {
Log.e("App", "[MainActivity] unable to save thumbnail");
e.printStackTrace();
return;
}
// upload small thumbnail
TransferObserver sObserver = transferUtility.upload(
"stills/small", /* The bucket to upload to */
filename + ".jpg", /* The key for the uploaded object */
sResizedFile /* The file where the data to upload exists */
);
Consulte este proyecto de GitHub https://github.com/pandiaraj44/Camera . Tiene la actividad de la cámara personalizada donde EXIF TAG_ORIENTATION se manejó correctamente. Puedes clonar el proyecto y comprobar. Para obtener más información sobre el código, consulte https://github.com/pandiaraj44/Camera/blob/master/app/src/main/java/com/pansapp/cameraview/CameraFragment.java
Has aceptado tu propia respuesta como solución. Mi perorata es solo información lateral útil, de todos modos ...
El "Sin embargo ..." en su Respuesta sugiere que ahora que conoce la causa, no tiene una solución.
Resulta que mi código pudo establecer los datos EXIF, pero hay una discrepancia entre cómo interpreta Android estos datos y cómo lo interpreta iOS ...
Esto podría ser un problema de endianness. Puedes intentar cambiar manualmente la configuración de endianness de Exif abriendo tu jpeg en un editor hexadecimal y encontrando ...
- Los bytes
45 78 69 66
(forman el texto "Exif") seguidos de dos bytes cero00 00
. - Entonces debería ser
49 49
(hace un texto "II") que significa leer los datos en un formato poco endiano. - Si lo reemplaza con
4D 4D
(o texto "MM"), el lado de lectura considerará los datos como big endian.
Prueba esto en iOS para ver si los números ahora son correctos.
y con respecto a esto ...
Sin embargo, la configuración
3
muestra como0
en iOS y la imagen está de lado en Chrome.
La configuración6
aparece como3
en iOS y la imagen se ve bien en Chrome.
Lo único que puedo agregar es que iOS Mac es Big Endian * y Android / PC es Little Endian . Esencialmente, Little Endian lee / escribe bytes como de derecha a izquierda, mientras que Big Endian es opuesto.
En binario: 011
significa 3 y 110
significa 6 . La diferencia entre 3 y 6 es simplemente el orden de lectura de esos bits de unos y ceros. Por lo tanto, un sistema que lea como zero-one-one
obtiene un resultado de 3, pero el otro sistema Endian leerá un byte con los mismos bits que one-one-zero
y le dirá que el resultado es un 6 . No puedo explicar por qué "3 aparece como 0" sin un archivo de prueba para analizar bytes, pero es un resultado extraño para mí.
</end rant>
<sleep>
* nota : mientras que las Mac son Big Endian, la doble comprobación dice que iOS usa el sistema Little Endian después de todo. Sus números todavía sugieren un problema Big vs Little Endian sin embargo.
Hay una clase para leer y actualizar esta información de imágenes.
Para actualizar los atributos puedes usarlos así.
ExifInterface ef = new ExifInterface(filePath);
ef.setAttribute(MAKE_TAG, MAKE_TAG);
ef.setAttribute(ExifInterface.TAG_ORIENTATION, orientation+"");
ef.saveAttributes();
Y para leer puedes usar así.
ExifInterface exif = null;
try {
exif = new ExifInterface(absolutePath+path);
} catch (IOException e) {
e.printStackTrace();
}
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_UNDEFINED);
Espero que te ayude
Resulta que mi código pudo establecer los datos EXIF, pero hay una discrepancia entre cómo interpreta Android estos datos y cómo lo interpretan iOS y Chrome en una Mac (donde estaba verificando el archivo resultante).
Este es el único código necesario para establecer la orientación EXIF:
ExifInterface exif = new ExifInterface(pictureFile.toString());
exif.setAttribute(ExifInterface.TAG_ORIENTATION, "3");
exif.saveAttributes();
Sin embargo, la configuración 3
muestra como 0
en iOS y la imagen está de lado en Chrome.
el ajuste 6
aparece como 3
en iOS y la imagen se ve bien en Chrome.