Behnam Esmaili
Behnam Esmaili

Reputation: 5967

Update WritableBitmap after Image.Source has been set

I am trying to use WritableBitmap to do some pixel level manipulation of bitmap images.But i can't get it working.What i want to do is manipulating pixel data of WritableBitmap after i assign Image.Source property with my bitmap.I googled and the only thing i found is call to bitmap.Invalidate() method but it seems to be deprecated as i couldn't find that method in WritableBitmap class.following is the code i am using to get the image updated but no luck:

    wbitmap.Lock();
    wbitmap.WritePixels(rect, pixels, stride, 0);
    wbitmap.AddDirtyRect(new Int32Rect(0, 0, width, height));
    wbitmap.Unlock();

    //given that i've already assigned image.Source with "wbitmap"
    image.InvalidateVisual();

any thoughts on this?

EDIT

i would appreciate any suggestion for other way of FAST 2D drawing in WPF better that WritableBitmap.

Upvotes: 0

Views: 2374

Answers (1)

Clemens
Clemens

Reputation: 128061

The following simple example shows how to continuously write a WriteableBitmap while it is assigned to the Source property of an image control.

The XAML is just this:

<Window ...>
    <Grid>
        <Image x:Name="image"/>
    </Grid>
</Window>

In code behind there is a timer that overwrites the WriteableBitmap ten times per second with a random pixel color value. Note that you have to allow unsafe code in the Visual Studio Project Properties (in the Build tab).

Alternatively to Lock/AddDirtyRect/Unlock you could also call WritePixels. However, the Lock approach also allows that another, non-UI thread writes to the BackBuffer.

public partial class MainWindow : Window
{
    private readonly WriteableBitmap bitmap
        = new WriteableBitmap(100, 100, 96, 96, PixelFormats.Bgr32, null);

    public MainWindow()
    {
        InitializeComponent();
        image.Source = bitmap;

        var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(0.1) };
        timer.Tick += OnTimerTick;
        timer.Start();
    }

    private unsafe void OnTimerTick(object sender, EventArgs e)
    {
        int pixelValue = (int)DateTime.Now.Ticks & 0xFFFFFF;

        bitmap.Lock();
        var backBuffer = bitmap.BackBuffer;

        for (int y = 0; y < bitmap.PixelHeight; y++)
        {
            for (int x = 0; x < bitmap.PixelWidth; x++)
            {
                var bufPtr = backBuffer + bitmap.BackBufferStride * y + x * 4;
                *((int*)bufPtr) = pixelValue;
            }
        }

        bitmap.AddDirtyRect(new Int32Rect(0, 0, bitmap.PixelWidth, bitmap.PixelHeight));
        bitmap.Unlock();
    }
}

Upvotes: 2

Related Questions