Search code examples
c#bitmapwinui-3winui

How to display gray scale 8 bit raw pixel data array (i.e. byte[]) to Image control in WinUI3


The raw pixel data array (byte[]) is retreived from camera and it is notified as an event to main page.
The pixel format is like that:-

  • GrayScale 8bit (i.e color band = 1)
  • width: 612, height: 512 -> total size = 612 * 512 = 313,344 bytes

Here is my code so far, which does not show anything in image control.

// Behind code of Main Page //////////////////////////////////////////////////////

// This event is called when camera image was captured from camera library
private void Camera_ImageCaptured(object? sender, ImageCapturedEventArgs e)
{
    // CameraImage is Image control of the main page
    _ = CameraImage.DispatcherQueue.TryEnqueue(async () =>
    {
        await GetBitmapAsync3(e.ImageBuffer, e.Width, e.Height);
    });
}

// This method is called in UI thread
public async Task GetBitmapAsync3(byte[] data, int width, int height)
{
    WriteableBitmap newImage = new WriteableBitmap(width, height);
    using var stream = newImage.PixelBuffer.AsStream();
    stream.Write(data);
    await stream.FlushAsync();
    stream.Close();
    ViewModel.WriteableBitmap = newImage;
}

// parameters from camera library
public class ImageCapturedEventArgs : EventArgs
{
    public ImageCapturedEventArgs( byte[] buffer, int width, int height );

    public int Height { get; set; }
    public int Width { get; set; }
    public byte[] ImageBuffer { get; set; }
}
// View Model ///////////////////////////////////////////////
public partial class MainViewModel : ObservableRecipient
{
    [ObservableProperty]
    public WriteableBitmap writeableBitmap;
    public int ImageWidth{ get; set; }
    public int ImageHeight { get; set; }
    public int ImageSize => ImageWidth * ImageHeight;

    public MainViewModel()
    {
        ImageWidth = 612;
        ImageHeight = 512;

        writeableBitmap = new WriteableBitmap(ImageWidth, ImageHeight);
    }
}

// XAML of main page /////////////////////////////////////////////////

<UserControl.DataContext>
    <viewmodels:MainViewModel />
</UserControl.DataContext>

<Grid x:Name="ContentArea">
    <Image
        x:Name="CameraImage"
        Grid.Row="0"
        Grid.Column="0"
        Width="612"
        Height="512"
        Source="{Binding WriteableBitmap}" />
</Grid>

I tried it with the above code, but it does not show anything in main page... Does anyone help me?


Solution

  • I'm not sure if Microsoft.UI.Xaml.Media.Imaging.WriteableBitmap supports 1 byte data for each pixel.

    Can you try the next?

    public async Task GetBitmapAsync3(byte[] data, int width, int height)
    {
        byte[] outputData= new byte[width * height * 4];
        int inputIndex = 0;
        int outputIndex = 0;
        for (int y = 0; y < height; y++)
        {
            for (int x = 0; x < width; x++)
            {
                byte value = data[inputIndex++];
                outputData[outputIndex++] = value;
                outputData[outputIndex++] = value;
                outputData[outputIndex++] = value;
                outputData[outputIndex++] = 255;
            }
        }
    
    
        WriteableBitmap newImage = new WriteableBitmap(width, height);
        using var stream = newImage.PixelBuffer.AsStream();
        await stream.WriteAsync(outputData);
        await stream.FlushAsync();
        stream.Close();
        ViewModel.WriteableBitmap = newImage;
    }