it-swarm.com.de

Lebende Geräte immer 1 für ExifInterface.TAG_ORIENTATION zurück

Ich hatte das Orientierungsproblem bei der Arbeit mit ACTION_IMAGE_CAPTURE activity. Ich habe den TAG_ORIENTATION verwendet, damit ich das Bild entsprechend drehen würde. Nun haben wir festgestellt, dass dies auf einigen neueren Geräten nicht funktioniert. Tatsächlich gibt es für alle Orientierungen 1 zurück.

Hier ist die Liste der Geräte, auf denen wir dies beobachtet haben; 

  • Samsung Infuse 4G (2.3.3) 
  • Samsung Galaxy SII X (2.3.5) 
  • Sony Xperia Arc (2.3.3)

Interessant ist, dass, sobald dieses Bild die Galerie ist, es richtig angezeigt wird und wenn ich es auswähle, der TAG_ORIENTATION richtig gefüllt ist. Irgendwie füllt die OS diese Informationen richtig, aber nicht auf ActivityResult.

Was ist der zuverlässigste Weg, um die Orientierung zu bestimmen? Jemand hat bei einer anderen Frage den Vergleich von Höhe und Breite vorgeschlagen, aber wenn Sie diese erhalten, werden sie entsprechend der Orientierung richtig gewechselt (ein anderes Rätsel).

BEARBEITEN: Es scheint, dass dies mit einem anderen Fehler zusammenhängen könnte, bei dem das Betriebssystem das in der Galerie aufgenommene Bild dupliziert (es soll nur das Bild in der von uns angegebenen URL speichern). Die Sache ist, dass dieses Bild in der Galerie die ORIENTATION-Informationen hat die am angegebenen Ort nicht.

Dies ist der Fehler. http://code.google.com/p/Android/issues/detail?id=19268

EDIT-2: Ich habe einen neuen Fehler mit Android gemeldet. Ich bin mir ziemlich sicher, dass dies ein Betriebssystemfehler ist, der mit dem oben genannten Fehler zusammenhängt. http://code.google.com/p/Android/issues/detail?id=22822

40
Tolga E

Ok, Jungs, es scheint, als würde dieser Fehler für Android eine Zeitlang nicht behoben. Ich habe zwar einen Weg gefunden, die ExifInformation so zu implementieren, dass beide Geräte (Geräte mit dem richtigen Exif-Tag und auch falsche Exif-Tags zusammenarbeiten).

Das Problem liegt also bei einigen (neueren) Geräten vor. Es gibt einen Fehler, der dazu führt, dass das Bild ohne korrekte Exif-Tags in Ihrem App-Ordner gespeichert wird, während ein ordnungsgemäß gedrehtes Bild im Android-Standardordner gespeichert wird (auch wenn dies nicht der Fall sein sollte). .

Jetzt nehme ich die Uhrzeit auf, wenn ich die Kamera-App von meiner App aus starte. Nach dem Aktivitätsergebnis frage ich den Medienanbieter, ob Bilder nach diesem von mir gespeicherten Zeitstempel gespeichert wurden. Das bedeutet, dass das Betriebssystem wahrscheinlich das ordnungsgemäß gedrehte Bild im Standardordner gespeichert hat und natürlich einen Eintrag im Medienspeicher ablegt, und wir können die Rotationsinformationen aus dieser Zeile verwenden. Um sicherzugehen, dass wir das richtige Bild betrachten, vergleiche ich die Größe dieser Datei mit der, auf die ich Zugriff habe (in meinem eigenen App-Ordner gespeichert).

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

Wenn nun die Rotation an diesem Punkt noch -1 ist, bedeutet dies, dass dies eines der Telefone mit den richtigen Rotationsinformationen ist. An diesem Punkt können wir die reguläre Exif-Ausrichtung der Datei verwenden, die an onActivityResult zurückgegeben wird

    else if(rotation == -1){
        rotation = getExifOrientationAttribute(filePath);
    }

Sie können leicht herausfinden, wie Sie Exif-Orientierungen finden, wie die Antwort in dieser Frage Problem mit der Kamera-Orientierung in Android

Beachten Sie auch, dass ExifInterface erst nach Api Level 5 unterstützt wird. Wenn Sie also Telefone vor 2.0 unterstützen möchten, können Sie diese praktische Bibliothek verwenden, die ich für Java mit freundlicher Genehmigung von Drew Noakes gefunden habe. http://www.drewnoakes.com/code/exif/

Viel Glück mit deinem Bild!

EDIT: Weil es gefragt wurde, war die Absicht, die ich verwendet habe und wie ich angefangen habe, so

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);
53
Tolga E

sie können auch diesen Weg gehen:

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

In der Tat ein problematischer Fehler! Ich bin mir nicht sicher, ob ich die vorgeschlagene Problemumgehung mag, also hier eine andere :)

Der Schlüssel ist, EXTRA_OUTPUT zu verwenden und es abzufragen, wenn das Bild aufgenommen wurde! Dies funktioniert natürlich nur, wenn Sie den Dateinamen angeben.

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

Was ich in letzter Zeit gelernt habe, ist, dass beim Ändern der Bildgröße normalerweise die EXIF-Informationen verloren gehen. Sie möchten also der neuen Datei die alten EXIF-Informationen geben. 

Quelle.

2
Rohit Sharma

Meine Lösung dafür. Getestet auf LG G2 Mobile. Ich habe bemerkt, dass alles gut funktioniert, wenn ich eine Kamera verwende und ein neues Foto mache. ExifInterface gibt die richtige Ausrichtung zurück. Es muss also etwas im Pfad sein, da mein Pfad in dieser Codezeile null war:

exif = new ExifInterface(path);

aber als ich absoluten Pfad verwendete, stürzte meine App ab. Die Lösung befindet sich jedoch in dieser Methode, da sie von Ihrer SDK-Version abhängt. Noch ein Hinweis zu erwähnen, dass ich absoluten Pfad nur für die Auswahl eines Galerie-Bildes verwendet habe, da meine App bei der Verwendung für Camera abstürzt. Ich bin neu in der Programmierung und habe nur 2 Tage verloren, um dieses Problem zu lösen. Ich hoffe es hilft jemandem.

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

Also bekomme ich mein ExifInterface in der onActivityResult-Methode

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

und meine Show-Image-Methode sieht so aus

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