Hi everyone,
I’m working with the Camera2 API to capture still images and handle device rotation properly for JPEG orientation. I’m using an OrientationEventListener to track device rotation (in degrees: 0, 90, 180, 270) and mapping these to Surface.ROTATION_* constants for orientation correction.
My current approach for JPEG orientation is:
val rotationConstant =currentDeviceOrientation
val jpegOrientation = (sensorOrientation + ORIENTATIONS.get(rotationConstant) + 270) % 360
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, jpegOrientation)
where currentDeviceOrientation is
orientationEventListener = object : OrientationEventListener(requireContext()) {
override fun onOrientationChanged(orientation: Int) {
if (orientation != ORIENTATION_UNKNOWN) {
currentDeviceOrientation = (orientation + 45) / 90 * 90/*when (orientation) {
in 45..134 -> 90 // Landscape left
in 135..224 -> 180 // Upside down
in 225..314 -> 270 // Landscape right
else -> 0 // Portrait
}*/
}
Log.e(TAG, "onOrientationChanged:$orientation---- $currentDeviceOrientation")
}
}
orientationEventListener?.enable()
and my ORIENTATIONS mapping is:
ORIENTATIONS.append(Surface.ROTATION_0, 90)
ORIENTATIONS.append(Surface.ROTATION_90, 0)
ORIENTATIONS.append(Surface.ROTATION_180, 270)
ORIENTATIONS.append(Surface.ROTATION_270, 180)
Problem:
Works fine in portrait and landscape left.
When the device is rotated to landscape right (clockwise 90°), the captured image is upside down.
Tried variants adding/subtracting 90°, 270°, or 360°, but can’t get consistent results across all orientations.
Sensor orientation is consistently 90°.
Hello,
You have hit a very common point of confusion in the Camera2 API: mixing up Device Rotation (in degrees: 0, 90, 180, 270) with Display Rotation surface constants (0, 1, 2, 3).
Your OrientationEventListener correctly calculates rotation in degrees (e.g., 270 for landscape right). However, you are using this degree value as a key to your ORIENTATIONS (SparseIntArray?). Your map uses Surface.ROTATION_* constants as keys, which are just integers 0, 1, 2, 3.
When your device is at 270°, you call ORIENTATIONS.get(270). Since 270 is not a key (only 0, 1, 2, 3 are), it returns standard default 0, messing up your calculation.
Since you are already using OrientationEventListener to get the physical device rotation in degrees, you don't need the ORIENTATIONS map or Surface constants for JPEG orientation. You can use the standard formula directly.
Here is the standard robust way to calculate JPEG_ORIENTATION that handles both front and back cameras:
For official reference, you can check the documentation for CaptureRequest.JPEG_ORIENTATION, which provides similar formulas.
I did as you said, but while the 270° (left, anti-clockwise) rotation works correctly, the issue occurs with the clockwise rotation — it rotates only 90 °. As your calculation for 90, the final orientation becomes 0.Please correct me if I'm wrong.
Hello,
The calculation (90 - 90 + 360) % 360 = 0 is mathematically correct for the formula you are using. If JPEG_ORIENTATION is 0, it tells the JPEG encoder "Do not apply any rotation."
If the resulting image is incorrect (e.g., it looks sideways or upside down) when the result is 0, it usually means one of two things:
You are using the Front Camera: The formula you are using is only for the Back Camera. The front camera requires a different calculation (sensor + rotation).
Confusion about Landscape Left vs. Right: Your comments in the OrientationEventListener are swapped.
Here is the breakdown of the issue and the corrected solution.
1. The Landscape Left/Right ConfusionIn your code comments, you have:
90° is Landscape Right (The top of the phone points to the Right).
You mentioned: "270° (left) works correctly". This is likely because (90 - 270 + 360) % 360 = 180. The image is flipped 180 degrees. You mentioned: "90° fails... becomes 0". (90 - 90) = 0. If you are holding the phone Landscape Right, the sensor is physically aligned with the horizon. 0 should be the correct rotation for a Back Camera.
2. If you are using the Front Camera (Selfie) but using the Back Camera formula (sensor - rotation), the math will fail for specific angles.If JPEG_ORIENTATION is 0, the image file is saved exactly as the sensor read it.
If you view the photo on a PC or Gallery that respects EXIF: It should look correct.
If you view the photo in a generic image viewer without EXIF support: It might look "rotated" because the raw pixel data of a phone sensor is usually 4:3 (Portrait) even when held in Landscape. The JPEG_ORIENTATION tag is what tells the viewer to rotate it to be Wide.
Please check if you are using the Front Camera. If so, the result 0 for the Back Camera formula is effectively "Upside Down" or "Mirrored" behavior depending on the angle. Using the combined function above will solve it.