0

I take a photo, load it into a bitmap/texture2D, mark something on it using SetPixel and assign the bitmap/texture2D to an image control.

So much for the theory.

Is it possible to achieve this with MAUI/Net house tools or do you need additional frameworks?

I tried SkiaSharp, but I am not satisfied with the performance.

What can you recommend?

Thank you very much.

Tested SkiaSharp and it was awful.

ToolmakerSteve
  • 18,547
  • 14
  • 94
  • 196
  • Perhaps you should post the code you tried and maybe we could help you address the performance problem? – Jason Mar 07 '23 at 18:57
  • // Get string picPath from TakePhoto(); SKBitmap bitmap = SKBitmap.Decode(picPath); // -> Here Drawing Fun with bitmap.SetPixel() // ... // Set Bitmap as ImageSource of Image Control: MemoryStream ms = new MemoryStream(); bitmap.Encode(ms, SKEncodedImageFormat.Jpeg, 95); ms.Position = 0; image.Source = ImageSource.FromStream(() => ms); – ChiefGardener Mar 07 '23 at 20:02
  • 1
    please [edit] your question, don't just stuff code in the comments. And are you saying that the code as posted has a performance issue? – Jason Mar 07 '23 at 20:05
  • You don't specify what performance testing you have done. Have you verified that it is `SetPixel` that takes too much time? If not, then you have incorrectly stated that the problem is Skiasharp. – ToolmakerSteve Mar 07 '23 at 22:38
  • Yes, I think it has problems. Because when I use code without SkiaSharp, everything runs much smoother. Test: assign the photo directly to the image control, so dImage.Source = picPath. I need the SetPixel() only for drawing a not filled Rect around some area, ca. 100x100 Pixel. Please show me how I can shorten the assignment of the ImageSource to the image control. Is there no way without the stream? Or where does the delay come from? It is there, I notice it. – ChiefGardener Mar 08 '23 at 15:56
  • `I need the SetPixel() only for drawing a not filled Rect around some area` What have you tried?And could you please post the code you have tried? – Jessie Zhang -MSFT Mar 09 '23 at 05:32
  • // Max. 200 Pixelx x max .20 Pixel: for (int x = x1; x <= x2; x++) { for (int i = 0; i < thickness; i++) { texture.SetPixel(x, y1 + i, color); texture.SetPixel(x, y2 - i, color); } } for (int y = y1; y <= y2; y++) { for (int i = 0; i < thickness; i++) { texture.SetPixel(x1 + i, y, color); texture.SetPixel(x2 - i, y, color); } } – ChiefGardener Mar 09 '23 at 10:03
  • As I said, I only set at max 200 Pixel x2. Even my C64 could handle this in no time... – ChiefGardener Mar 09 '23 at 10:04

1 Answers1

1

At this time, there is nothing in Maui itself that would be relevant to your goal.

First option is to use SkiaSharp in a way that gives higher performance manipulation of individual pixels.

Second option is to use a c# byte array.


Regardless of the approach you use, its important to measure how slow it is to move to/from the array, vs how slow individual pixel writing is.

I'll assume that you have tested writing HUNDREDS of pixels (with a single decode/encode), and compared how long that took to writing NO pixels (just decoding the image, then returning it to a format you can display.)

For example, encoding to jpeg takes a significant amount of time. Be sure to measure time, to find out whether SetPixel is the problem, or something else in the process.

ALSO, be aware that any of these solutions will likely be quite slow, if a debugger is attached. Consider "Debug menu / Run without debugger", to get a better feel for how long it will take in the final app.

Likewise, test on an actual device, not an emulator. Unless you have a very fast pc running the emulator.


Approach 1: SkColor pixel array

// --- NOT TESTED ---

// Given "SKBitmap bitmap", extract pixels.
SkiaSharp.SKColor[] pixels = bitmap.Pixels;

// manipulate individual pixels.
SKColor color = MyGetPixel(pixels, 12, 34, bitmap);
var newcolor = new SKColor(255,128, 0); 
MySetPixel(newcolor, pixels, 12, 34, bitmap);
...

// write pixels back to bitmap.
bitmap.Pixels = pixels;

// --- helper methods. ---
SKColor MyGetPixel(SKColor[] pixels, int x, int y, SKBitmap bitmap)
{
    return pixels[y * bitmap.Width + x];
}
void MySetPixel(SKColor color, SKColor[] pixels, int x, int y, SKBitmap bitmap)
{
    pixels[y * bitmap.Width + x] = color;
}

Approach 2: byte array

For high performance, copy bitmap data to a byte[] variable.

Look for some c# library or explanation of manipulating image data when its in a byte array. Recommending what to use is beyond scope of StackOverflow; you'll have to research.

There are some earlier SO questions such as Faster alternatives to SetPixel and GetPixel ....

Maui runs on .Net; any c# solution should be relevant.

ToolmakerSteve
  • 18,547
  • 14
  • 94
  • 196
  • Thank you for your help, I will use your Ideas. But: I dont encode and decode every pixel, please look at my Code above. Thank you. – ChiefGardener Mar 09 '23 at 10:05
  • As Jason mentioned, please add that code to your question. Its hard to read inside a comment. I figured you probably were not decoding on every setpixel; mentioned just in case, as it would cause a slowdown. Regardless, the most important thing for you to do is to find out exactly what call causes most of the slowdown. If it isn’t setpixel, then you are wasting your time trying to replace that with something else. – ToolmakerSteve Mar 09 '23 at 20:08