关于位图:获取wpf WriteableBitmap的DrawingContext

关于位图:获取wpf WriteableBitmap的DrawingContext

Getting a DrawingContext for a wpf WriteableBitmap

有没有办法为WriteableBitmap获取DrawingContext(或类似的东西)? 即 可以让您调用简单的DrawLine / DrawRectangle / etc方法,而不是直接操作原始像素。


我发现sixlettervariables解决方案是最可行的解决方案。但是,缺少" drawingContext.Close()"。根据MSDN,"必须先关闭DrawingContext,然后才能呈现其内容"。
结果是以下实用程序功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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;
}

然后可以像这样轻松使用:

1
2
3
4
5
6
7
8
9
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));
    });

如果您不介意使用System.Drawing,则可以执行以下操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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();


我想知道同一件事,因为目前我正在做类似的事情:

1
2
3
4
5
6
7
8
9
10
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;
}

我正在尝试使用WriteableBitmap允许对像素缓冲区的多线程访问,而DrawingContext或RenderTargetBitmap当前均不允许这样做。基于您从RenderTargetBitmap检索的内容的某种WritePixels例程可能行得通吗?


看来这个词不是。

为了将来参考,我们计划使用WPF的Writeable Bitmap Extensions的端口。

对于使用纯现有代码的解决方案,下面提到的任何其他建议都可以使用。


解决此问题的另一种方法是使用RenderTargetBitmap作为后备存储,就像WriteableBitmap示例一样。然后,您可以随时创建WPF绘图命令并向其发出WPF绘图命令。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 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);

如果要每帧重绘该RenderTargetBitmap,则可以捕获CompositionTarget.Rendering事件,如下所示:

1
CompositionTarget.Rendering += MyRenderingHandler;


推荐阅读