In diesem Thema wird gezeigt, wie Sie CameraX-Anwendungsfälle in Ihrer App einrichten, um Bilder mit den richtigen Drehinformationen zu erhalten, unabhängig davon, ob es sich um den Anwendungsfall ImageAnalysis
oder ImageCapture
handelt. So gehts:
- Der
Analyzer
des AnwendungsfallsImageAnalysis
sollte Frames mit der richtigen Drehung erhalten. - Beim Anwendungsfall
ImageCapture
sollten Bilder mit der richtigen Drehung aufgenommen werden.
Terminologie
In diesem Thema werden die folgenden Begriffe verwendet. Es ist wichtig, die Bedeutung der einzelnen Begriffe zu kennen:
- Displayausrichtung
- Hier wird angegeben, welche Seite des Geräts nach oben zeigt. Es kann einer der vier Werte sein: „Porträt“, „Querformat“, „Invertiertes Porträt“ oder „Invertiertes Querformat“.
- Displayausrichtung
- Das ist der Wert, der von
Display.getRotation()
zurückgegeben wird. Er gibt an, um wie viele Grad das Gerät gegen den Uhrzeigersinn von seiner natürlichen Ausrichtung gedreht ist. - Zielrotation
- Dies ist die Anzahl der Grad, um die das Gerät im Uhrzeigersinn gedreht werden muss, um seine natürliche Ausrichtung zu erreichen.
Zieldrehung ermitteln
In den folgenden Beispielen wird gezeigt, wie die Zieldrehung für ein Gerät anhand seiner natürlichen Ausrichtung ermittelt wird.
Beispiel 1: Natürliches Hochformat
Gerätebeispiel: Google Pixel 3 XL | |
---|---|
Natürliche Ausrichtung = Hochformat Displayausrichtung = 0 |
|
Natürliche Ausrichtung = Hochformat Displayausrichtung = 90 |
Beispiel 2: Natürliche Ausrichtung im Querformat
Gerätebeispiel: Google Pixel C | |
---|---|
Natürliche Ausrichtung = Querformat Displayausrichtung = 0 |
|
Natürliche Ausrichtung = Querformat Displayausrichtung = 270 |
Bilddrehung
Welches Ende ist oben? Die Sensorausrichtung wird in Android als konstanter Wert definiert, der die Gradzahl (0, 90, 180, 270) angibt, um die der Sensor von der Oberseite des Geräts gedreht wird, wenn sich das Gerät in einer natürlichen Position befindet. In allen Fällen in den Diagrammen beschreibt die Bilddrehung, wie die Daten im Uhrzeigersinn gedreht werden müssen, damit sie richtig herum angezeigt werden.
Die folgenden Beispiele zeigen, wie die Bilddrehung je nach Ausrichtung des Kamerasensors sein sollte. Außerdem wird davon ausgegangen, dass die Zielausrichtung auf die Displayausrichtung festgelegt ist.
Beispiel 1: Sensor um 90 Grad gedreht
Gerätebeispiel: Google Pixel 3 XL | |
---|---|
Displayausrichtung = 0 |
|
Displayausrichtung = 90 |
Beispiel 2: Sensor um 270 Grad gedreht
Beispiel für ein Gerät: Nexus 5X | |
---|---|
Displayausrichtung = 0 |
|
Displaydrehung = 90 |
Beispiel 3: Sensor um 0 Grad gedreht
Gerätebeispiel: Google Pixel C (Tablet) | |
---|---|
Displayausrichtung = 0 |
|
Displaydrehung = 270 |
Drehung eines Bildes berechnen
ImageAnalysis
Der Analyzer
von ImageAnalysis
empfängt Bilder von der Kamera in Form von ImageProxy
s. Jedes Bild enthält Informationen zur Drehung, auf die Sie über folgende Methoden zugreifen können:
val rotation = imageProxy.imageInfo.rotationDegrees
Dieser Wert gibt an, um wie viele Grad das Bild im Uhrzeigersinn gedreht werden muss, damit es der Zieldrehung von ImageAnalysis
entspricht. Im Kontext einer Android-App entspricht die Zieldrehung von ImageAnalysis
in der Regel der Bildschirmausrichtung.
ImageCapture
Mit einer ImageCapture
-Instanz wird ein Callback verknüpft, um anzuzeigen, wenn ein Aufnahmeergebnis verfügbar ist. Das Ergebnis kann entweder das aufgenommene Bild oder ein Fehler sein.
Beim Aufnehmen eines Fotos kann der bereitgestellte Rückruf einen der folgenden Typen haben:
OnImageCapturedCallback
:Empfängt ein Bild mit In-Memory-Zugriff in Form einesImageProxy
.OnImageSavedCallback
:Wird aufgerufen, wenn das aufgenommene Bild an dem vonImageCapture.OutputFileOptions
angegebenen Speicherort erfolgreich gespeichert wurde. Die Optionen können eineFile
, eineOutputStream
oder einen Ort inMediaStore
angeben.
Die Drehung des aufgenommenen Bildes, unabhängig von seinem Format (ImageProxy
, File
, OutputStream
, MediaStore Uri
), entspricht der Drehung in Grad, um die das aufgenommene Bild im Uhrzeigersinn gedreht werden muss, um der Zieldrehung von ImageCapture
zu entsprechen. Im Kontext einer Android-App entspricht dies in der Regel der Ausrichtung des Bildschirms.
So rufen Sie die Drehung des aufgenommenen Bildes ab:
ImageProxy
val rotation = imageProxy.imageInfo.rotationDegrees
File
val exif = Exif.createFromFile(file) val rotation = exif.rotation
OutputStream
val byteArray = outputStream.toByteArray() val exif = Exif.createFromInputStream(ByteArrayInputStream(byteArray)) val rotation = exif.rotation
MediaStore uri
val inputStream = contentResolver.openInputStream(outputFileResults.savedUri) val exif = Exif.createFromInputStream(inputStream) val rotation = exif.rotation
Drehung eines Bildes prüfen
Bei den Anwendungsfällen ImageAnalysis
und ImageCapture
werden nach einer erfolgreichen Aufnahmeanfrage ImageProxy
s von der Kamera empfangen. Ein ImageProxy
umschließt ein Bild und Informationen dazu, einschließlich der Drehung. Diese Drehinformationen geben an, um wie viele Grad das Bild gedreht werden muss, damit es der Zieldrehung des Anwendungsfalls entspricht.
Richtlinien für die Ausrichtung von Zielen für ImageCapture/ImageAnalysis
Da viele Geräte standardmäßig nicht in die umgekehrte Hoch- oder Querformatansicht wechseln, unterstützen einige Android-Apps diese Ausrichtungen nicht. Ob eine App diese Funktion unterstützt oder nicht, wirkt sich darauf aus, wie die Zielrotation der Anwendungsfälle aktualisiert werden kann.
Unten finden Sie zwei Tabellen, in denen beschrieben wird, wie Sie die Ausrichtung der Zielansicht der Anwendungsfälle mit der Displayausrichtung synchronisieren. Im ersten Beispiel wird gezeigt, wie Sie dies bei Unterstützung aller vier Ausrichtungen tun. Im zweiten Beispiel werden nur die Ausrichtungen berücksichtigt, in die das Gerät standardmäßig gedreht wird.
So wählen Sie aus, welche Richtlinien in Ihrer App gelten sollen:
Prüfen Sie, ob die Kamera
Activity
Ihrer App eine gesperrte oder entriegelte Ausrichtung hat oder ob Änderungen an der Ausrichtungskonfiguration überschrieben werden.Legen Sie fest, ob die Kamera Ihrer App
Activity
alle vier Geräteausrichtungen (Hochformat, umgekehrtes Hochformat, Querformat und umgekehrtes Querformat) unterstützen soll oder nur die Ausrichtungen, die das Gerät, auf dem sie ausgeführt wird, standardmäßig unterstützt.
Alle vier Ausrichtungen unterstützen
In dieser Tabelle werden bestimmte Richtlinien für den Fall erwähnt, dass sich das Gerät nicht ins Querformat drehen lässt. Dasselbe gilt für Geräte, die sich nicht ins Hochformat drehen lassen.
Szenario | Richtlinien | Einzelfenstermodus | Mehrfenstermodus mit Splitscreen |
---|---|---|---|
Ausrichtung bei entsperrtem Display |
Richten Sie die Use Cases jedes Mal ein, wenn die Activity erstellt wird, z. B. im onCreate() -Callback der Activity .
|
||
Verwenden Sie OrientationEventListener s onOrientationChanged() .
Aktualisieren Sie im Callback die Zielrotation der Anwendungsfälle. So wird verhindert, dass das System die Activity auch nach einer Änderung der Ausrichtung nicht neu erstellt, z. B. wenn das Gerät um 180 Grad gedreht wird.
|
Wird auch verwendet, wenn sich das Display im umgekehrten Hochformat befindet und das Gerät standardmäßig nicht ins umgekehrte Hochformat gedreht wird. |
Außerdem wird damit umgegangen, wenn das Activity nicht neu erstellt wird, wenn das Gerät gedreht wird (z. B. um 90 Grad). Das passiert auf Geräten mit kleinem Formfaktor, wenn die App die Hälfte des Displays einnimmt, und auf größeren Geräten, wenn die App zwei Drittel des Displays einnimmt.
|
|
Optional: Legen Sie in der Datei AndroidManifest das Attribut screenOrientation von Activity auf fullSensor fest.
|
So ist die Benutzeroberfläche auch im umgekehrten Hochformat lesbar und Activity kann vom System neu erstellt werden, wenn das Gerät um 90 Grad gedreht wird.
|
Hat keine Auswirkungen auf Geräte, die standardmäßig nicht ins umgekehrte Hochformat gedreht werden. Der Modus „Mehrere Fenster“ wird nicht unterstützt, wenn das Display im umgekehrten Hochformat ist. | |
Ausrichtung gesperrt |
Richte die Anwendungsfälle nur einmal ein, wenn die Activity zum ersten Mal erstellt wird, z. B. im onCreate() -Callback der Activity .
|
||
Verwenden Sie OrientationEventListener s onOrientationChanged() .
Aktualisieren Sie im Rückruf die Zielrotation der Anwendungsfälle mit Ausnahme der Vorschau.
|
Außerdem wird damit umgegangen, wenn das Activity nicht neu erstellt wird, wenn das Gerät gedreht wird (z. B. um 90 Grad). Das passiert auf Geräten mit kleinem Formfaktor, wenn die App die Hälfte des Displays einnimmt, und auf größeren Geräten, wenn die App zwei Drittel des Displays einnimmt.
|
||
Ausrichtungs-Konfigurationsänderungen überschrieben |
Richten Sie die Anwendungsfälle nur einmal ein, wenn die Activity zum ersten Mal erstellt wird, z. B. im onCreate() -Callback der Activity .
|
||
Verwenden Sie OrientationEventListener s onOrientationChanged() .
Aktualisieren Sie im Callback die Zielrotation der Anwendungsfälle.
|
Außerdem wird damit umgegangen, wenn das Activity nicht neu erstellt wird, wenn das Gerät gedreht wird (z. B. um 90 Grad). Das passiert auf Geräten mit kleinem Formfaktor, wenn die App die Hälfte des Displays einnimmt, und auf größeren Geräten, wenn die App zwei Drittel des Displays einnimmt.
|
||
Optional: Legen Sie in der AndroidManifest-Datei die Eigenschaft „screenOrientation“ der Aktivität auf „fullSensor“ fest. | Ermöglicht es, die Benutzeroberfläche im Hochformat anzuzeigen, wenn sich das Gerät im umgekehrten Hochformat befindet. | Hat keine Auswirkungen auf Geräte, die standardmäßig nicht ins umgekehrte Hochformat gedreht werden. Der Modus mit mehreren Fenstern wird nicht unterstützt, wenn das Display im umgekehrten Hochformat ist. |
Nur vom Gerät unterstützte Ausrichtungen unterstützen
Es werden nur Ausrichtungen unterstützt, die das Gerät standardmäßig unterstützt. Dies kann auch das umgekehrte Hoch-/Querformat umfassen.
Szenario | Richtlinien | Modus für geteilten Bildschirm mit mehreren Fenstern |
---|---|---|
Ausrichtung bei entsperrtem Display |
Richten Sie die Use Cases jedes Mal ein, wenn die Activity erstellt wird, z. B. im onCreate() -Callback der Activity .
|
|
Verwenden Sie DisplayListener s onDisplayChanged() . Aktualisieren Sie im Callback die Zieldrehung der Anwendungsfälle, z. B. wenn das Gerät um 180 Grad gedreht wird.
|
Außerdem wird damit umgegangen, wenn das Activity nicht neu erstellt wird, wenn das Gerät gedreht wird (z. B. um 90 Grad). Das passiert auf Geräten mit kleinem Formfaktor, wenn die App die Hälfte des Displays einnimmt, und auf größeren Geräten, wenn die App zwei Drittel des Displays einnimmt.
|
|
Ausrichtung gesperrt |
Richten Sie die Anwendungsfälle nur einmal ein, wenn die Activity zum ersten Mal erstellt wird, z. B. im onCreate() -Callback der Activity .
|
|
Verwenden Sie OrientationEventListener s onOrientationChanged() .
Aktualisieren Sie im Callback die Zielrotation der Anwendungsfälle.
|
Außerdem wird damit umgegangen, wenn das Activity nicht neu erstellt wird, wenn das Gerät gedreht wird (z. B. um 90 Grad). Das passiert auf Geräten mit kleinem Formfaktor, wenn die App die Hälfte des Displays einnimmt, und auf größeren Geräten, wenn die App zwei Drittel des Displays einnimmt.
|
|
Ausrichtungs-Konfigurationsänderungen überschrieben |
Richten Sie die Anwendungsfälle nur einmal ein, wenn die Activity zum ersten Mal erstellt wird, z. B. im onCreate() -Callback der Activity .
|
|
Verwenden Sie DisplayListener s onDisplayChanged() . Aktualisieren Sie im Rückruf die Zieldrehung der Anwendungsfälle, z. B. wenn das Gerät um 180 Grad gedreht wird.
|
Außerdem wird damit umgegangen, wenn das Activity nicht neu erstellt wird, wenn das Gerät gedreht wird (z. B. um 90 Grad). Das passiert auf Geräten mit kleinem Formfaktor, wenn die App die Hälfte des Displays einnimmt, und auf größeren Geräten, wenn die App zwei Drittel des Displays einnimmt.
|
Ausrichtung entsperrt
Bei einem Activity
ist die Ausrichtung entsperrt, wenn die Displayausrichtung (z. B. Hoch- oder Querformat) mit der physischen Ausrichtung des Geräts übereinstimmt. Eine Ausnahme bildet das umgekehrte Hoch-/Querformat, das einige Geräte standardmäßig nicht unterstützen. Wenn das Gerät in alle vier Ausrichtungen gedreht werden soll, setzen Sie die Eigenschaft screenOrientation
von Activity
auf fullSensor
.
Im Multifenstermodus wird ein Gerät, das das umgekehrte Hoch-/Querformat standardmäßig nicht unterstützt, nicht in das umgekehrte Hoch-/Querformat gedreht, auch wenn die screenOrientation
-Eigenschaft auf fullSensor
festgelegt ist.
<!-- The Activity has an unlocked orientation, but might not rotate to reverse portrait/landscape in single-window mode if the device doesn't support it by default. --> <activity android:name=".UnlockedOrientationActivity" /> <!-- The Activity has an unlocked orientation, and will rotate to all four orientations in single-window mode. --> <activity android:name=".UnlockedOrientationActivity" android:screenOrientation="fullSensor" />
Ausrichtung gesperrt
Ein Display hat eine gesperrte Ausrichtung, wenn es unabhängig von der physischen Ausrichtung des Geräts immer im selben Displayformat (z. B. Hoch- oder Querformat) bleibt. Dazu geben Sie die screenOrientation
-Eigenschaft eines Activity
in der Deklaration in der Datei AndroidManifest.xml
an.
Wenn die Displayausrichtung gesperrt ist, wird das Activity
vom System nicht zerstört und neu erstellt, wenn das Gerät gedreht wird.
<!-- The Activity keeps a portrait orientation even as the device rotates. --> <activity android:name=".LockedOrientationActivity" android:screenOrientation="portrait" />
Änderungen an der Ausrichtungskonfiguration überschrieben
Wenn ein Activity
Änderungen an der Ausrichtungskonfiguration überschreibt, wird es vom System nicht gelöscht und neu erstellt, wenn sich die physische Ausrichtung des Geräts ändert.
Das System aktualisiert die Benutzeroberfläche jedoch so, dass sie der physischen Ausrichtung des Geräts entspricht.
<!-- The Activity's UI might not rotate in reverse portrait/landscape if the device doesn't support it by default. --> <activity android:name=".OrientationConfigChangesOverriddenActivity" android:configChanges="orientation|screenSize" /> <!-- The Activity's UI will rotate to all 4 orientations in single-window mode. --> <activity android:name=".OrientationConfigChangesOverriddenActivity" android:configChanges="orientation|screenSize" android:screenOrientation="fullSensor" />
Einrichtung von Kamera-Anwendungsfällen
In den oben beschriebenen Szenarien können die Kamera-Anwendungsfälle eingerichtet werden, wenn die Activity
zum ersten Mal erstellt wird.
Bei einem Activity
mit entsperrter Ausrichtung wird diese Einrichtung jedes Mal durchgeführt, wenn das Gerät gedreht wird, da das System das Activity
bei Änderungen der Ausrichtung zerstört und neu erstellt. Dadurch wird die Zieldrehung der Anwendungsfälle standardmäßig so festgelegt, dass sie der Displayausrichtung entspricht.
Bei einer Activity
mit einer gesperrten Ausrichtung oder einer, die Änderungen an der Ausrichtungskonfiguration überschreibt, erfolgt diese Einrichtung einmal, wenn die Activity
zum ersten Mal erstellt wird.
class CameraActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val cameraProcessFuture = ProcessCameraProvider.getInstance(this) cameraProcessFuture.addListener(Runnable { val cameraProvider = cameraProcessFuture.get() // By default, the use cases set their target rotation to match the // display’s rotation. val preview = buildPreview() val imageAnalysis = buildImageAnalysis() val imageCapture = buildImageCapture() cameraProvider.bindToLifecycle( this, cameraSelector, preview, imageAnalysis, imageCapture) }, mainExecutor) } }
OrientationEventListener einrichten
Mit einem OrientationEventListener
können Sie die Zieldrehung der Kameranutzungsfälle kontinuierlich aktualisieren, wenn sich die Ausrichtung des Geräts ändert.
class CameraActivity : AppCompatActivity() { private val orientationEventListener by lazy { object : OrientationEventListener(this) { override fun onOrientationChanged(orientation: Int) { if (orientation == ORIENTATION_UNKNOWN) { return } val rotation = when (orientation) { in 45 until 135 -> Surface.ROTATION_270 in 135 until 225 -> Surface.ROTATION_180 in 225 until 315 -> Surface.ROTATION_90 else -> Surface.ROTATION_0 } imageAnalysis.targetRotation = rotation imageCapture.targetRotation = rotation } } } override fun onStart() { super.onStart() orientationEventListener.enable() } override fun onStop() { super.onStop() orientationEventListener.disable() } }
DisplayListener-Einrichtung
Mit einem DisplayListener
können Sie die Zieldrehung der Kamera in bestimmten Situationen aktualisieren, z. B. wenn das System die Activity
nicht zerstört und neu erstellt, nachdem sich das Gerät um 180 Grad gedreht hat.
class CameraActivity : AppCompatActivity() { private val displayListener = object : DisplayManager.DisplayListener { override fun onDisplayChanged(displayId: Int) { if (rootView.display.displayId == displayId) { val rotation = rootView.display.rotation imageAnalysis.targetRotation = rotation imageCapture.targetRotation = rotation } } override fun onDisplayAdded(displayId: Int) { } override fun onDisplayRemoved(displayId: Int) { } } override fun onStart() { super.onStart() val displayManager = getSystemService(Context.DISPLAY_SERVICE) as DisplayManager displayManager.registerDisplayListener(displayListener, null) } override fun onStop() { super.onStop() val displayManager = getSystemService(Context.DISPLAY_SERVICE) as DisplayManager displayManager.unregisterDisplayListener(displayListener) } }