如何使用SharpDX将Direct2D BitmapRenderTarget的Bitmap绘制到WicRenderTarget?
解决SharpDX中BitmapRenderTarget内容转WicRenderTarget并保存为PNG的问题
你的代码出现静默崩溃主要有几个核心问题:
- 错误将渲染目标尺寸赋值给
DotsPerInch属性,DPI是每英寸点数(比如标准96),并非画布尺寸 - 直接绘制BitmapRenderTarget的Bitmap到WicRenderTarget存在资源兼容性问题,且未正确托管非托管资源
- 缺少完整的PNG编码保存逻辑
修复方案一:直接使用WicRenderTarget绘制并保存(更高效)
跳过BitmapRenderTarget的中间步骤,直接在WicRenderTarget上完成绘制并导出为PNG:
using SharpDX; using SharpDX.Direct2D1; using SharpDX.WIC; using System.IO; // 计算缩放后尺寸 int scaledWidth = (int)(_deviceContext.Size.Width * Zoom); int scaledHeight = (int)(_deviceContext.Size.Height * Zoom); Size2F standardDpi = new(96, 96); // 标准屏幕DPI // 初始化WIC组件 _imagingFactory = new ImagingFactory(); _wicBitmap = new Bitmap(_imagingFactory, scaledWidth, scaledHeight, PixelFormat.Format32bppPBGRA, BitmapCreateCacheOption.CacheOnLoad); // 创建WicRenderTarget using var wicRenderTarget = new WicRenderTarget(_deviceContext.Factory, _wicBitmap, new RenderTargetProperties(new PixelFormat(Format.Unknown, AlphaMode.Premultiplied)) { DotsPerInch = standardDpi, AntialiasMode = AntialiasMode.PerPrimitive }); // 执行绘制 wicRenderTarget.BeginDraw(); wicRenderTarget.Clear(new RawColor4(1, 1, 1, 1)); using var blackBrush = new SolidColorBrush(wicRenderTarget, new RawColor4(0, 0, 0, 1)); wicRenderTarget.DrawLine(new RawVector2(0, 0), new RawVector2(100, 100), blackBrush, 1); wicRenderTarget.EndDraw(); // 编码并保存为PNG using var outputStream = new FileStream("output.png", FileMode.Create); using var pngEncoder = new PngBitmapEncoder(_imagingFactory); pngEncoder.Initialize(outputStream); using var frameEncoder = new BitmapFrameEncode(pngEncoder); frameEncoder.Initialize(); frameEncoder.SetSize(scaledWidth, scaledHeight); PixelFormat targetFormat = PixelFormat.Format32bppPBGRA; frameEncoder.SetPixelFormat(ref targetFormat); frameEncoder.WriteSource(_wicBitmap); frameEncoder.Commit(); pngEncoder.Commit(); // 转换为Direct2D Bitmap供后续使用 Bitmap = Bitmap.FromWicBitmap(_deviceContext, _wicBitmap);
修复方案二:保留BitmapRenderTarget,直接导出内容到WIC
如果必须先使用BitmapRenderTarget绘制,可直接将其内容转换为WIC Bitmap,跳过中间绘制步骤:
using SharpDX; using SharpDX.Direct2D1; using SharpDX.WIC; using System.IO; Size2F scaledSize = new((float)(_deviceContext.Size.Width * Zoom), (float)(_deviceContext.Size.Height * Zoom)); Size2F standardDpi = new(96, 96); // 创建BitmapRenderTarget并绘制 using var bitmapRenderTarget = new BitmapRenderTarget(_deviceContext, CompatibleRenderTargetOptions.None, scaledSize) { DotsPerInch = standardDpi, AntialiasMode = AntialiasMode.PerPrimitive }; bitmapRenderTarget.BeginDraw(); bitmapRenderTarget.Clear(new RawColor4(1, 1, 1, 1)); using var blackBrush = new SolidColorBrush(bitmapRenderTarget, new RawColor4(0, 0, 0, 1)); bitmapRenderTarget.DrawLine(new RawVector2(0, 0), new RawVector2(100, 100), blackBrush, 1); bitmapRenderTarget.EndDraw(); // 直接从BitmapRenderTarget的Bitmap创建WIC Bitmap _imagingFactory = new ImagingFactory(); _wicBitmap = new Bitmap(_imagingFactory, bitmapRenderTarget.Bitmap, BitmapCreateCacheOption.CacheOnLoad); // 保存为PNG(同方案一的编码逻辑) using var outputStream = new FileStream("output.png", FileMode.Create); using var pngEncoder = new PngBitmapEncoder(_imagingFactory); pngEncoder.Initialize(outputStream); using var frameEncoder = new BitmapFrameEncode(pngEncoder); frameEncoder.Initialize(); frameEncoder.SetSize((int)scaledSize.Width, (int)scaledSize.Height); PixelFormat targetFormat = PixelFormat.Format32bppPBGRA; frameEncoder.SetPixelFormat(ref targetFormat); frameEncoder.WriteSource(_wicBitmap); frameEncoder.Commit(); pngEncoder.Commit(); Bitmap = Bitmap.FromWicBitmap(_deviceContext, _wicBitmap);
关键修复说明
- 修正DPI设置:
DotsPerInch必须设置为每英寸点数(如96),而非画布尺寸,否则会导致渲染上下文参数异常 - 托管非托管资源:使用
using语句自动释放SharpDX的非托管对象(如Brush、RenderTarget),避免内存泄漏和静默崩溃 - 简化转换流程:方案二直接通过BitmapRenderTarget的Bitmap创建WIC Bitmap,规避跨RenderTarget绘制的兼容性问题
- 补充PNG编码:原代码缺少完整的PNG保存逻辑,上述代码补充了从WIC Bitmap到PNG文件的完整编码流程
内容的提问来源于stack exchange,提问作者user25472896
相关产品推荐
相关产品推荐

