使用Direct2D在WPF的Image控件上绘图

  Direct2D中,最常用的渲染目标是从窗口句柄建立的HwndRenderTarget,但是有些时候,我们并不希望在整个窗口上绘图,而是在其中的一部分上。这个问题可以通过把创建RenderTarget时引入的窗口句柄设定为某一控件的句柄来解决,但是这有诸多弊端。首先,一些框架的控件没有独立的句柄,例如WPF。其次,在控件重绘时,如果绘图速度不够快可能造成闪烁。
  要解决第二个问题,通常的方法是双缓冲,而如果要在解决第二个问题的基础上,同时解决第一个问题,我想到的一个方法就是绘制的结果作为一个Source显示在Image控件上。Direct2D自然没有提供相关的支持,所以我们要自己搭建这个桥梁,造桥材料的其中一个选择是WriteableBitmap。

  buffer = new WriteableBitmap(size.Width, size.Height, 72, 72, System.Windows.Media.PixelFormats.Pbgra32, null);

  如图的代码可以创建一个新的WriteableBitmap对象。前两个参数是位图的大小,第三、四个参数分别是横纵的dpi,第五个参数是位图的像素格式,最后一个是调色盘,通常留空。
  WriteableBitmap类可以作为Image控件的Source,并且可以实时更新内容。然而Direct2D不能直接在它上面绘图,我们需要一个间接的过程,比如使用WIC图片。

_ImagFc = new ImagingFactory();
_bufferBack = new WICBitmap(_ImagFc,(int)size.Width(int)size.Height,SharpDX.WIC.PixelFormat.Format32bppBGR,BitmapCreateCacheOption.CacheOnLoad);

  创建WIC图片的过程不多赘述,但是要注意,WIC图片的各个参数必须与作为缓冲区的WriteableBitmap图片相同。
然后我们要做的就是创建一个WicRenderTarget,使Direct2D绘制的结果保存在其中。

DxFac = new D2DFactory();
View = new WicRenderTarget(DxFac, _bufferBack, 
	new RenderTargetProperties(
    	RenderTargetType.Default,
        new PixelFormat(Format.Unknown, AlphaMode.Unknown),
        0,
        0,
        RenderTargetUsage.None,
        FeatureLevel.Level_DEFAULT
    ));

  WicRenderTarget的第二个参数为创建的WIC对象,剩余参数一般填默认。
  在绘制完成后,我们需要把WIC缓冲区中的数据复制到WriteableBitmap中,然而并没有安全的手段来进行这一操作,我们就必须用一些“暴力”的方式。

buffer.Lock();
var m_lock = _bufferBack.Lock(BitmapLockFlags.Read);
RtlMoveMemory((void*)buffer.BackBuffer, (void*)m_lock.Data.DataPointer, buffer.PixelHeight * buffer.BackBufferStride);
m_lock.Dispose();
buffer.AddDirtyRect(new Int32Rect(0, 0, Width, Height));
buffer.Unlock();

  首先,调用WriteableBitmap的Lock方法,开始改写缓冲区。然后再调用WICBitmap的Lock方法,得到缓冲区的地址,并使用CopyMemory把WICBitmap的缓冲区数据复制到WriteableBitmap中,缓冲区的大小可以通过像素高度*每行的字节数来计算。在数据复制完成后要调用WriteableBitmap的AddDirtyRect或者WritePixels方法,来刷新前台的数据,把绘制的结果显示在屏幕上。
  总结:这种方法可以实现Direct2D在局部窗口中绘图,并且无需响应WM_PAINT事件,缺点则是对CPU负担较重,在高帧率时性能欠佳。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值