Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting a DrawingContext for a wpf WriteableBitmap

Is there a way to get a DrawingContext (or something similar) for a WriteableBitmap? I.e. something to allow you to call simple DrawLine/DrawRectangle/etc kinds of methods, rather than manipulate the raw pixels directly.

like image 436
Emperor XLII Avatar asked Sep 17 '08 22:09

Emperor XLII


4 Answers

I found sixlettervariables' solution the most workable one. However, there's a "drawingContext.Close()" missing. According to MSDN, "A DrawingContext must be closed before its content can be rendered". The result is the following utility function:

public static BitmapSource CreateBitmap(
    int width, int height, double dpi, Action<DrawingContext> render)
{
    DrawingVisual drawingVisual = new DrawingVisual();
    using (DrawingContext drawingContext = drawingVisual.RenderOpen())
    {
        render(drawingContext);
    }
    RenderTargetBitmap bitmap = new RenderTargetBitmap(
        width, height, dpi, dpi, PixelFormats.Default);
    bitmap.Render(drawingVisual);

    return bitmap;
}

This can then easily be used like this:

BitmapSource image = ImageTools.CreateBitmap(
    320, 240, 96,
    drawingContext =>
    {
        drawingContext.DrawRectangle(
            Brushes.Green, null, new Rect(50, 50, 200, 100));
        drawingContext.DrawLine(
            new Pen(Brushes.White, 2), new Point(0, 0), new Point(320, 240));
    });
like image 122
Daniel Wolf Avatar answered Oct 21 '22 09:10

Daniel Wolf


If you don't mind using System.Drawing you could do something like:

var wb = new WriteableBitmap( width, height, dpi, dpi, 
                              PixelFormats.Pbgra32, null );
wb.Lock();
var bmp = new System.Drawing.Bitmap( wb.PixelWidth, wb.PixelHeight,
                                     wb.BackBufferStride, 
                                     PixelFormat.Format32bppPArgb, 
                                     wb.BackBuffer );

Graphics g = System.Drawing.Graphics.FromImage( bmp ); // Good old Graphics

g.DrawLine( ... ); // etc...

// ...and finally:
g.Dispose(); 
bmp.Dispose();
wb.AddDirtyRect( ... );
wb.Unlock();                    
like image 25
Danko Durbić Avatar answered Oct 21 '22 10:10

Danko Durbić


I'm wondering the same thing, as currently I do something like:

DrawingVisual drawingVisual = new DrawingVisual();
using (DrawingContext drawingContext = drawingVisual.RenderOpen())
{
   //
   // ... draw on the drawingContext
   //
   RenderTargetBitmap bmp = new RenderTargetBitmap(width, height, dpi, dpi, PixelFormats.Default);
   bmp.Render(drawingVisual);
   image.Source = bmp;
}

I'm trying to use the WriteableBitmap to allow multithreaded access to the pixel buffer, which is currently not allowed with neither a DrawingContext nor a RenderTargetBitmap. Maybe some sort of WritePixels routine based off of what you've retrieved from the RenderTargetBitmap would work?

like image 24
user7116 Avatar answered Oct 21 '22 10:10

user7116


It appears the word is no.


For future reference, we plan to use a port of the Writeable Bitmap Extensions for WPF.

For a solution using purely existing code, any of the other suggestions mentioned below will work.

like image 4
3 revs Avatar answered Oct 21 '22 09:10

3 revs