Android Pictures Are Rotated 90 Degrees When I Upload Them
This topic showcases how to set up CameraX employ cases inside your app to go images with the correct rotation information, whether it's from the ImageAnalysis or the ImageCapture use case. And so:
- The
ImageAnalysisuse example'southwardAnalyzershould receive frames with the correct rotation. - The
ImageCaptureuse case should take pictures with the right rotation.
Terminology
This topic uses the following terminology, so understanding what each term means is important:
- Display orientation
- This refers to which side of the device is in the upward position, and can be one of four values: portrait, mural, contrary portrait, or reverse landscape.
- Display rotation
- This is the value returned by
Display.getRotation(), and represents the degrees past which the device is rotated counter-clockwise from its natural orientation. - Target rotation
- This represents the number of degrees through which to rotate the device clockwise to reach its natural orientation.
How to determine the target rotation
The post-obit examples show how to determine the target rotation for a device based on its natural orientation.
Example 1: Portrait natural orientation
| Device instance: Pixel 3 XL | |
|---|---|
| Natural orientation = Portrait Display rotation = 0 | |
| Natural orientation = Portrait Display rotation = ninety | |
Example 2: Landscape natural orientation
| Device case: Pixel C | |
|---|---|
| Natural orientation = Landscape Display rotation = 0 | |
| Natural orientation = Landscape Brandish rotation = 270 | |
Paradigm rotation
Which end is upwards? The sensor orientation is divers in Android as a constant value, which represents the degrees (0, 90, 180, 270) the sensor is rotated from the top of the device when the device is in a natural position. For all the cases in the diagrams, the epitome rotation describes how the data should be rotated clockwise to appear upright.
The following examples show what the image rotation should exist depending on the photographic camera sensor orientation. They too assume the target rotation is set to the display rotation.
Case 1: Sensor rotated 90 degrees
| Device instance: Pixel 3 Twoscore | |
|---|---|
| Display rotation = 0 | |
| Brandish rotation = 90 | |
Example ii: Sensor rotated 270 degrees
| Device instance: Nexus 5X | |
|---|---|
| Display rotation = 0 | |
| Brandish rotation = 90 | |
Example 3: Sensor rotated 0 degrees
| Device example: Pixel C (Tablet) | |
|---|---|
| Display rotation = 0 | |
| Display rotation = 270 | |
Computing an epitome'south rotation
ImageAnalysis
ImageAnalysis'due south Analyzer receives images from the camera in the form of ImageProxysouth. Each paradigm contains rotation information, which is attainable via:
val rotation = imageProxy.imageInfo.rotationDegrees
This value represents the degrees by which the prototype needs to be rotated clockwise to lucifer ImageAnalysis's target rotation. In the context of an Android app, ImageAnalysis'southward target rotation would typically lucifer the screen's orientation.
ImageCapture
A callback is attached to an ImageCapture example to point when a capture upshot is ready. The result can be either the captured paradigm or an error.
When taking a picture, the provided callback can be of one of the following types:
-
OnImageCapturedCallback: Receives an image with in-memory admission in the form of anImageProxy. -
OnImageSavedCallback: Invoked when the captured image has been successfully stored in the location specified byImageCapture.OutputFileOptions. The options can specify aFile, anOutputStream, or a location inMediaStore.
The rotation of the captured image, regardless of its format (ImageProxy, File, OutputStream, MediaStore Uri) represents the rotation degrees past which the captured paradigm needs to be rotated clockwise to match ImageCapture's target rotation, which once more, in the context of an Android app, would typically lucifer the screen's orientation.
Retrieving the captured paradigm'southward rotation tin can be washed in 1 of the post-obit ways:
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
Verify an epitome's rotation
The ImageAnalysis and ImageCapture utilise cases receive ImageProxys from the photographic camera after a successful capture asking. An ImageProxy wraps an epitome and information about it, including its rotation. This rotation information represents the degrees by which the image has to be rotated to match the utilise case'due south target rotation.
ImageCapture/ImageAnalysis target rotation guidelines
Since many devices don't rotate to reverse portrait or reverse landscape by default, some Android apps don't support these orientations. Whether an app supports it or not changes the fashion the use cases' target rotation can be updated.
Below are 2 tables defining how to keep the use cases' target rotation in sync with the display rotation. The first shows how to do and then while supporting all four orientations; the second only handles the orientations the device rotates to past default.
To choose which guidelines to follow in your app:
-
Verify whether your app's camera
Actionhas a locked orientation, an unlocked orientation, or if it overrides orientation configuration changes. -
Decide whether your app'south camera
Activityshould handle all iv device orientations (portrait, reverse portrait, landscape, and reverse landscape), or if it should only handle orientations the device it'southward running on supports past default.
Support all four orientations
This table mentions certain guidelines to follow for cases where the device doesn't rotate to contrary portrait. The aforementioned tin be applied to devices that don't rotate to opposite mural.
| Scenario | Guidelines | Unmarried-window mode | Multi-window split-screen mode |
|---|---|---|---|
| Unlocked orientation | Prepare up the use cases every fourth dimension the Activity is created, such as in the Activity'south onCreate() callback. | ||
Utilise OrientationEventListener's onOrientationChanged(). Inside the callback, update the target rotation of the employ cases. This handles cases where the system doesn't recreate the Action fifty-fifty later on an orientation alter, such every bit when the device is rotated 180 degrees. | Also handles when the display is in a reverse portrait orientation and the device doesn't rotate to opposite portrait by default. | Likewise handles cases where the Activity isn't recreated when the device rotates (90 degrees, for example). This happens on small class factor devices when the app takes up half the screen, and on larger devices when the app takes upward two thirds of the screen. | |
Optional: Gear up the Activity'southward screenOrientation holding to fullSensor in the AndroidManifest file. | This allows for the UI to be upright when the device is in reverse portrait, and allows for the Action to exist recreated past the arrangement whenever the device is rotated by xc degrees. | Has no effect on devices that don't rotate to opposite portrait by default. Multi-window fashion isn't supported while the display is in a contrary portrait orientation. | |
| Locked orientation | Set upwards the use cases just one time, when the Action is first created, such as in the Action's onCreate() callback. | ||
Use OrientationEventListener's onOrientationChanged(). Within the callback, update the target rotation of the use cases. | Likewise handles cases where the Activity isn't recreated when the device rotates (90 degrees, for case). This happens on small form gene devices when the app takes up one-half the screen, and on larger devices when the app takes up two thirds of the screen. | ||
| Orientation configChanges overridden | Gear up the use cases just once, when the Activity is first created, such as in the Activity'south onCreate() callback. | ||
Employ OrientationEventListener'southward onOrientationChanged(). Inside the callback, update the target rotation of the utilize cases. | Also handles cases where the Action isn't recreated when the device rotates (90 degrees, for example). This happens on small grade factor devices when the app takes up half the screen, and on larger devices when the app takes up two thirds of the screen. | ||
| Optional: Set the Activity's screenOrientation property to fullSensor in the AndroidManifest file. | Allows for the UI to be upright when the device is in reverse portrait. | Has no effect on devices that don't rotate to reverse portrait by default. Multi-window manner isn't supported while the display is in a opposite portrait orientation. |
Back up just device-supported orientations
Support only orientations the device supports past default (which may or may not include reverse portrait/reverse mural).
| Scenario | Guidelines | Multi-window split-screen mode |
|---|---|---|
| Unlocked orientation | Fix the employ cases every time the Activity is created, such as in the Activeness'due south onCreate() callback. | |
Use DisplayListener's onDisplayChanged(). Inside the callback, update the target rotation of the apply cases, such equally when the device is rotated 180 degrees. | Too handles cases where the Activity isn't recreated when the device rotates (90 degrees, for example). This happens on small form factor devices when the app takes up one-half the screen, and on larger devices when the app takes up 2 thirds of the screen. | |
| Locked orientation | Prepare upwards the employ cases just once, when the Activity is first created, such as in the Activity's onCreate() callback. | |
Use OrientationEventListener'due south onOrientationChanged(). Inside the callback, update the target rotation of the use cases. | Also handles cases where the Activity isn't recreated when the device rotates (90 degrees, for instance). This happens on pocket-size form gene devices when the app takes up half the screen, and on larger devices when the app takes up two thirds of the screen. | |
| Orientation configChanges overridden | Gear up upwards the utilize cases only once, when the Activity is outset created, such equally in the Activeness's onCreate() callback. | |
Use DisplayListener's onDisplayChanged(). Within the callback, update the target rotation of the use cases, such as when the device is rotated 180 degrees. | Also handles cases where the Activity isn't recreated when the device rotates (90 degrees, for case). This happens on small form factor devices when the app takes up one-half the screen, and on larger devices when the app takes up two thirds of the screen. |
Unlocked orientation
An Activity has an unlocked orientation when its brandish orientation (such as portrait or landscape) matches the device'southward physical orientation, with the exception of contrary portrait/landscape, which some devices don't support by default. To force the device to rotate to all 4 orientations, prepare the Activeness'southward screenOrientation property to fullSensor.
In multi-window mode, a device that doesn't support reverse portrait/landscape by default won't rotate to reverse portrait/mural, fifty-fifty when its screenOrientation property is ready to fullSensor.
<!-- The Activity has an unlocked orientation, only might non rotate to reverse portrait/mural in single-window mode if the device doesn't support it by default. --> <action android:name=".UnlockedOrientationActivity" /> <!-- The Action has an unlocked orientation, and will rotate to all iv orientations in single-window style. --> <activity android:name=".UnlockedOrientationActivity" android:screenOrientation="fullSensor" />
Locked orientation
A display has a locked orientation when it stays in the same brandish orientation (such as portrait or mural) regardless of the physical orientation of the device. This tin be done by specifying an Activity's screenOrientation property inside its declaration in the AndroidManifest.xml file.
When the display has a locked orientation, the system doesn't destroy and recreate the Activity as the device is rotated.
<!-- The Activity keeps a portrait orientation even as the device rotates. --> <activity android:name=".LockedOrientationActivity" android:screenOrientation="portrait" />
Orientation configuration changes overridden
When an Activity overrides orientation configuration changes, the arrangement doesn't destroy and recreate it when the device'southward physical orientation changes. The system updates the UI though to match the device'due south physical orientation.
<!-- The Activity's UI might non rotate in opposite portrait/landscape if the device doesn't support it past default. --> <action android:name=".OrientationConfigChangesOverriddenActivity" android:configChanges="orientation|screenSize" /> <!-- The Action's UI volition rotate to all 4 orientations in single-window mode. --> <activity android:name=".OrientationConfigChangesOverriddenActivity" android:configChanges="orientation|screenSize" android:screenOrientation="fullSensor" />
Camera use cases setup
In the scenarios described in a higher place, the camera use cases tin can be set up when the Activity is beginning created.
In the case of an Activeness with an unlocked orientation, this setup is done every time the device is rotated, equally the organization destroys and recreates the Activity on orientation changes. This results in the utilise cases setting their target rotation to lucifer the brandish'south orientation by default each time.
In the case of an Activity with a locked orientation or one that overrides orientation configuration changes, this setup is done once, when the Activity is outset created.
grade CameraActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val cameraProcessFuture = ProcessCameraProvider.getInstance(this) cameraProcessFuture.addListener(Runnable { val cameraProvider = cameraProcessFuture.get() // Past 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 setup
Using an OrientationEventListener allows you to continuously update the target rotation of the camera use cases equally the device's orientation changes.
class CameraActivity : AppCompatActivity() { individual val orientationEventListener by lazy { object : OrientationEventListener(this) { override fun onOrientationChanged(orientation: Int) { if (orientation == UNKNOWN_ORIENTATION) { 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 setup
Using a DisplayListener allows y'all to update the target rotation of the camera utilise cases in certain situations, for case when the system doesn't destroy and recreate the Activity subsequently the device rotates by 180 degrees.
class CameraActivity : AppCompatActivity() { private val displayListener = object : DisplayManager.DisplayListener { override fun onDisplayChanged(displayId: Int) { if (rootView.brandish.displayId == displayId) { val rotation = rootView.brandish.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) } } Source: https://developer.android.com/training/camerax/orientation-rotation
0 Response to "Android Pictures Are Rotated 90 Degrees When I Upload Them"
Post a Comment