Getting a DrawingContext for a wpf WriteableBitmap
Solution 1
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.
Solution 2
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));
});
Solution 3
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();
Solution 4
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?
Solution 5
A different way to solve this problem is to use a RenderTargetBitmap
as a backing store, just like in the WriteableBitmap
example. Then you can create and issue WPF drawing commands to it whenever you want. For example:
// create the backing store in a constructor
var backingStore =
new RenderTargetBitmap(200,200,97,97,PixelFormats.Pbgra32);
myImage.Source = backingStore;
// whenever you want to update the bitmap, do:
var drawingVisual = new DrawingVisual();
var drawingContext = drawingVisual.RenderOpen();
{
// your drawing commands go here
drawingContext.DrawRectangle(
Brushes.Red, new Pen(),
new Rect(this.RenderSize));
}
Render(drawingContext);
drawingContext.Close();
backingStore.Render(drawingVisual);
If you want to redraw this RenderTargetBitmap
every frame, you can catch the CompositionTarget.Rendering
event, like this:
CompositionTarget.Rendering += MyRenderingHandler;
Related videos on Youtube
Emperor XLII
.net, c#, powershell; TMBG, TA; LE, RM; NS; JRR, LEM :)
Updated on July 09, 2022Comments
-
Emperor XLII almost 2 years
Is there a way to get a
DrawingContext
(or something similar) for aWriteableBitmap
? I.e. something to allow you to call simpleDrawLine
/DrawRectangle
/etc kinds of methods, rather than manipulate the raw pixels directly. -
Emperor XLII about 15 yearsI haven't had a chance to try it out just yet, but this seems like a very reasonable workaround in WPF. Thanks!
-
Eamon Nerbonne over 14 yearsThe
.Close()
is implicit in the.Dispose()
- which is the whole point behind theusing
statement. If you leave only therender(...)
command inside the using block, you'll be fine and don't need any.Close()
. -
Roman Starkov over 12 yearsThere's no
WriteableBitmap
in this answer, why is it the top one? :) It's completely unrelated to the question. -
Roman Starkov over 12 yearsThat's no official word. That's just some guy saying something on a forum.
-
Emperor XLII over 12 yearsPoint taken; updated text. I suppose you could say it meant "official" as in "posted to a forum monitored by officials, and not corrected by them", but that is a bit of a stretch :)
-
Verax over 12 yearsJust in case anyone is wondering, I tested the DrawingVisual WPF method mentioned in this topic and this System.Drawing method, and this System.Drawing method is MUCH FASTER. I'm very disappointed in WPF.
-
codekaizen almost 10 yearsMy guess is that it's upvoted because the original question may be akin to asking "How do I turn this screw with this hammer?" and the answer is "Use a screwdriver" instead of how to use the hammer to do it.
-
vac almost 9 yearsif you want to make WritableBitmap from it you can simply call:
WritaBleBitmap result = new WritableBitmap(image);
-
David Jeske almost 7 yearsYou can do the same thing with WPF, with similar (or better?) performance by using RenderTargetBitmap and DrawingVisual / DrawingContext
-
lindexi almost 7 yearsRender spend too long
-
lindexi almost 7 yearsYou cant write the bmp.Render in using that cant get the drawingVisual.
-
fadden about 4 yearsYou may need to
bmp.Freeze()
if you're sharing the bitmap between threads.