我使用 WriteableBitmap 作为在 WPF 窗口中渲染和显示内容的快速方法,然后导出为媒体(重用相同的渲染管道)。
我可以绘制图像、基本形状,执行操作图像字节的常见操作(调整大小、裁剪、翻转、更改角度、不透明度等)。与此问题无关。
我的渲染管道只是获取 WriteableBitmap 后台缓冲区 (nint/IntPtr) 及其一些参数(大小、比例、偏移量等),并使用 SharpDX 来绘制文本,如下所示:
public override void RenderAt(nint canvas, int canvasStride, int canvasWidth, int canvasHeight,
double horizontalScale, double verticalScale, int leftOffset, int topOffset,
int rightOffset, int bottomOffset)
{
using (var factory = new SharpDX.Direct2D1.Factory(FactoryType.MultiThreaded))
using (var writeFactory = new SharpDX.DirectWrite.Factory(SharpDX.DirectWrite.FactoryType.Shared))
using (var textFormat = new TextFormat(writeFactory, "Segoe UI", 20))
using (var bitmap = new SharpDX.WIC.Bitmap(new ImagingFactory(), canvasWidth, canvasHeight, SharpDX.WIC.PixelFormat.Format32bppPBGRA, SharpDX.WIC.BitmapCreateCacheOption.CacheOnLoad))
using (var renderTarget = new WicRenderTarget(factory, bitmap, new RenderTargetProperties()))
{
//Create a SharpDX Bitmap as the backbuffer.
var backBufferBitmap = new SharpDX.Direct2D1.Bitmap(renderTarget, new Size2(canvasWidth, canvasHeight), new SharpDX.Direct2D1.BitmapProperties(renderTarget.PixelFormat));
backBufferBitmap.CopyFromMemory(canvas, canvasStride);
//Render the text and other content to the backbuffer.
renderTarget.BeginDraw();
renderTarget.Transform = Matrix3x2.Scaling((float)horizontalScale, (float)verticalScale) * Matrix3x2.Translation(leftOffset, topOffset);
renderTarget.DrawBitmap(backBufferBitmap, 1f, BitmapInterpolationMode.Linear);
var text = "Example";
//Backdrop.
using (var brush = new SharpDX.Direct2D1.SolidColorBrush(renderTarget, new RawColor4(0,0,0,1)))
renderTarget.FillRectangle(new RawRectangleF(0, 0, canvasWidth, canvasHeight / 4), brush);
//Text.
using (var brush = new SharpDX.Direct2D1.SolidColorBrush(renderTarget, new RawColor4(1,1,1,1)))
renderTarget.DrawText(text, textFormat, new RectangleF(0, 0, Width, Height), brush);
renderTarget.EndDraw();
bitmap.CopyPixels(new RawBox(0, 0, canvasWidth, canvasHeight), canvasStride, new DataPointer(canvas, canvasStride * canvasHeight));
}
}
我想知道是否可以直接绘制到后台缓冲区,而不必进行这么多复制操作,因为现在我已经做了两个副本。
WPF 的 WriteableBitmap 已经封装了 WIC Bitmap ,因此代码的性能可能会比您想象的得到改善,但遗憾的是它没有公开。
您可以使用如下代码来访问它:
var writeableBitmap = new WriteableBitmap(200, 200, 96, 96, PixelFormats.Bgr32, null); // create some writeable bitmap
// get its internal COM reference
var prop = writeableBitmap.GetType().GetProperty("WicSourceHandle", BindingFlags.NonPublic | BindingFlags.Instance);
var handle = (SafeHandleZeroOrMinusOneIsInvalid)prop.GetValue(writeableBitmap, null);
using (var bitmap = new SharpDX.WIC.Bitmap(handle.DangerousGetHandle())) // we're already walking on the dangerous edge anyway
{
etc...
// EndDraw does Lock+Unlock
}
注1:WPF现在已经相当冻结了,所以我认为使用这个内部结构不会有很大的风险,但这显然取决于你。
注 2:处理 WIC 位图就是在 CPU 上工作。如果您想要更好的性能,您可以使用驻留在 GPU 上并可以利用 GPU 能力的 Direct2D 位图。可能需要进行重要的更改。