Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] CamaraView Photo Rotate #2096

Open
2 tasks done
AugPav opened this issue Aug 6, 2024 · 7 comments
Open
2 tasks done

[BUG] CamaraView Photo Rotate #2096

AugPav opened this issue Aug 6, 2024 · 7 comments
Labels
bug Something isn't working Camera 📸 Issue/PR associated with the Camera package unverified

Comments

@AugPav
Copy link

AugPav commented Aug 6, 2024

Is there an existing issue for this?

  • I have searched the existing issues

Did you read the "Reporting a bug" section on Contributing file?

Current Behavior

Under certain circumstances photos are taken and displayed rotated.
Landscape
Portrait

Expected Behavior

Photos are expected to be saved/returned with the same orientation as they were captured with cameraview.

Steps To Reproduce

Using (https://github.com/CommunityToolkit/Maui/blob/main/samples/CommunityToolkit.Maui.Sample/Pages/Views/CameraView/CameraViewPage.xaml.cs)

How to reproduce the error?

1 - Position your device in portrait and do not turn the device until further notice.
2 - Enter CameraView Page
3 - Take a photo --> the photo will be displayed correctly in the image.
4 - Put the device in landscape
5 - Take a photo --> the photo will be displayed incorrectly in the image.

Take the photo without errors.

1 - Position your device in portrait and do not turn the device until further notice.
2 - Touch CameraView Page
3 - Take a photo --> the photo will be displayed correctly in the image.
4 - Exit the CameraViewPage
5 - Put the device in landscape
6 - Enter CameraView Page
3 - Take a photo --> the photo will be displayed correctly in the image.

The problem is that when taking the photo it saves the exif horientation that the device had before entering the CameraViewPage. At least that is my conclusion.

Link to public reproduction project repository

https://github.com/CommunityToolkit/Maui/blob/main/samples/CommunityToolkit.Maui.Sample/Pages/Views/CameraView/CameraViewPage.xaml.cs

Environment

- .NET MAUI CommunityToolkit:8.0.1
- OS:Windows 10 Build 10.0.19041.0
- .NET MAUI: 8.0
. (Samsung Flip 5 Android 14 / Samsung S24 Android 14 / Samsung Galaxy A03 Core Android 13  )

Anything else?

No response

@AugPav
Copy link
Author

AugPav commented Aug 20, 2024

In the following table you can see the results obtained from the different tests carried out to determine the image recording position according to the position of the device.

Description of the columns:

Start orientation: Position in which the device is located before entering the camera view.

Camera view orientation: Position in which the device is located when capturing the image.

Exif.Rotation: Orientation that is recorded in the exif.

Image:* Example of how the image looks WITH the exif.

Image WITHOUT Exif: Example of how the image looks WITHOUT the exif.

Necessary rotation: Rotation necessary for the image to be correctly oriented.

Exif.Rotation: Orientation that is recorded in the exif.

Image: Example of how the image looks WITHOUT the exif.

Subtraction logic Rear: Logic used so that the image is always in view in a well-positioned position. In which “Camera view orientation” is subtracted from “Start orientation”.

Samsung equipment used for the tests: Samsung s24, z flip, s8.

Motorola equipment used for the test: Motorola e22.

Tables:

Rear Camera:

Samsung s24, z flip, s8 Camera with Exif Data. Motorola e22 Camera without Exif Data
Device Image 1 Image 2 Logic Image 1 Logic
Orientation start Orientation camera view Exif.Rotation Image Image without Exif Necessary rotation Exif.Rotation Exif.Image Necessary rotation
90 90 Not detected Subtraction logic Rear
90 0 Not detected Subtraction logic Rear
90 -90 Not detected Subtraction logic Rear
90 180 Not detected Subtraction logic Rear
0 90 Sin rotacion Subtraction logic Rear
0 0 Sin rotacion Subtraction logic Rear
0 -90 Sin rotacion Subtraction logic Rear
0 180 Sin rotacion Subtraction logic Rear
-90 90 Not detected Subtraction logic Rear
-90 0 Not detected Subtraction logic Rear
-90 -90 Not detected Subtraction logic Rear
-90 180 Not detected Subtraction logic Rear
180 90 Not detected Subtraction logic Rear
180 0 Not detected Subtraction logic Rear
180 -90 Not detected Subtraction logic Rear
180 180 Not detected Subtraction logic Rear

Camara Frontal:

Front Subtraction Logic: Logic used to keep the image always in the correct position. In which the orientation of the device when taking the photo with the front camera is subtracted from the orientation of the device before touching the camera switch button.

Samsung Motorola
Device Image 1 Image 2 Rotacion Image 1 Rotacion
Vista camara trasera Vista camara frontal Exif.Rotation Image Image without Exif Necessary rotation Exif.Rotation Image Necessary rotation
-90 -90 Not detected Front Subtraction Logic
-90 0 Not detected Front Subtraction Logic
-90 90 Not detected Front Subtraction Logic
-90 180 Not detected Front Subtraction Logic
0 -90 Not detected Front Subtraction Logic
0 0 Not detected Front Subtraction Logic
0 90 Not detected Front Subtraction Logic
0 180 Not detected Front Subtraction Logic
90 -90 Not detected Front Subtraction Logic
90 0 Not detected Front Subtraction Logic
90 90 Not detected Front Subtraction Logic
90 180 Not detected Front Subtraction Logic
180 -90 Not detected Front Subtraction Logic
180 0 Not detected Front Subtraction Logic
180 90 Not detected Front Subtraction Logic
180 180 Not detected Front Subtraction Logic

To solve the problem on Android, after obtaining the image I leave you a code extract

    private void MyCamera_MediaCaptured(object sender, CommunityToolkit.Maui.Views.MediaCapturedEventArgs e)
    {
        try
        {
            if (Dispatcher.IsDispatchRequired)
            {
                Dispatcher.Dispatch(() =>
                {
                    using (var memoryStream = new MemoryStream())
                    {
                        MediaCaptured(e);
                    }
                });
                return;
            }
            MediaCaptured(e);
        }
        catch (Exception ex)
        {
            var a = ex.ToString();

        }
    }

  private void MediaCaptured(CommunityToolkit.Maui.Views.MediaCapturedEventArgs e)
  {
      int ExifOrientation = 0;

      using (var memoryStream = new MemoryStream())
      {
          //Toma la foto
          e.Media.CopyTo(memoryStream);
          memoryStream.Position = 0;
          MyImage.Source = ImageSource.FromStream(() => new MemoryStream(memoryStream.ToArray()));

          memoryStream.Position = 0;
          ExifOrientation = ExifOrientation_Get(memoryStream);
          deviceOrientationPreviusPage = tPhotoDto.OrientationPreviusPage;
          int OrientationPreviusPageDegrees = Utils.Tools.ConvertDeviceDisplayRotationToDegrees(deviceOrientationPreviusPage);
          int OrientationCameraViewPageDegrees = Utils.Tools.ConvertDeviceDisplayRotationToDegrees(DeviceOrientationCameraViewPage);
          int ExifOrientationDegrees = ConvertExitOrientationToDegress(ExifOrientation);

          PhotoRotateLogic(ExifOrientation, memoryStream);
      }
  }

    private void PhotoRotateLogic(int ExifOrientation, MemoryStream memoryStream)
    {
        memoryStream.Position = 0;

        if (ExifOrientation != 0)
        {
            PhotoRotateLogicWithExif(memoryStream);
        }
        else
        {
            PhotoRotateLogicUnExif(memoryStream);
        }
        MyImageRotate.Source = ImageSource.FromStream(() => new MemoryStream(fotoBytes));
    }

    private void PhotoRotateLogicWithExif(MemoryStream memoryStream)
    {
        int rotateDegrees = 0;

        //se eliminalos exif. En funcion de la orientacion de esta page
        //se rota la foto, ya que el cameraView tiene un bug que 
        //no se orienta la foto como se correctamente.

        if (MyCamera.SelectedCamera?.Position == CameraPosition.Rear)
        {
            switch (DeviceOrientationCameraViewPage)
            {
                case 1:
                    rotateDegrees = 90;
                    break;

                case 2:
                    rotateDegrees = 0;
                    break;

                case 3:
                    rotateDegrees = -90;
                    break;

                case 4:
                    rotateDegrees = 180;
                    break;
            }
        }
        else
        {
            switch (DeviceOrientationCameraViewPage)
            {
                case 1:
                    rotateDegrees = -90;
                    break;

                case 2:
                    rotateDegrees = 0;
                    break;

                case 3:
                    rotateDegrees = 90;
                    break;

                case 4:
                    rotateDegrees = 180;
                    break;
            }

        }

        fotoBytes = RotateImage(memoryStream, rotateDegrees).ToArray();

    }

    private void PhotoRotateLogicUnExif(MemoryStream memoryStream)
    {
        int rotateDegrees = 0;

        if (MyCamera.SelectedCamera?.Position == CameraPosition.Rear)
        {
            rotateDegrees = Utils.Tools.ConvertDeviceDisplayRotationToDegrees(deviceOrientationPreviusPage) - Utils.Tools.ConvertDeviceDisplayRotationToDegrees(DeviceOrientationCameraViewPage);
        }
        else
        {
            rotateDegrees = Utils.Tools.ConvertDeviceDisplayRotationToDegrees(DeviceOrientationCameraViewPage) - Utils.Tools.ConvertDeviceDisplayRotationToDegrees(DeviceOrientationWhenSeletedCameraFront);
        }

        fotoBytes = RotateImage(memoryStream, rotateDegrees).ToArray();

    }
    public static MemoryStream RotateImage(Stream imageStream, int rotateDegrees)
    {
        if (imageStream.CanSeek)
        {
            imageStream.Seek(0, SeekOrigin.Begin);
        }

        // Cargar la imagen original desde el stream
        using (var original = SKBitmap.Decode(imageStream))
        {
            SKBitmap rotatedBitmap;

            rotatedBitmap = RotateBitmap(original, rotateDegrees);

            // Crear un nuevo MemoryStream para la imagen rotada
            var rotatedStream = new MemoryStream();
            rotatedBitmap.Encode(rotatedStream, SKEncodedImageFormat.Jpeg, 100);
            rotatedStream.Seek(0, SeekOrigin.Begin);

            rotatedStream.Position = 0;
            return rotatedStream;
        }
    }

    private static SKBitmap RotateBitmap(SKBitmap original, float degrees)
    {

        int width = degrees == 90 || degrees == -90 || degrees == 270 || degrees == -270 ? original.Height : original.Width;
        int height = degrees == 90 || degrees == -90 || degrees == 270 || degrees == -270 ? original.Width : original.Height;

        var rotatedBitmap = new SKBitmap(width, height);

        using (var surface = SKSurface.Create(new SKImageInfo(width, height)))
        {
            var canvas = surface.Canvas;
            canvas.Clear(SKColors.Transparent);

            canvas.Translate(width / 2, height / 2);
            canvas.RotateDegrees(degrees);
            canvas.Translate(-original.Width / 2, -original.Height / 2);
            canvas.DrawBitmap(original, new SKPoint(0, 0));

            using (var img = surface.Snapshot())
            using (var pixmap = img.PeekPixels())
            {
                pixmap.ReadPixels(rotatedBitmap.Info, rotatedBitmap.GetPixels(), rotatedBitmap.RowBytes);
            }
        }
        return rotatedBitmap;
    }

@bijington
Copy link
Contributor

Sorry we are primarily English speaking on this team. It looks like you have provided a lot of detail but I don't understand it. Would you mind translating it into English please?

@AugPav
Copy link
Author

AugPav commented Aug 21, 2024

Sorry we are primarily English speaking on this team. It looks like you have provided a lot of detail but I don't understand it. Would you mind translating it into English please?

@bijington Done!! :)

@bijington
Copy link
Contributor

That is really helpful, thank you

@AugPav
Copy link
Author

AugPav commented Aug 22, 2024

That is really helpful, thank you
@bijington If you need a testing project, ask me and I will prepare it!

@MiklosPathy
Copy link

I have the same problem. It behaves totally differently on different devices, so it is impossible to fix it with a simple rotate.

@AugPav
Copy link
Author

AugPav commented Sep 16, 2024

I have the same problem. It behaves totally differently on different devices, so it is impossible to fix it with a simple rotate.

Look at the solution, I think we covered all the possibilities there

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working Camera 📸 Issue/PR associated with the Camera package unverified
Projects
None yet
Development

No branches or pull requests

4 participants