测量 TextRenderer 的文本范围

发布于 2025-01-10 15:04:55 字数 1148 浏览 0 评论 0原文

我有一个自定义控件,它使用 System.Drawing.Graphics.DrawString() 呈现文本,包括自动换行。渲染的一部分包括在文本的指定范围上绘制突出显示,例如背景颜色、下划线或其他装饰。

void HighlightRegion(Graphics g, string text, int startPos, int length, RectangleF region, Font font, StringFormat sf, Color c)
{
    var range = new CharacterRange[1];
    range[0].First = startPos;
    range[0].Length = length;
    sf.SetMeasureableCharacterRanges(range);
    var ranges = g.MeasureCharacterRanges(text, font, region, sf);
    using (ranges[0])
    using (var brush = new SolidBrush(c))
    {
         g.FillRegion(brush, ranges[0]);
    }
}

不幸的是,我发现 Graphics.DrawString 不能正确处理字体回退。我确保它可以处理 Unicode,并且使用表情符号进行测试表明它们呈现为小盒子。然而,我发现 System.Windows.Forms.TextRenderer.DrawText() 可以正确处理字体回退。因此,我一直在尝试更改文本渲染以使用 TextRenderer.DrawText()。但我无法弄清楚范围突出显示部分。

TextRenderer.MeasureText 可以很好地计算整个文本大小,但似乎没有任何方法可以仅测量其中的一部分。一系列字符可以从一行中间开始,绕到下一行,然后继续。尝试预测这些字符将落在哪里意味着准确地再现 TextRenderer 内部使用的自动换行逻辑。

我研究了 GDI GetCharacterPlacementW 的 P/Invoke(没有自动换行),研究了 Uniscribe(没有内置字体回退),我考虑过逐个字符地测量(混乱,而且我可能会得到边缘情况错误,我必须以某种方式匹配内置自动换行),但它们都有问题。有没有正确的方法来测量 TextRenderer.DrawText 范围?或者我应该完全接管渲染过程并逐个字符地布置文本?

I have a custom control which renders text, including word wrap, using System.Drawing.Graphics.DrawString(). Part of the rendering includes drawing highlight, such as a background color, or an underline, or other decoration on specified ranges of the text.

void HighlightRegion(Graphics g, string text, int startPos, int length, RectangleF region, Font font, StringFormat sf, Color c)
{
    var range = new CharacterRange[1];
    range[0].First = startPos;
    range[0].Length = length;
    sf.SetMeasureableCharacterRanges(range);
    var ranges = g.MeasureCharacterRanges(text, font, region, sf);
    using (ranges[0])
    using (var brush = new SolidBrush(c))
    {
         g.FillRegion(brush, ranges[0]);
    }
}

Unfortunately, I discovered that Graphics.DrawString doesn't handle font fallbacks properly. I was making sure it could handle Unicode, and testing with emojis showed that they render as little boxes. I found, however, that System.Windows.Forms.TextRenderer.DrawText() handles font fallback correctly. So I've been experimenting with changing the text rendering to use TextRenderer.DrawText(). But I can't figure out the range highlighting portion.

TextRenderer.MeasureText works fine for calculating the entire text size, but there doesn't seem to be any way to measure just a portion of it. A range of characters could start in the middle of a line, wrap around to the next line, and continue on. Trying to predict where those characters would fall would mean exactly reproducing the word wrap logic that TextRenderer uses internally.

I've looked into P/Invoke of GDI GetCharacterPlacementW (no word wrap), I've looked into Uniscribe (no built-in font fallback), I've considered measuring character by character (messy, and I'm likely to get edge cases wrong, and I have to somehow match the built in word wrap), but they all have issues. Is there a correct way to measure a TextRenderer.DrawText range? Or should I just take over the rendering process entirely and lay out the text character by character?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文