Aris Theo
Aris Theo

Reputation: 55

Threading WriteableBitmap to Image control

I am using OpenGL to render a static picture in WPF, on a .NET Core 3.1 platform. The context is initially displayed in a hidden GLFW window. Then I am using glReadPixels to read the context and display it on an Image control on the UI, using the code shown below. The code works fine when not using threading. However, when calling the rendering code through a different thread the image is not displayed. As an intermediate check, I created the using (FileStream... code, which reads the WriteableBitmap and saves it locally and appears to be working correctly; this means that the WriteableBitmap is created correctly. So, I guess the problem is how to transmit a WriteableBitmap to the Image control, both of which were created on different threads. Dispatcher.BeginInvoke does not work for some strange reason.

    byte[] imageBuffer = new byte[imageWidth * imageHeight * 4];
    glReadPixels(0, 0, imageWidth, imageHeight, GL_BGRA, GL_UNSIGNED_BYTE, imageBuffer);
    imageBuffer = ImageReverse(imageBuffer, imageWidth);
    PixelFormat pixelFormat = PixelFormats.Pbgra32;
    int rawStride = (imageWidth * pixelFormat.BitsPerPixel) / 8;
    BitmapSource bitmapSource = BitmapSource.Create(imageWidth, imageHeight, 96, 96, pixelFormat, null, imageBuffer, rawStride);
    WriteableBitmap writeableBitmap = new WriteableBitmap(bitmapSource);

    //This is a check whether the writeableBitmap has been created correctly
    using (FileStream fileStream = new FileStream(@"C:\Temp\Image1.bmp", FileMode.Create))
    {
        BmpBitmapEncoder encoder = new BmpBitmapEncoder();
        encoder.Frames.Add(BitmapFrame.Create(writeableBitmap));
        encoder.Save(fileStream);
    }

    Action action = new Action(() => {
        _imgSoilProfile.Source = writeableBitmap; 
    });
    _imgSoilProfile.Dispatcher.BeginInvoke(action, DispatcherPriority.Send);

Upvotes: 1

Views: 228

Answers (1)

mm8
mm8

Reputation: 169200

Try to call w.Freeze() on the background thread before you set the Source of the Image:

using (FileStream fileStream = new FileStream(@"C:\Temp\Image1.bmp", FileMode.Create))
{
    ...
}
w.Freeze();

Action action = new Action(() => {
    _imgSoilProfile.Source = writeableBitmap; 
});

From the docs:

A frozen Freezable can also be shared across threads, while an unfrozen Freezable cannot.

Upvotes: 1

Related Questions