question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Image auto orientation method

See original GitHub issue

When uploading an image from mobile, it is always rotated to landscape view. But when you access the image in code you usually want to save it in correct orientation.

At the moment, there is no easy way to rotate the image. So it would be nice to have something like AutoOrient() which would correctly rotate the image based on its EXIF data.

Issue Analytics

  • State:open
  • Created 4 years ago
  • Reactions:2
  • Comments:13 (4 by maintainers)

github_iconTop GitHub Comments

12reactions
iainxtcommented, Sep 29, 2022

It took my brain awhile to catch up on it, so to save others time here is the code I am using. I have tested this on all origins and it works.

        public Stream FixImageOrientation(Stream stream, out int width, out int height)
        {
            try { stream.Position = 0; } catch (NotSupportedException) { }
            using (var inputStream = new SKManagedStream(stream))
            {
                using (var codec = SKCodec.Create(inputStream))
                {
                    using (var original = SKBitmap.Decode(codec))
                    {
                        var useWidth = original.Width;
                        var useHeight = original.Height;
                        Action<SKCanvas> transform = canvas => { };
                        switch (codec.EncodedOrigin)
                        {
                            case SKEncodedOrigin.TopLeft:
                                break;
                            case SKEncodedOrigin.TopRight:
                                // flip along the x-axis
                                transform = canvas => canvas.Scale(-1, 1, useWidth / 2, useHeight / 2);
                                break;
                            case SKEncodedOrigin.BottomRight:
                                transform = canvas => canvas.RotateDegrees(180, useWidth / 2, useHeight / 2);
                                break;
                            case SKEncodedOrigin.BottomLeft:
                                // flip along the y-axis
                                transform = canvas => canvas.Scale(1, -1, useWidth / 2, useHeight / 2);
                                break;
                            case SKEncodedOrigin.LeftTop:
                                useWidth = original.Height;
                                useHeight = original.Width;
                                transform = canvas =>
                                {
                                    // Rotate 90
                                    canvas.RotateDegrees(90, useWidth / 2, useHeight / 2);
                                    canvas.Scale(useHeight * 1.0f / useWidth, -useWidth * 1.0f / useHeight, useWidth / 2, useHeight / 2);
                                };
                                break;
                            case SKEncodedOrigin.RightTop:
                                useWidth = original.Height;
                                useHeight = original.Width;
                                transform = canvas =>
                                {
                                    // Rotate 90
                                    canvas.RotateDegrees(90, useWidth / 2, useHeight / 2);
                                    canvas.Scale(useHeight * 1.0f / useWidth, useWidth * 1.0f / useHeight, useWidth / 2, useHeight / 2);
                                };
                                break;
                            case SKEncodedOrigin.RightBottom:
                                useWidth = original.Height;
                                useHeight = original.Width;
                                transform = canvas =>
                                {
                                    // Rotate 90
                                    canvas.RotateDegrees(90, useWidth / 2, useHeight / 2);
                                    canvas.Scale(-useHeight * 1.0f / useWidth, useWidth * 1.0f / useHeight, useWidth / 2, useHeight / 2);
                                };
                                break;
                            case SKEncodedOrigin.LeftBottom:
                                useWidth = original.Height;
                                useHeight = original.Width;
                                transform = canvas =>
                                {
                                    // Rotate 90
                                    canvas.RotateDegrees(90, useWidth / 2, useHeight / 2);
                                    canvas.Scale(-useHeight * 1.0f / useWidth, -useWidth * 1.0f / useHeight, useWidth / 2, useHeight / 2);
                                };
                                break;
                            default:
                                break;
                        }
                        var info = new SKImageInfo(useWidth, useHeight);
                        using (var surface = SKSurface.Create(info))
                        {
                            using (var paint = new SKPaint())
                            {
                                // high quality with antialiasing
                                paint.IsAntialias = true;
                                paint.FilterQuality = SKFilterQuality.High;

                                // rotate according to origin
                                transform.Invoke(surface.Canvas);

                                // draw the bitmap to fill the surface
                                surface.Canvas.DrawBitmap(original, info.Rect, paint);
                                surface.Canvas.Flush();

                                using (var image = surface.Snapshot())
                                {
                                    var output = new MemoryStream();
                                    using (var data = image.Encode(SKEncodedImageFormat.Jpeg, _azureStorageConfig.OriginalImageQuality))
                                    {
                                        data.SaveTo(output);
                                        width = useWidth;
                                        height = useHeight;
                                        return output;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
5reactions
deivyd321commented, Sep 29, 2022

At the moment it doesn’t exist. But it can be solved with this method.

private static SKBitmap AutoOrient(SKBitmap bitmap, SKEncodedOrigin origin)
        {
            SKBitmap rotated;
            switch (origin)
            {
                case SKEncodedOrigin.BottomRight:
                    using (var surface = new SKCanvas(bitmap))
                    {
                        surface.RotateDegrees(180, bitmap.Width / 2, bitmap.Height / 2);
                        surface.DrawBitmap(bitmap.Copy(), 0, 0);
                    }
                    return bitmap;
                case SKEncodedOrigin.RightTop:
                    rotated = new SKBitmap(bitmap.Height, bitmap.Width);
                    using (var surface = new SKCanvas(rotated))
                    {
                        surface.Translate(rotated.Width, 0);
                        surface.RotateDegrees(90);
                        surface.DrawBitmap(bitmap, 0, 0);
                    }
                    return rotated;
                case SKEncodedOrigin.LeftBottom:
                    rotated = new SKBitmap(bitmap.Height, bitmap.Width);
                    using (var surface = new SKCanvas(rotated))
                    {
                        surface.Translate(0, rotated.Height);
                        surface.RotateDegrees(270);
                        surface.DrawBitmap(bitmap, 0, 0);
                    }
                    return rotated;
                default:
                    return bitmap;
            }
        }
Read more comments on GitHub >

github_iconTop Results From Across the Web

When Should I Auto-Orient My Images?
The recommended Roboflow setting is "Auto-Orient: Enabled". When should you auto-orient your images? The short answer: almost always.
Read more >
How to auto rotate the image using Deep learning!!!
5 simple steps to auto rotate the image to get the right angle in the human photos using computer vision · Read the...
Read more >
JPEG Image Orientation and Exif
When you are holding the camera with non-upright position, the raw photo you take is stored as a rotated image. The digital device...
Read more >
Image::orientate | Intervention Image v2 | intervention.io
This method reads the EXIF image profile setting 'Orientation' and performs a rotation on the image to display the image correctly. Image object...
Read more >
Auto rotating / orientation of photos - Adobe Support Community
The information panel shows both the value of the orientation: 'normal' or 'Rotate 90'; it also shows the width and height in pixels,...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found