Search code examples
c#xamarin.formsimage-rotationxamarin.essentialsandroid-image-capture

CapturePhotoAsync function on Xamarin Forms works well on emulator but rotates images on debugging with actual device


The Xamarin Essentials MediaPicker function to capture with camera using the CapturePhotoAsync runs correctly on the emulator but behaves differently when a mobile phone is connected to debug the program. I believe this is a bug and I would appreciate if anyone can help with a work around.

 private async void Capture_Photo(object sender, EventArgs e)
        {
            var result = await MediaPicker.CapturePhotoAsync();
            if (result != null)
            {          
                var stream = await result.OpenReadAsync();

                statBitmap = SKBitmap.Decode(stream);
               
               
            }
        }

From here I am using the SkiaSharp CanvasViewPaintSurface to display the bitmap on canvas


Solution

  • As @Jason mentioned, SkiaSharp may not use the EXIF orientation data from the image. So we have to obtain the EXIF orientation information and determine what transform the image should take.

    Referring to iPhone image orientation wrong when resizing with SkiaSharp, I tried the following code to get the orientation data:

    var stream = await result.OpenReadAsync();
    using (var inputStream = new SKManagedStream(stream))
    {
        using (var codec = SKCodec.Create(inputStream))
        {
            orientation = codec.Origin;
        }
    }
    

    I deployed my app on Andriod physical device, and it returned RightTop.

    Then we should determine the degree the image should rotate or other transformation such as reversal according to the orientation. For this part, you could refer to Image auto orientation method. Once the transformation is determined, we could draw the Bitmap.

     private void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs e)
        {
            SKImageInfo info = e.Info;
            SKSurface surface = e.Surface;
            SKCanvas canvas = surface.Canvas;
            var width = statBitmap.Width;
            var height = statBitmap.Height;
            canvas.Clear();
    
            switch (orientation)  
            {
                case SKCodecOrigin.TopLeft:
                    canvas.RotateDegrees(90, info.Width / 2, info.Height / 2);
                    canvas.Scale(height * 1.0f / width, -width * 1.0f / height, info.Width / 2, info.Height / 2);
                    break;
                case SKCodecOrigin.TopRight:
                    canvas.Scale(-1, 1,info.Width/2,info.Height / 2);
                    break;
                case SKCodecOrigin.BottomRight:
                    canvas.RotateDegrees(180, info.Width / 2, info.Height / 2);
                    break;
                case SKCodecOrigin.BottomLeft:
                    canvas.Scale(1, -1, info.Width / 2, info.Height / 2);
                    break;
                case SKCodecOrigin.LeftTop:
                    canvas.RotateDegrees(90, info.Width / 2, info.Height / 2);
                    canvas.Scale(height * 1.0f / width, -width * 1.0f / height,  info.Width / 2, info.Height / 2);
                    break;
                case SKCodecOrigin.RightTop:
                    canvas.RotateDegrees(90, info.Width / 2, info.Height / 2);
                    canvas.Scale(height * 1.0f / width, width * 1.0f / height, info.Width / 2, info.Height / 2);
                    break;
                case SKCodecOrigin.RightBottom:
                    canvas.RotateDegrees(90, info.Width / 2, info.Height / 2);
                    canvas.Scale(-height * 1.0f / width, width * 1.0f / height, info.Width / 2, info.Height / 2);
    
                    break;
                case SKCodecOrigin.LeftBottom:
                    canvas.RotateDegrees(90, info.Width / 2, info.Height / 2);
                    canvas.Scale(-height * 1.0f / width, -width * 1.0f / height, info.Width / 2, info.Height / 2);
    
                    break;
                default:
                    break;
            }
    
            canvas.DrawBitmap(statBitmap, info.Rect);       
        }  
    

    Hope my answer works for you.

    ========origin answer====

    In SKiasharp, you could use the following code:

     canvas.RotateDegrees(90, xCenter, yCenter);
    

    to rotate the photo. For more information, you could refer to The Rotate Transform