Is there a way to draw pixel arrays dynamically on Image control in MAUI?

YVKOMAR 11 Reputation points
2022-05-31T10:33:24.757+00:00

Hi! For every frame, I have a 4-bytes BGRA pixel array to update my Image control. However, I can't find a way to update it in MAUI frequently. Tens times per second.
In WinUI3 I use an Image control with WriteableBitmap as a source. I update WriteableBitmap.PixelBuffer as a stream for every frame and it works fine. WinUI3 pseudo-code is:

private Image Image;  
private WriteableBitmap bitmap = new WriteableBitmap(width, height);  
...  
Image.Source = bitmap;  
...  
var stream = bitmap.PixelBuffer.AsStream();  
byte[] pixelsBytes = (byte[])parameters.Pixels; // every 4 bytes is a BGRA pixel  
stream.Seek(0, SeekOrigin.Begin);  
stream.Write(pixelsBytes, 0, pixelsBytes.Length);  
bitmap.Invalidate();  

In MAUI I tried this approach:
Xaml:

<Image x:Name="MyImage" HeightRequest="200"/>  

Code:

private MemoryStream stream;  
...  
stream = new MemoryStream(new byte[width * height * 4]);  
...  
private void OnPaint(byte[] pixelsBytes)  
{  
    stream.Seek(0, SeekOrigin.Begin);  
    stream.Write(pixelsBytes, 0, pixelsBytes.Length);  
    ImageSource source = ImageSource.FromStream(() => stream);  
    Image.Source = source;  
}  

with no luck. ImageSource wants a stream from a graphics file, not a stream of a pixels byte array.
I also saw how to use GraphicsView with Canvas, however, it looks uncompleted. Microsoft.Maui.Graphics.Platform namespace is inaccessible on Windows and there are no examples for Windows.
Even if I could use:

var image = PlatformImage.FromStream(stream);  
canvas.DrawImage(image, 10, 10, image.Width, image.Height);  

MAUI awaits that stream is a stream of a graphics file from resources or disk, not a pixels array with channels of color. I think MAUI WebView does something similar to show web pages. Is there a way to draw pixel arrays dynamically on Image control or are there some other surfaces to do it? Could someone direct me, please?

.NET MAUI
.NET MAUI
A Microsoft open-source framework for building native device applications spanning mobile, tablet, and desktop.
2,868 questions
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. Wenyan Zhang (Shanghai Wicresoft Co,.Ltd.) 26,316 Reputation points Microsoft Vendor
    2022-06-01T07:50:31.307+00:00

    Hello @YVKOMAR ,
    You said "ImageSource wants a stream from a graphics file, not a stream of a pixels byte array " and you can update WriteableBitmap.PixelBuffer as a stream in WinUI3.
    Currently, the Image control only supports images that use BGRA8 encoding and pre-multiplied or no alpha channel. Before attempting to display an image, test to make sure it has the correct format, and if not, use the SoftwareBitmap static Convert method to convert the image to the supported format.
    .NET MAUI is for Windows 11 and Windows 10 version 1809 or higher, using Windows UI Library (WinUI) 3. So we could set BitmapPixelFormat.Bgra8 as BitmapPixelFormat, and set pixel data on the frame, then invoke
    the Windows platform code
    , try to convert your pixels byte array to stream in Windows platform and use the stream in MAUI, refer to the following code:

    Define the cross-platform API in MAUI project

    namespace ImageMAUIDemo  
    {  
        public partial class ImageStreamService  
        {  
            public  partial Task<Stream> ConvertWriteableBitmapToRandomAccessStream(byte[] pixelsBytes, double width, double height);  
        }  
    }  
    

    Implement the API under Windows platform

    using Windows.Graphics.Imaging;  
    using Windows.Storage.Streams;  
      
    namespace ImageMAUIDemo  
    {  
        partial class ImageStreamService  
        {  
            public async partial Task<Stream> ConvertWriteableBitmapToRandomAccessStream(byte[] pixelsBytes, double width, double height)  
            {  
                var stream = new InMemoryRandomAccessStream();  
      
                BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, stream);  
      
                var wb = new WriteableBitmap((int)width, (int)height);  
                encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore, (uint)width, (uint)height, 96.0, 96.0, pixelsBytes);  
                await encoder.FlushAsync();  
      
                return stream.AsStream();  
            }  
        }  
    }  
    

    Invoke the cross-platform API in MainPage

    private async void  OnCounterClicked(object sender, EventArgs e)  
     {  
            ImageStreamService streamService = new ImageStreamService();  
     var imageStream = await streamService.ConvertWriteableBitmapToRandomAccessStream(new byte[200 * 200 * 4], 200, 200);// put your 4-bytes BGRA pixel array here, I add an empty byte[] for testing  
            ImageSource source = ImageSource.FromStream(() => imageStream);  
            MyImage.Source = source;  
        }  
    

    Best Regards,
    Wenyan Zhang


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
    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.

    1 person found this answer helpful.
    0 comments No comments