GDI+ - 为啥 MeasureString 函数使用 Courier 字体失败?

Posted

技术标签:

【中文标题】GDI+ - 为啥 MeasureString 函数使用 Courier 字体失败?【英文标题】:GDI+ - Why the MeasureString function fails with a Courier font?GDI+ - 为什么 MeasureString 函数使用 Courier 字体失败? 【发布时间】:2018-02-11 10:26:03 【问题描述】:

我正在使用 RAD Studio XE7。在几个项目中,我使用通用代码获取文本周围的边界框(以像素为单位),使用 GDI+ MeasureString 函数:

// configure the font to use. NOTE be careful, the SVG font size matches with the
// GDI font HEIGHT property, and not with the font SIZE
std::auto_ptr<TFont> pTextFont(new TFont());
pTextFont->Name   =  fontFamily;
pTextFont->Height = -fontSize;
std::auto_ptr<Gdiplus::Font> pFont(new Gdiplus::Font(pCanvas->Handle, pTextFont->Handle));

// char range is required to extract the first char bounds
Gdiplus::CharacterRange charRange;
charRange.First  = 0;
charRange.Length = 1;

// configure the text format
std::auto_ptr<Gdiplus::StringFormat> pTextFormat(new Gdiplus::StringFormat());
pTextFormat->SetAlignment(Gdiplus::StringAlignmentNear);
pTextFormat->SetLineAlignment(Gdiplus::StringAlignmentNear);
pTextFormat->SetFormatFlags(Gdiplus::StringFormatFlagsNoWrap);
pTextFormat->SetTrimming(Gdiplus::StringTrimmingNone);
pTextFormat->SetMeasurableCharacterRanges(1, &charRange);

Gdiplus::RectF boundingBox;
Gdiplus::RectF viewBoxF(viewBox);

// measure the rect surrounding the text
if (pGraphics->MeasureString(text.c_str(), text.length(), pFont.get(), viewBoxF,
        pTextFormat.get(), &boundingBox) != Gdiplus::Ok)

    // error is handled here

此函数在某些情况下运行良好,但有时 MeasureString 会莫名其妙地失败,返回 InvalidParameter 作为错误消息,而例如字体参数如下:

pTextFont->Name   =  L"Courier";
pTextFont->Height = -16;

我首先认为这可能是字体后备问题。我尝试实现以下解决方案来获取后备字体:How to automatically choose most suitable font for different language?

但是,这并没有解决我的问题:

    在上述情况下,返回的备用字体也是 Courier,这意味着我的系统以某种方式认为此字体是有效的(除非字体备用代码本身已损坏,但我认为并非如此)李> 对于另一个用 Delphi 编写的项目,我翻译了上面的代码,我遇到了完全相同的问题 GDI(不是 GDI+)似乎可以通过 SelectObject 和 DrawText 等函数使用此字体(使用 DrawText 和 DT_CALCRECT 测量时,返回的 rect 似乎有效) 另一方面,GDI+ 似乎无法对字体(在 pFont 中实例化的字体)进行处理。绘图功能也失败了

有人可以向我解释我做错了什么吗?

【问题讨论】:

不应该是“新快递”吗? 不,我没有混淆 Courier 和 Courier New。我从几个来源收到这个名称,afaik Courier 也是一个有效的字体名称(请参阅en.wikipedia.org/wiki/Courier_(typeface))但是 Courier 可能是包括 Courier New 在内的一类字体的通用名称,但我真的不知道.但是在这种情况下,GDI+ 引擎应该能够处理,还是不能?因为 GDI 确实... Courier New 是 Truetype 字体,但 Courier 不是。 但除非我错了,否则 GDI+ 应该也支持非 truetype 字体,对吧? 只是为了好奇:pTextFont->Height 不应该总是一个正值吗? GDI 应该如何计算负大小?至少在 C' 中,如果我尝试使用 negitve 字体大小绘制,我会收到异常。我怀疑 C 和 MeasureString 是一样的 【参考方案1】:

与我的想法相反,GDI+ 确实不支持所有已安装的字体,正如 DrawString 函数备注 (https://msdn.microsoft.com/en-us/library/windows/desktop/ms535991(v=vs.85).aspx) 中所说:

请注意,GDI+ 不支持 PostScript 字体或 OpenType 字体 没有 TrueType 轮廓。

Courier 字体似乎属于不能在 GDI+ 中“按原样”使用的那种字体。因此,如果使用 GDI+ 绘制失败,我需要改用 GDI,或者提供替代字体。

【讨论】:

以上是关于GDI+ - 为啥 MeasureString 函数使用 Courier 字体失败?的主要内容,如果未能解决你的问题,请参考以下文章

C# winform如何计算控件上文字的实际宽度(像素)

为啥用 gdi 有锯齿图形?

为啥使用“RenderTargetBitmap”类会使 GDI 句柄数增加?

为啥控件的类名不好?不能创建新的 GDI 句柄?

为啥 DirectX/DirectWrite/Direct2D 文本渲染不能像 GDI 一样清晰?

MeasureString 始终认为空格适合