question

JuggernOtt81-7927 avatar image
0 Votes"
JuggernOtt81-7927 asked LeonLu-MSFT edited

easy rotate and crop on freshly shot image (essential:media picker)?

so, I've implemented the media picker from Xamarin.Essentials to capture from camera. works in iOS, android and UWP. nice!
but i'm not sure how to proceed. on iOS and android, when i take the photo in portrait mode, the image is rotated 90 degrees.
don't feel i should educate the user in app to rotate the phone to take the picture.
a) how to force the native camera's pic to stay in the orientation it was taken?
b) whether "a" happens or not, how to allow user to then and there rotate and crop image before it becomes the official image to be used? (trying to not use 3rd party stuff. trying to stay very xamarin-basics as much as possible.)

thanks.


XAML:

<Entry x:Name="UPC" Placeholder="[passed in UPC string]"/>
                    <Entry x:Name="ProductName" Placeholder="Flite"/>
                    <Entry x:Name="Count" Placeholder="15"/>
                    <Entry x:Name="SellPrice" Placeholder="0"/>
                    <Entry x:Name="BaseBuyingPrice" Placeholder="0"/>
                    <Button x:Name="CameraButton" Text="Take Image" Clicked="CameraButton_Clicked" />
                    <Image x:Name="resultImage" />
                    <Button x:Name="SaveProduct" Text="Save Product" Clicked="SaveProduct_Clicked"/>


C#:

private async void CameraButton_Clicked(System.Object sender, System.EventArgs e)
            {
                var result = await MediaPicker.CapturePhotoAsync();
    
                if (result != null)
                {
                    var stream = await result.OpenReadAsync();
    
                    resultImage.Source = ImageSource.FromStream(() => stream);
                }
            }
            private void SaveProduct_Clicked(object sender, EventArgs e)
            {
                //add this product and all its fields to the database with the UPC string as the key/unique identifier
                Navigation.PushAsync(new AllProductsPage());
            }
dotnet-xamarin
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

1 Answer

LeonLu-MSFT avatar image
0 Votes"
LeonLu-MSFT answered LeonLu-MSFT edited

Hello,​

Welcome to our Microsoft Q&A platform!

First of all, there is an active bug on this:

https://github.com/xamarin/Essentials/issues/1514

It doesn't have a fix yet.

Here is a workaround.

If you want to rotate the image, you can use SkiaSharp, it is not third-part plugin.

You can use following code to rotate the image.

using SkiaSharp;
using SkiaSharp.Views.Forms;
using System;
using System.ComponentModel;
using System.IO;
using Xamarin.Essentials;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace App114.Views
{
    public partial class AboutPage : ContentPage
    {
        // Save bitmaps for later use.
        static SKBitmap m_bm;
        static SKBitmap m_editedBm;

        // Boolean for displaying the image captured with the camera.
        bool m_displayedImage;

        public AboutPage()
        {
            // Set to explicit default values to always be in control of the assignments.
            m_bm = null;
            m_editedBm = null;

            // No picture has been taken yet.
            m_displayedImage = false;

            InitializeComponent();
        }

        // Assigned to the button in the xaml page.
        private async void SnapPicture(System.Object sender, System.EventArgs e)
        {
            // Let user take a picture.
            var result = await MediaPicker.CapturePhotoAsync(new MediaPickerOptions
            {
                Title = "Take a picture"
            });

            // Save stream.
            var stream = await result.OpenReadAsync();

            // Create the bitmap.
            m_bm = SKBitmap.Decode(stream);

            // Get the rotated image.
            m_editedBm = Rotate();

            SKImage image = SKImage.FromPixels(m_editedBm.PeekPixels());
            SKData encoded = image.Encode();
            // get a stream over the encoded data
            Stream streamRotat = encoded.AsStream();
            resultImage.Source = ImageSource.FromStream(() => streamRotat);
            // Set to true because the image will be prepared soon.
            m_displayedImage = true;
        }

        public static SKBitmap Rotate()
        {
            using (var bitmap = m_bm)
            {
                var rotated = new SKBitmap(bitmap.Height, bitmap.Width);

                using (var surface = new SKCanvas(rotated))
                {
                    surface.Translate(bitmap.Width, 0);
                    surface.RotateDegrees(90);
                    surface.DrawBitmap(bitmap, 0, 0);
                }

                return rotated;
            }
        }

        private void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs e)
        {
            if (m_bm != null && m_displayedImage == true)
            {
                e.Surface.Canvas.Clear();

                // Draw in a new rect space.
                e.Surface.Canvas.DrawBitmap(m_editedBm, new SKRect(0.0f, 0.0f, 300.0f, 300.0f));

                // ---Testing.
                // e.Surface.Canvas.DrawBitmap(m_editedBm, new SKRect(112, 238, 184, 310), new SKRect(0, 0, 9, 9));

                // Avoid having this function launch again for now.
                m_displayedImage = false;
            }
        }
    }

}


Best Regards,

Leon Lu



If the response is helpful, please click "Accept Answer" and upvote it.

Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


· 7
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

@JuggernOtt81-7927 May I know whether your issue has been solved or not? If not, please share it in here. We can work together to figure it out.

0 Votes 0 ·

sorry. for some reason it didn't load your post, just the comment. anyway, i see the post now. and checking it out. thank you!

0 Votes 0 ·

i keep getting errors on this line. not sure what to make of it since i'm not well verse on Skia.Net yet.

CS1061 'SKImage' does not contain a definition for 'Source' and no accessible extension method 'Source' accepting a first argument of type 'SKImage' could be found

 resultImage.Source = ImageSource.FromStream(() => streamRotat);


0 Votes 0 ·

resultImage is an Image control, not SKImage, and If you used skiasharp in xamarin forms, you need to install SkiaSharp.Views.Forms nuget package.


0 Votes 0 ·

i had already got the SkiaSharp nugets installed.
the resultImage thing was because i had my xaml commented out. so i feel stupid.

finally got it back to taking pictures with the new code.
in UWP my old code gets and upright image, new code gets 90 degrees clockwise image
in android my old code gets 90 degrees clockwise image, new code gets 180 clockwise image
in iOS my old code gets 90 degrees counter-clockwise, new code gets upright image.

i guess i /could/ do a switch statement for environment to set which degrees in which direction.

but i had assumed that since it's such a common practice, there would be something that would allow the user to select rotation and cropping.

0 Votes 0 ·
Show more comments