webentwicklung-frage-antwort-db.com.de

Android-Kamera unerklärliche Drehung bei der Aufnahme für einige Geräte (nicht bei EXIF)

Was ich mache, scheint einfach zu sein, aber ich bin immer noch verloren, nachdem ich jede mögliche Stackoverflow-Antwort gelesen und alle Artikel, die ich finden kann, googelt habe.

Ich verwende eine Vorschau von SurfaceView und nehme ein Bild von einer Aktivität auf, die in meiner AndroidManifest.xml für screenOrientation = "landscape" festgelegt ist.

Ich folgte dem Beispielcode der Camera-App und dachte, die Dinge liefen, bis ich meine App auf ein paar Motorola-Geräten mit 1.5 ausprobierte.

Ich habe den OrientationEventListener ausgeführt, und ich verwende Reflection, um zu sehen, ob die Rotation so eingestellt ist:

final int latchedOrientation = roundOrientation(mLastOrientation + 90);

Parameters parameters = preview.camera.getParameters();

JPLog.d("Setting camera rotation = %d", latchedOrientation);
try {
    // if >= 2.0
    Method method = Camera.Parameters.class.getMethod("setRotation",
        int.class);

    if(method != null) {
        method.invoke(parameters, latchedOrientation);
    }

} catch(Throwable t) {
    // if < 2.0
    parameters.set("rotation", latchedOrientation);
}

preview.camera.setParameters(parameters);

NexusOne (OS 2.2) - Funktioniert großartig. LatchedOrientation = 0, Bild OK ohne Drehung im EXIF-Header.

T-Mobile G1 (OS 1.6) - Funktioniert auch hervorragend. LatchedOrientation = 0, Bild OK.

Motorola Backflip (OS 1.5) - Bild gedreht. LatchedOrientation = 0, Bild enthält keine EXIF-Drehung.

Motorola CLIQ (OS 1.5) - Bild gedreht. LatchedOrientation = 0, Bild enthält keine EXIF-Drehung.

Was ist los mit diesen Motorola-Geräten? Ich dachte, mein Problem war, dass der Motorola-Kameratreiber die Bilder nicht rotierte. Ich fand die Sanselan EXIF-Lesekurse für Android und bereitete sich darauf vor, sie selbst zu drehen. Lustig ist, dass es EXIF-Header gibt, aber kein Rotationselement.

Wenn ich die Drehung manuell auf 90 Grad stelle, kommen die Bilder perfekt von den Motorola-Geräten, aber jetzt haben der G1 und der NexusOne Bilder, die um 90 Grad gedreht sind (nicht das, was ich will). Es muss etwas geben, das ich hier nicht bekomme.

Ich bezweifle, dass es sich um eine 1.5-Ausgabe handelt, oder hätte jemand Informationen darüber gepostet?

27
Scott Merritt

Dies ist tatsächlich ein gerätespezifisches Problem, das hauptsächlich Motorola-Geräte betrifft. Die google devs enthielten einenAufruf von setDisplayOrientationin API 8, um das Problem zu umgehen. Der Hauptfehler ist hier .).

Für diejenigen, die sich nicht für API 8 entscheiden können, gibt es zwei Lösungen:

onDraw überschreiben
Überschreiben Sie onDraw in einer ViewGroup der obersten Ebene, und drehen Sie die Leinwand um 90 Grad, um die Drehung zu kompensieren. Beachten Sie, dass hier ein Vorbehalt besteht, da Ihre Berührungsereignisse ebenfalls gedreht werden müssen.

Landschaftsmodus verwenden
Sperren Sie die Aktivität im Querformat, zeichnen Sie jedoch die Elemente wie im Hochformat. Dies bedeutet, dass Sie Ihr Layout erstellen und Ihre Bildelemente so drehen, dass sie wie im Hochformat erscheinen, sodass die Ansicht normal aussieht. Dies macht es leider schwierig, das Menü zu verwenden, da das Menü horizontal geöffnet wird.

Ich habe auch gesehen, dass Leute einen Animationscontroller verwenden, um die Ansicht zu drehen. Der Nachteil, den ich nicht überwinden konnte, ist, dass sich die gedrehte Ansicht nicht ausdehnt, um den Bildschirm zu füllen. Siehe Antwort von Georg für eine Beispielimplementierung).

10
Error 454

Ich hatte dieses Problem und habe diese Methode verwendet, um das Bild aufzunehmen. (Ohne eine benutzerdefinierte Kamera zu erstellen)

final Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(image));
startActivityForResult(intent, 0);

und erledigte den Rest in onActivityResult (int requestCode, int resultCode, Intent data) {}

Aber das Originalbild (Tatsächliches SD-Kartenbild) war korrekt und Bitmap wurde gedreht, als ich so abgerufen wurde. Bitmap bmp = BitmapFactory.decodeStream (..

Die Lösung: 

    try {
        File f = new File(SD_CARD_IMAGE_PATH);
        ExifInterface exif = new ExifInterface(f.getPath());
        int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);

        int angle = 0;

        if (orientation == ExifInterface.ORIENTATION_ROTATE_90) {
            angle = 90;
        } 
        else if (orientation == ExifInterface.ORIENTATION_ROTATE_180) {
            angle = 180;
        } 
        else if (orientation == ExifInterface.ORIENTATION_ROTATE_270) {
            angle = 270;
        }

        Matrix mat = new Matrix();
        mat.postRotate(angle);

        Bitmap bmp = BitmapFactory.decodeStream(new FileInputStream(f), null, null);
        Bitmap correctBmp = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), mat, true);                 
    }
    catch (IOException e) {
        Log.w("TAG", "-- Error in setting image");
    }   
    catch(OutOfMemoryError oom) {
        Log.w("TAG", "-- OOM Error in setting image");
    }
45
Rukmal Dias

Hier ist der Code, den ich in meiner Aktivität onActivityResult () verwendet habe. Die zurückgegebene Absicht war die Auswahl eines Bildes vom Typ image/*. Funktioniert gut für mich! 

Uri imageUri = intent.getData();
                String[] orientationColumn = {MediaStore.Images.Media.ORIENTATION};
                Cursor cur = managedQuery(imageUri, orientationColumn, null, null, null);
                int orientation = -1;
                if (cur != null && cur.moveToFirst()) {
                    orientation = cur.getInt(cur.getColumnIndex(orientationColumn[0]));
                }  
                Matrix matrix = new Matrix();
                matrix.postRotate(orientation);
4
dbaugh

Es scheint, dass der Vorschlag "Landschaftsmodus verwenden" das einzige ist, was wirklich funktioniert. Es scheint, dass es in Ordnung ist, entweder im Manifest zu sein oder über einen Aufruf von setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) in der Aktivität onCreate zu erfolgen.

0
KayEss