0

I'm trying to get an image in skiasharp that's left rotated by 90 degrees to be centered and fit perfectly on the canvas. I've tried 2 ways. My own custom way, and another one that seems like a popular solution but maybe I'm not understanding how it works correctly?

  1. My own way.

Here is the code:

SKSurface surf = e.Surface;
SKCanvas canvas = surf.Canvas;
SKSize size = canvasView.CanvasSize;
canvas.Clear();

SKRect rect = SKRect.Create(0.0f, 0.0f, size.Height, size.Width);
canvas.RotateDegrees(85);
canvas.DrawBitmap(m_bm, rect);

"m_bm" is a bitmap that was retrieved in a separate function. That function is:

// 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);

// Set to true because the image will be prepared soon.
m_displayedImage = true;

I only put 85 instead of 90 because I wanted to visually see it getting closer but when I do that, it goes off screen. I'm coming from a game programming background so this is normally solved with getting the width of whatever we're working with (like the player in the game) and adding that to the x position, and boom. But with Xamarin, didn't work. That's my own attempt. Then I hit the internet of course to find help, and a different implementation was given to me.

  1. Popular solution.

See here for this popular solution and it's the FIRST answer to this users question. The code I used is SLIGHTLY different because I didn't see the point in returning an image in that users function. Here it is:

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

        using (var bitmap = SKBitmap.Decode(stream))
        {
            var rotated = new SKBitmap(bitmap.Height, bitmap.Width);

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

I'm drawing the bitmap with the canvas and I thought that would work because testing it in other code samples it did exactly that, so I definitely am not rotating properly or something?

Red
  • 26,798
  • 7
  • 36
  • 58
Omar Moodie
  • 263
  • 3
  • 13
  • in the 2nd example, `rotated` is your modified bitmap. It will go out of scope when the using statement completes. Are you doing anything to preserve or return the modified bitmap? – Jason Feb 07 '21 at 23:25
  • Hmmm, that makes sense with the using statement. I was using it differently then the link I posted which is here: https://stackoverflow.com/questions/45077047/rotate-photo-with-skiasharp . I was confused because I thought that SKCanvas called surface would draw my bitmap and it would be fine. – Omar Moodie Feb 07 '21 at 23:26
  • that's just a SKCanvas object you created in memory, it is not tied to the device display – Jason Feb 07 '21 at 23:28
  • Interesting. So I'll give a try at saving the bitmap in a separate variable a try and then calling that function to have it save the edited bitmap, and finally drawing the new edited bitmap in the function "OnCanvasViewPaintSurface". – Omar Moodie Feb 07 '21 at 23:33
  • @OmarMoodie Hi, if you have solved it, remember to uopate the solution in answer when you have time. – Junior Jiang Feb 08 '21 at 02:49
  • Does this answer your question? [Rotate photo with SkiaSharp](https://stackoverflow.com/questions/45077047/rotate-photo-with-skiasharp) – Cheesebaron Feb 08 '21 at 09:20
  • @Cheesebaron I seen that before but to be honest I think it was my own lack of knowledge on C# that made it NOT work because I did remove the "static" keyword from the person's (individual who posted a solution to that link) function among other things. I'm currently editing the code right now. Will give updates soon – Omar Moodie Feb 09 '21 at 01:15
  • @JuniorJiang-MSFT Of course – Omar Moodie Feb 09 '21 at 01:16

1 Answers1

0

The link that @Cheesebaron gave me in the reply to the original post ended up working out. But a new issue arises but I'll google that myself. Here's my own code:

namespace BugApp
{


public partial class MainPage : 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 MainPage()
    {
        // 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(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();

        // 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;
        }
    }
}

}

The main portion of code that matters is the rotate function which was this one here: Link.

Thanks to everyone that replied.

Omar Moodie
  • 263
  • 3
  • 13