3

I am trying to write a drawing application that allows users to select two points on canvas and draws a line between those points pixel-by-pixel. In WinForms that would be an easy solution - create a canvas, get its bitmap, draw on the bitmap using the SetPixel method, and replace the canvas bitmap. I am wondering if there is a way to do this in a similar way in AvaloniaUI? From what I understood, it uses SkiaSharp under the hood. However, solutions to render SKCanvas on Avalonia.Controls.Canvas seem... hard. Although SKBitmap also has the SetPixel method. The question is not about how to draw a line - it is about how to set single pixels on Bitmap in AvaloniaUI and set this bitmap to the Avalonia.Controls.Canvas. Here are some links I found:

P.S. As tempting as this may sound, drawing a rectangle-by-rectangle of size 1x1 as in the official documentation example (https://docs.avaloniaui.net/docs/controls/canvas) is also not allowed by the university.

P.P.S. I am not asking anyone to do the homework for me - in case you are worried about that please, consider this a framework comparison question, not a "please do that for me" one. I have found and linked solutions that I can use - it just seems to me that there should be a more easy way to achieve the result I seek. That's why I have asked the question - in case I missed something.

Doing a Jedi thing: this is not some student trying to lay off his work on other people. You can go by your business

  • 2
    @LeeTaylor - I am allowed to use the `SetPixel` method. Unfortunately, there is no such method on any of the native `AvaloniaUI` bitmaps. It is on the `SkBitmap` and `System.Drawing.Bitmap` - but converting between different bitmap types doesn't seem like a concise solution to me (the examples I have linked show how to achieve this, though). Regarding drawing lines: this is not a part of my question - everything you have described is actually a part of the task - Implement correct line drawing, anti-aliasing, and thickness modification algorithms using `SetPixel`. Those I know how to do – Kiryl Volkau Apr 22 '22 at 21:22
  • 1
    @KirylVolkau Perhaps you can use writeableBitmap? https://stackoverflow.com/questions/63209683/artifacts-on-avalonia-writeablebitmap-bitmapcontext – Lee Taylor Apr 22 '22 at 21:41
  • 1
    @LeeTaylor oh yes, thank you. This was also one of the solutions I looked at, forgot to reference it. This is the solution that uses `unsafe` code for pixel copying and requires three additional extension methods. This is indeed an option - still, I think the framework should have something that will just work, not requiring users to re-invent the wheel. I still hope that I've just missed something in the documentation or there is a guru who knows "the way". I will also add this reference to the original question and explain why this is not what I am looking for. – Kiryl Volkau Apr 22 '22 at 21:48
  • 1
    Since you say you are arbitrarily limited to use a function named `SetPixel` or one setting a pixel one by one, this effectively seems to be a question about how to convert from an `SkBitmap` or `System.Drawing.Image` to an Avalonia image, as the latter doesn't provide such method. At the same time, you state you already found solutions for this, and seemingly have trouble using them - I recommend focusing on that by pointing out the code you found and have problems with, as the question is otherwise too unclear and impossible to answer. – Ray Apr 22 '22 at 21:53
  • @Ray I see your point in how the question is unclear - I think I have found the main answer: it doesn't seem possible to set pixels on Avalonia bitmaps, and the only solution is to actually convert between other bitmap types. Although I really don't like it. But! It does seem like a great opportunity to contribute to the open-source project. Thanks to everyone a lot (especially the moderator who cleared some of the controversial comments ), closing the question. – Kiryl Volkau Apr 22 '22 at 22:05
  • 1
    @KirylVolkau No problem. I think `writeableBitmap` would be a good direction to explore. – Lee Taylor Apr 22 '22 at 22:13

2 Answers2

0

UPDATED: you can swap bitmap on the image control: https://docs.avaloniaui.net/docs/controls/image

The original question (although poorly stated, my bad) was intented to clarify if there is a way to perform the SetPixel operation on the Avalonia bitmap. Unfortunately, currently, it doesn't seem like an available option: so the only way is to either create a custom drawing context OR control OR conversion between different Bitmap types (like System.Drawing.Bitmap or SkBitmap from SkiaSharp) to Avalonia.WriteableBitmap. All those solutions are referenced in the original question.

0

You can create an SKBitmap and draw on it however you want, then convert to an Avalonia Bitmap with the following.

public Avalonia.Media.Imaging.Bitmap SKBitmapToAvaloniaBitmap(SKBitmap skBitmap)
{
    SKData data = skBitmap.Encode(SKEncodedImageFormat.Png, 100);
    using (Stream stream = data.AsStream())
    {
        return new Avalonia.Media.Imaging.Bitmap(stream);
    }
}

The resulting bitmap can be displayed in an Image xaml component using binding. Note that I have used the PNG encoding format instead of BMP. I found that using SKEncodedImageFormat.Bmp resulted in null data returned. Something to do with the underlying native BMP codec not available on Windows.