You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF C# .NET 6.0中Graphics绘文本致性能下降的解决方法

问题描述

在WPF C# .NET 6.0环境中,backbuffer(WritableBitmap)已包含OpenTK绘制的线条数据,单独渲染这些线条时流畅度正常,但通过System.Drawing.Graphics绘制大量文本后,整体流畅度明显下降。相关代码如下:

var bm2 = new System.Drawing.Bitmap((int)backbuffer.Width, (int)backbuffer.Height, backbuffer.BackBufferStride, System.Drawing.Imaging.PixelFormat.Format24bppRgb, backbuffer.BackBuffer);

backbuffer.Lock();
using (graphics = System.Drawing.Graphics.FromImage(bm2))
{
 graphics.CompositingQuality = CompositingQuality.HighQuality;
 graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
 graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;

 // 实际场景中会调用数千次DrawString,此处仅为示例
 graphics.DrawString("MyText test only up5", new Font("Tahoma", 14), System.Drawing.Brushes.White, 10, (float)(OtkCanvas.otkHeight - 60));
}

backbuffer.Unlock();

OtkCanvas.imageSource = backbuffer;

请问如何解决这种因Graphics绘制文本导致的性能下降问题?

优化方案

1. 复用Font和Brush对象

每次调用DrawString时创建新的Font和Brush会产生大量不必要的内存分配与GC开销,提前初始化并复用这些对象:

// 类级别成员,仅初始化一次
private readonly Font _tahomaFont = new Font("Tahoma", 14);
private readonly Brush _whiteBrush = System.Drawing.Brushes.White;

// 绘制时直接复用
graphics.DrawString("MyText test only up5", _tahomaFont, _whiteBrush, 10, (float)(OtkCanvas.otkHeight - 60));

2. 降低图形质量设置

当前启用的HighQuality级别的合成、插值和像素偏移模式会大幅增加CPU计算量。若文本显示质量可接受,改为性能优先的设置:

graphics.CompositingQuality = CompositingQuality.HighSpeed;
graphics.InterpolationMode = InterpolationMode.Low;
graphics.PixelOffsetMode = PixelOffsetMode.HighSpeed;

3. 修正WritableBitmap锁定时机

原代码中backbuffer.Lock()的时机错误,应在创建Bitmap前就锁定,且缩短锁定时长,仅在必要操作时保持锁定:

backbuffer.Lock();
try
{
    var bm2 = new System.Drawing.Bitmap((int)backbuffer.Width, (int)backbuffer.Height, backbuffer.BackBufferStride, 
        System.Drawing.Imaging.PixelFormat.Format24bppRgb, backbuffer.BackBuffer);
    using (var graphics = System.Drawing.Graphics.FromImage(bm2))
    {
        // 执行绘制操作
    }
}
finally
{
    backbuffer.Unlock();
}

4. 替换GDI+为WPF原生文本渲染

System.Drawing基于GDI+,与WPF的DirectX渲染管道不兼容,跨管道绘制会产生额外开销。推荐两种替代方案:

方案A:用FormattedText直接绘制到WritableBitmap

利用WPF原生的DrawingVisual和FormattedText完成文本渲染,避免GDI+交互:

backbuffer.Lock();
try
{
    var visual = new DrawingVisual();
    using (var drawingContext = visual.RenderOpen())
    {
        var formattedText = new FormattedText(
            "MyText test only up5",
            CultureInfo.CurrentCulture,
            FlowDirection.LeftToRight,
            new Typeface("Tahoma"),
            14,
            Brushes.White);
        drawingContext.DrawText(formattedText, new Point(10, OtkCanvas.otkHeight - 60));
    }
    // 将DrawingVisual内容渲染到WritableBitmap
    var renderTarget = new RenderTargetBitmap((int)backbuffer.Width, (int)backbuffer.Height, 96, 96, PixelFormats.Pbgra32);
    renderTarget.Render(visual);
    // 按需将renderTarget内容复制到backbuffer(需处理像素格式转换)
}
finally
{
    backbuffer.Unlock();
}

方案B:叠加WPF文本元素

直接在OpenTK画布的Image控件上方放置TextBlock或Label,让WPF原生负责文本渲染与布局,完全规避GDI+操作:

<Grid>
    <Image x:Name="OtkCanvasImage" Source="{Binding imageSource}"/>
    <TextBlock Text="MyText test only up5" FontFamily="Tahoma" FontSize="14" Foreground="White" 
               Margin="10,0,0,60" VerticalAlignment="Bottom"/>
</Grid>

5. 批量处理文本绘制

若需绘制数千条文本,尽量一次性批量处理:统一设置StringFormat的对齐、换行等参数,减少重复配置;或者合并相同样式的文本绘制逻辑,降低DrawString调用次数。

内容的提问来源于stack exchange,提问作者Shree John

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 17:40:46