In diesem Artikel erfahren Sie, wie Sie CameraX-Anwendungsfälle in Ihrer App einrichten, um Bilder mit den richtigen Rotationsinformationen zu erhalten, sei es aus dem Anwendungsfall ImageAnalysis
oder ImageCapture
. Also:
- Das
Analyzer
des AnwendungsfallsImageAnalysis
sollte Frames mit der richtigen Rotation erhalten. - Der Anwendungsfall
ImageCapture
sollte Bilder mit der richtigen Drehung aufnehmen.
Terminologie
In diesem Thema wird die folgende Terminologie verwendet, daher ist es wichtig, die Bedeutung der einzelnen Begriffe zu verstehen:
- Bildschirmausrichtung
- Hier wird angegeben, welche Seite des Geräts nach oben ist. Dies kann einer der vier Werte sein: Hochformat, Querformat, umgekehrtes Hochformat oder umgekehrtes Querformat.
- Displaydrehung
- Dieser Wert wird von
Display.getRotation()
zurückgegeben. Er stellt die Grad dar, um die das Gerät aus seiner natürlichen Ausrichtung gegen den Uhrzeigersinn gedreht wird. - Zielrotation
- Dies steht für die Anzahl der Grad, um die das Gerät im Uhrzeigersinn gedreht werden soll, um seine natürliche Ausrichtung zu erreichen.
So legen Sie die Zielrotation fest
Die folgenden Beispiele zeigen, wie die Zieldrehung für ein Gerät anhand seiner natürlichen Ausrichtung bestimmt wird.
Beispiel 1: Natürliche Ausrichtung im Hochformat
Gerätebeispiel: Pixel 3 XL | |
---|---|
Natürliche Ausrichtung = Hochformat Displaydrehung = 0 |
|
Natürliche Ausrichtung = Hochformat Displaydrehung = 90 |
Beispiel 2: Natürliche Ausrichtung im Querformat
Gerätebeispiel: Pixel C | |
---|---|
Natürliche Ausrichtung = Querformat Displaydrehung = 0 |
|
Natürliche Ausrichtung = Querformat Displayrotation = 270 |
Bilddrehung
Welches Ende ist angekommen? Die Sensorausrichtung wird in Android als konstanter Wert definiert, der die Grade (0, 90, 180, 270) angibt, die der Sensor vom oberen Rand des Geräts gedreht wird, wenn sich das Gerät in einer natürlichen Position befindet. Für alle Fälle in den Diagrammen beschreibt die Bilddrehung, wie die Daten im Uhrzeigersinn gedreht werden sollten, um sie aufrecht anzuzeigen.
Die folgenden Beispiele zeigen, wie die Bilddrehung je nach Ausrichtung des Kamerasensors aussehen sollte. Außerdem wird davon ausgegangen, dass die Zielrotation auf „Displayrotation“ festgelegt ist.
Beispiel 1: Sensor um 90 Grad gedreht
Gerätebeispiel: Pixel 3 XL | |
---|---|
Displaydrehung = 0 |
|
Displaydrehung = 90 |
Beispiel 2: Sensor um 270 Grad gedreht
Gerätebeispiel: Nexus 5X | |
---|---|
Displaydrehung = 0 |
|
Displaydrehung = 90 |
Beispiel 3: Sensor um 0 Grad gedreht
Gerätebeispiel: Pixel C (Tablet) | |
---|---|
Displaydrehung = 0 |
|
Displaydrehung = 270 |
Rotation eines Bilds berechnen
Bildanalyse
Das Analyzer
von ImageAnalysis
empfängt Bilder von der Kamera in Form von ImageProxy
s. Jedes Bild enthält Rotationsinformationen, auf die über Folgendes zugegriffen werden kann:
val rotation = imageProxy.imageInfo.rotationDegrees
Dieser Wert gibt die Grad an, um die das Bild im Uhrzeigersinn gedreht werden muss, damit es der Zieldrehung von ImageAnalysis
entspricht. Bei einer Android-App entspricht die Zielrotation von ImageAnalysis
in der Regel der Bildschirmausrichtung.
Bilderfassung
Ein Callback wird an eine ImageCapture
-Instanz angehängt, um zu signalisieren, dass ein Erfassungsergebnis verfügbar ist. Das Ergebnis kann entweder das aufgenommene Bild oder ein Fehler sein.
Beim Aufnehmen eines Bildes kann der bereitgestellte Callback einen der folgenden Typen haben:
OnImageCapturedCallback
:Erhält ein Image mit speicherinternem Zugriff in Form einesImageProxy
.OnImageSavedCallback
:Wird aufgerufen, wenn das aufgenommene Bild erfolgreich an dem inImageCapture.OutputFileOptions
angegebenen Ort gespeichert wurde. Die Optionen können einenFile
,OutputStream
oder einen Standort inMediaStore
angeben.
Die Drehung des aufgenommenen Bildes unabhängig von seinem Format (ImageProxy
, File
, OutputStream
, MediaStore Uri
) gibt die Grad der Drehung an, um die das aufgenommene Bild im Uhrzeigersinn gedreht werden muss, um der Zieldrehung von ImageCapture
zu entsprechen, die auch im Kontext einer Android-App normalerweise der Bildschirmausrichtung entspricht.
Die Rotation des aufgenommenen Bildes kann auf eine der folgenden Arten abgerufen werden:
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
Drehen eines Bildes prüfen
Bei den Anwendungsfällen ImageAnalysis
und ImageCapture
werden nach einer erfolgreichen Erfassungsanfrage ImageProxy
s von der Kamera empfangen. Ein ImageProxy
umschließt ein Bild mit Informationen über es, einschließlich seiner Drehung. Diese Rotationsinformationen geben die Grad an, um die das Bild gedreht werden muss, damit es der Zieldrehung des Anwendungsfalls entspricht.
Richtlinien für die Rotation von ImageCapture-/ImageAnalysis-Zielen
Da viele Geräte nicht standardmäßig das Hoch- oder Querformat umkehren, unterstützen einige Android-Apps diese Ausrichtungen nicht. Ob eine App dies unterstützt oder nicht, ändert die Art und Weise, wie die Zielrotation der Anwendungsfälle aktualisiert werden kann.
Unten sehen Sie zwei Tabellen, die definieren, wie die Zielrotation der Anwendungsfälle mit der Displayrotation synchron gehalten wird. Die erste zeigt, wie das geht, wobei alle vier Ausrichtungen unterstützt werden. Die zweite behandelt nur die Ausrichtungen, zu denen das Gerät standardmäßig gedreht wird.
So wählen Sie die Richtlinien für Ihre App aus:
Prüfe, ob die Kamera (
Activity
) deiner App gesperrt oder entsperrt ist oder ob sie Änderungen der Ausrichtungskonfiguration überschreibt.Lege fest, ob die Kamera
Activity
deiner App alle vier Geräteausrichtungen (Hochformat, umgekehrtes Hochformat, Querformat und umgekehrtes Querformat) verarbeiten soll oder ob sie nur Ausrichtungen verarbeiten soll, auf denen das Gerät standardmäßig unterstützt wird.
Unterstützung für alle vier Ausrichtungen
In dieser Tabelle werden bestimmte Richtlinien aufgeführt, die für den Fall gelten, dass das Gerät nicht ins umgekehrte Hochformat gedreht wird. Dasselbe gilt für Geräte, die nicht in das Querformat gedreht werden.
Szenario | Vorgaben | Einzelfenstermodus | Splitscreen-Modus im Mehrfenstermodus |
---|---|---|---|
Ausrichtung ohne SIM-Lock |
Richte die Anwendungsfälle jedes Mal ein, wenn die Activity erstellt wird, z. B. im onCreate() -Callback des Activity .
|
||
Verwenden Sie onOrientationChanged() von OrientationEventListener .
Aktualisieren Sie im Callback die Zielrotation der Anwendungsfälle. Dadurch wird Activity auch nach einer Änderung der Ausrichtung, z. B. wenn das Gerät um 180 Grad gedreht wurde, nicht neu erstellt.
|
Behandelt auch, wenn sich der Bildschirm im umgekehrten Hochformat befindet und das Gerät nicht standardmäßig in das umgekehrte Hochformat gedreht wird. |
Auch für Fälle, in denen Activity nicht neu erstellt wird, wenn das Gerät gedreht wird (z. B. um 90 Grad). Dies geschieht auf Geräten mit kleinem Formfaktor, wenn die App den halben Bildschirm einnimmt, und auf größeren Geräten, wenn die App zwei Drittel des Bildschirms einnimmt.
|
|
Optional: Setzen Sie die Eigenschaft screenOrientation von Activity in der Datei AndroidManifest auf fullSensor .
|
Auf diese Weise kann die Benutzeroberfläche aufrecht stehen, wenn sich das Gerät im umgekehrten Hochformat befindet. Außerdem kann Activity vom System neu erstellt werden, wenn das Gerät um 90 Grad gedreht wird.
|
Hat keine Auswirkungen auf Geräte, die nicht standardmäßig ins Hochformat drehen. Wenn sich das Display im umgekehrten Hochformat befindet, wird der Mehrfenstermodus nicht unterstützt. | |
Ausrichtung gesperrt |
Richten Sie die Anwendungsfälle nur einmal ein, wenn das Activity zum ersten Mal erstellt wird, z. B. im onCreate() -Callback des Activity .
|
||
Verwenden Sie onOrientationChanged() von OrientationEventListener .
Aktualisieren Sie im Callback die Zielrotation der Anwendungsfälle mit Ausnahme der Vorschau.
|
Auch für Fälle, in denen Activity nicht neu erstellt wird, wenn das Gerät gedreht wird (z. B. um 90 Grad). Dies geschieht auf Geräten mit kleinem Formfaktor, wenn die App den halben Bildschirm einnimmt, und auf größeren Geräten, wenn die App zwei Drittel des Bildschirms einnimmt.
|
||
Konfigurationsänderungen für die Ausrichtung überschrieben |
Richten Sie die Anwendungsfälle nur einmal ein, wenn das Activity zum ersten Mal erstellt wird, z. B. im onCreate() -Callback des Activity .
|
||
Verwenden Sie onOrientationChanged() von OrientationEventListener .
Aktualisieren Sie im Callback die Zielrotation der Anwendungsfälle.
|
Auch für Fälle, in denen Activity nicht neu erstellt wird, wenn das Gerät gedreht wird (z. B. um 90 Grad). Dies geschieht auf Geräten mit kleinem Formfaktor, wenn die App den halben Bildschirm einnimmt, und auf größeren Geräten, wenn die App zwei Drittel des Bildschirms einnimmt.
|
||
Optional: Setze die Eigenschaft „screenOrientation“ der Aktivität in der Datei „AndroidManifest“ auf „fullSensor“. | Die Benutzeroberfläche kann aufrecht ausgerichtet sein, wenn sich das Gerät im umgekehrten Hochformat befindet. | Hat keine Auswirkungen auf Geräte, die nicht standardmäßig ins Hochformat drehen. Wenn sich das Display im umgekehrten Hochformat befindet, wird der Mehrfenstermodus nicht unterstützt. |
Nur von Geräten unterstützte Ausrichtungen unterstützen
Nur Ausrichtungen unterstützen, die das Gerät standardmäßig unterstützt. Dies kann umgekehrtes Hoch- oder umgekehrtes Querformat umfassen.
Szenario | Vorgaben | Splitscreen-Modus im Mehrfenstermodus |
---|---|---|
Ausrichtung ohne SIM-Lock |
Richte die Anwendungsfälle jedes Mal ein, wenn die Activity erstellt wird, z. B. im onCreate() -Callback des Activity .
|
|
Verwende onDisplayChanged() von DisplayListener . Aktualisieren Sie im Callback die Zieldrehung der Anwendungsfälle, z. B. wenn das Gerät um 180 Grad gedreht wird.
|
Auch für Fälle, in denen Activity nicht neu erstellt wird, wenn das Gerät gedreht wird (z. B. um 90 Grad). Dies geschieht auf Geräten mit kleinem Formfaktor, wenn die App den halben Bildschirm einnimmt, und auf größeren Geräten, wenn die App zwei Drittel des Bildschirms einnimmt.
|
|
Ausrichtung gesperrt |
Richten Sie die Anwendungsfälle nur einmal ein, wenn das Activity zum ersten Mal erstellt wird, z. B. im onCreate() -Callback des Activity .
|
|
Verwenden Sie onOrientationChanged() von OrientationEventListener .
Aktualisieren Sie im Callback die Zielrotation der Anwendungsfälle.
|
Auch für Fälle, in denen Activity nicht neu erstellt wird, wenn das Gerät gedreht wird (z. B. um 90 Grad). Dies geschieht auf Geräten mit kleinem Formfaktor, wenn die App den halben Bildschirm einnimmt, und auf größeren Geräten, wenn die App zwei Drittel des Bildschirms einnimmt.
|
|
Konfigurationsänderungen für die Ausrichtung überschrieben |
Richten Sie die Anwendungsfälle nur einmal ein, wenn das Activity zum ersten Mal erstellt wird, z. B. im onCreate() -Callback des Activity .
|
|
Verwende onDisplayChanged() von DisplayListener . Aktualisieren Sie im Callback die Zieldrehung der Anwendungsfälle, z. B. wenn das Gerät um 180 Grad gedreht wird.
|
Auch für Fälle, in denen Activity nicht neu erstellt wird, wenn das Gerät gedreht wird (z. B. um 90 Grad). Dies geschieht auf Geräten mit kleinem Formfaktor, wenn die App den halben Bildschirm einnimmt, und auf größeren Geräten, wenn die App zwei Drittel des Bildschirms einnimmt.
|
Ausrichtung ohne SIM-Lock
Ein Activity
hat eine entsperrte Ausrichtung, wenn seine Bildschirmausrichtung (z. B. Hochformat oder Querformat) der physischen Ausrichtung des Geräts entspricht. Eine Ausnahme bildet das umgekehrte Hoch-/Querformat, das von einigen Geräten standardmäßig nicht unterstützt wird. Wenn Sie erzwingen möchten, dass das Gerät in alle vier Ausrichtungen gedreht wird, setzen Sie die Eigenschaft screenOrientation
von Activity
auf fullSensor
.
Im Mehrfenstermodus wird ein Gerät, das das umgekehrte Hoch-/Querformat nicht unterstützt, nicht standardmäßig zum Hoch-/Querformat drehen, selbst wenn die Eigenschaft screenOrientation
auf fullSensor
gesetzt 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
Die Ausrichtung eines Displays ist gesperrt, wenn es unabhängig von der physischen Ausrichtung des Geräts in derselben Bildschirmausrichtung bleibt (z. B. Hochformat oder Querformat). Dazu kann das Attribut screenOrientation
einer Activity
in der Deklaration in der Datei AndroidManifest.xml
angegeben werden.
Wenn die Ausrichtung des Bildschirms gesperrt ist, löscht das System die Activity
nicht und erstellt sie nicht neu, 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 der Ausrichtungskonfiguration überschrieben
Wenn ein Activity
Änderungen der Ausrichtungskonfiguration überschreibt, wird das System nicht gelöscht und neu erstellt, wenn sich die physische Ausrichtung des Geräts ändert.
Das System aktualisiert die Benutzeroberfläche jedoch entsprechend der physischen Ausrichtung des Geräts.
<!-- 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" />
Kamera-Anwendungsfälle einrichten
In den oben beschriebenen Szenarien können die Anwendungsfälle für die Kamera eingerichtet werden, wenn die Activity
zum ersten Mal erstellt wird.
Bei einem Activity
mit entsperrter Ausrichtung erfolgt diese Einrichtung jedes Mal, wenn das Gerät gedreht wird, da das System die Activity
löscht und neu erstellt, wenn sich die Ausrichtung ändert. Dies führt dazu, dass die Zieldrehung in den Anwendungsfällen jedes Mal standardmäßig so festgelegt wird, dass sie der Bildschirmausrichtung entspricht.
Im Fall einer Activity
mit gesperrter Ausrichtung oder einer, die Änderungen der Ausrichtungskonfiguration überschreibt, wird diese Einrichtung einmalig vorgenommen, 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-Einrichtung
Mit einer OrientationEventListener
kannst du die Zieldrehung der Kamera-Anwendungsfä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 Kameraanwendungsfälle in bestimmten Situationen aktualisieren, z. B. wenn das System nicht löscht und den Activity
neu erstellt, nachdem das Gerät um 180 Grad gedreht wurde.
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) } }