From 2bcc7235c0f09b93782dd0ed0f91e648a2b32eaa Mon Sep 17 00:00:00 2001 From: Bartlomiej Moskal Date: Tue, 9 May 2023 14:25:28 +0200 Subject: Android-backend: Fix for Captured Image rotation When using android-camera backend, the result photo was not correctly rotated for landscape orientation. Preview rotation is handled by [0]setDisplayOrientation method, but it does not affect taking pictures and recording. Recording is handled by [1]setOrientationHint. Both mentioned methods use QAndroidCameraSession::currentCameraRotation for rotate correction. It is reasonable to handle photo rotation in the same way. This commit removes a special rotation handling from onPictureTaken java method and move it to QAndroidCameraSession. That allows to handle photo rotation in the same way as preview rotation and recording rotation. https://developer.android.com/reference/android/hardware/Camera#setDisplayOrientation(int) https://developer.android.com/reference/android/media/MediaRecorder#setOrientationHint(int) Fixes: QTBUG-113029 Pick-to: 6.5 6.2 Change-Id: I2d08fef43fbd78faeafc7e20e100329e75019679 Reviewed-by: Lars Knoll --- .../qt/android/multimedia/QtCameraListener.java | 70 ---------------------- .../android/mediacapture/qandroidcamerasession.cpp | 16 +++++ 2 files changed, 16 insertions(+), 70 deletions(-) diff --git a/src/android/jar/src/org/qtproject/qt/android/multimedia/QtCameraListener.java b/src/android/jar/src/org/qtproject/qt/android/multimedia/QtCameraListener.java index e1391142c..cb0fcfa0e 100644 --- a/src/android/jar/src/org/qtproject/qt/android/multimedia/QtCameraListener.java +++ b/src/android/jar/src/org/qtproject/qt/android/multimedia/QtCameraListener.java @@ -9,15 +9,7 @@ import android.hardware.Camera.CameraInfo; import android.graphics.ImageFormat; import android.graphics.SurfaceTexture; import android.util.Log; -import java.io.File; -import java.io.FileOutputStream; import java.lang.Math; -import android.media.ExifInterface; -import java.io.ByteArrayOutputStream; -import java.lang.String; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Matrix; public class QtCameraListener implements Camera.ShutterCallback, Camera.PictureCallback, @@ -172,68 +164,6 @@ public class QtCameraListener implements Camera.ShutterCallback, @Override public void onPictureTaken(byte[] data, Camera camera) { - File outputFile = null; - try { - outputFile = File.createTempFile("pic_", ".jpg", QtMultimediaUtils.getCacheDirectory()); - FileOutputStream out = new FileOutputStream(outputFile); - - // we just want to read the exif... - BitmapFactory.decodeByteArray(data, 0, data.length) - .compress(Bitmap.CompressFormat.JPEG, 10, out); - - ExifInterface exif = new ExifInterface(outputFile.getAbsolutePath()); - int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, - ExifInterface.ORIENTATION_UNDEFINED); - - int degree = 0; - - switch (orientation) { - case ExifInterface.ORIENTATION_ROTATE_90: - degree = 90; - break; - case ExifInterface.ORIENTATION_ROTATE_180: - degree = 180; - break; - case ExifInterface.ORIENTATION_ROTATE_270: - degree = 270; - break; - } - - Camera.CameraInfo info = new Camera.CameraInfo(); - Camera.getCameraInfo(m_cameraId, info); - - int rotation = (info.orientation - degree + 360) % 360; - - Bitmap source = BitmapFactory.decodeByteArray(data, 0, data.length); - Matrix matrix = new Matrix(); - matrix.postRotate(rotation); - - if (info.facing == CameraInfo.CAMERA_FACING_FRONT) { - matrix.postScale(-1, 1, source.getWidth() / 2.0f, source.getHeight() / 2.0f); - } - - Bitmap rotatedBitmap = Bitmap.createBitmap(source, 0, 0, source.getWidth(), - source.getHeight(), matrix, true); - - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - rotatedBitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream); - byte[] byteArray = outputStream.toByteArray(); - - rotatedBitmap.recycle(); - source.recycle(); - - notifyPictureCaptured(m_cameraId, byteArray); - - return; - - } catch (Exception e) { - Log.w(TAG, "Error fixing bitmap orientation."); - e.printStackTrace(); - } finally { - if (outputFile != null && outputFile.exists()) - outputFile.delete(); - } - notifyPictureCaptured(m_cameraId, data); } diff --git a/src/plugins/multimedia/android/mediacapture/qandroidcamerasession.cpp b/src/plugins/multimedia/android/mediacapture/qandroidcamerasession.cpp index d6aee3aff..c1f661d28 100644 --- a/src/plugins/multimedia/android/mediacapture/qandroidcamerasession.cpp +++ b/src/plugins/multimedia/android/mediacapture/qandroidcamerasession.cpp @@ -660,6 +660,22 @@ void QAndroidCameraSession::onNewPreviewFrame(const QVideoFrame &frame) void QAndroidCameraSession::onCameraPictureCaptured(const QVideoFrame &frame) { + // Frame needs to be correctly rotated before image proccessing. We are using + // the same rotation angle that was used for preview with setDisplayOrientation + auto rotation = QVideoFrame::Rotation0; + switch (currentCameraRotation()) { + case 90: + rotation = QVideoFrame::Rotation90; + break; + case 180: + rotation = QVideoFrame::Rotation180; + break; + case 270: + rotation = QVideoFrame::Rotation270; + break; + } + const_cast(frame).setRotationAngle(rotation); + // Loading and saving the captured image can be slow, do it in a separate thread (void)QtConcurrent::run(&QAndroidCameraSession::processCapturedImage, this, m_currentImageCaptureId, frame, m_imageCaptureToBuffer, -- cgit v1.2.1