我正在使用GDI +绘制文本。我最近注意到,当DPI更改时,此文本会自动缩放。有没有办法使GDI +文本绘图独立于DPI?例如。无论DPI如何,我想绘制最多20像素的文本。可能吗?怎么做?
以下是示例代码。我想绘制具有常量大小的第一个文本,无论DPI如何,第二个文本通常是:
case WM_PAINT:
{
inherited::WndProc(message);
Canvas->Brush->Style = bsSolid;
Canvas->Brush->Color = clWhite;
Canvas->FillRect(ClientRect);
// get GDI+ graphics from canvas
Gdiplus::Graphics graphics(Canvas->Handle);
// set text rendering hint
graphics.SetTextRenderingHint(Gdiplus::TextRenderingHintSystemDefault);
std::auto_ptr<Gdiplus::Font> pFont(new Gdiplus::Font(Canvas->Handle, Font->Handle));
std::auto_ptr<Gdiplus::SolidBrush> pBrush(new Gdiplus::SolidBrush(Gdiplus::Color(255, 0, 0, 0)));
std::auto_ptr<Gdiplus::StringFormat> pFormat(new Gdiplus::StringFormat());
Gdiplus::FontFamily fontFamily;
pFont->GetFamily(&fontFamily);
std::auto_ptr<Gdiplus::Font> pFont2(new Gdiplus::Font(&fontFamily, pFont->GetSize(),
pFont->GetStyle(), Gdiplus::UnitPixel));
Gdiplus::Unit test = pFont->GetUnit();
Gdiplus::Unit test2 = pFont2->GetUnit();
pFormat->SetAlignment(Gdiplus::StringAlignmentNear);
pFormat->SetLineAlignment(Gdiplus::StringAlignmentNear);
Gdiplus::StringFormatFlags flags = Gdiplus::StringFormatFlagsBypassGDI;
//flags = (Gdiplus::StringFormatFlags)(flags | Gdiplus::StringFormatFlagsDirectionRightToLeft);
//flags = (Gdiplus::StringFormatFlags)(flags | Gdiplus::StringFormatFlagsDirectionVertical);
//flags = (Gdiplus::StringFormatFlags)(flags | Gdiplus::StringFormatFlagsNoWrap);
//flags = (Gdiplus::StringFormatFlags)(flags | Gdiplus::StringFormatFlagsNoClip);
pFormat->SetFormatFlags(flags);
pFormat->SetTrimming(Gdiplus::StringTrimmingEllipsisCharacter);
pFormat->SetHotkeyPrefix(Gdiplus::HotkeyPrefixNone);
std::wstring text = L"This is a sample code";
Gdiplus::Unit prevPageUnit = graphics.GetPageUnit();
try
{
graphics.SetPageUnit(Gdiplus::UnitPixel);
// draw text
graphics.DrawString(text.c_str(), text.length(), pFont2.get(), Gdiplus::RectF(ClientRect.Left,
ClientRect.Top, ClientWidth, ClientHeight), pFormat.get(), pBrush.get());
}
__finally
{
graphics.SetPageUnit(prevPageUnit);
}
// draw text 2
graphics.DrawString(text.c_str(), text.length(), pFont.get(), Gdiplus::RectF(ClientRect.Left,
ClientRect.Top + 25, ClientWidth, ClientHeight), pFormat.get(), pBrush.get());
return;
}
此致
答案 0 :(得分:5)
我想提一些与您的问题略有不同的内容。你不应该再在GDI +中使用Graphics.DrawString
了。它在.NET 2中被弃用。相反,Microsoft创建了TextRenderer.DrawString
。
在.NET中有两种绘制文本的方法:
graphics.MeasureString
和graphics.DrawString
)TextRenderer.MeasureText
和TextRenderer.DrawText
)在.NET 1.1中,所有内容都使用 GDI + 进行文本呈现。 But there were some problems:
- 由于GDI +的某种无状态特性会导致一些性能问题,其中设置上下文然后在每次调用后恢复原始内容。
- 国际文本的整形引擎已针对Windows / Uniscribe和Avalon(Windows Presentation Foundation)多次更新,但尚未针对GDI +进行更新,这导致对新语言的国际渲染支持不具有相同级别质量。
所以他们知道他们想要改变.NET框架以停止使用 GDI + 的文本渲染系统,并使用 GDI 。起初他们希望他们可以简单地改变:
graphics.DrawString
调用旧的DrawText
API而不是GDI +。但它们无法使文本包装和间距与GDI +完全匹配。所以他们被迫保留graphics.DrawString
来调用GDI +(兼容性原因;正在调用graphics.DrawString
的人会突然发现他们的文本没有像过去那样包装)。
创建了一个新的静态TextRenderer
类来包装GDI文本呈现。它有两种方法:
TextRenderer.MeasureText
TextRenderer.DrawText
注意:强>
的包装器
-TextRenderer
是GDI的包装纸 -graphics.DrawString
仍然是GDI +
然后出现了如何处理所有现有.NET控件的问题,例如:
Label
Button
TextBox
他们希望将它们切换为使用TextRenderer
(即GDI),但他们必须小心。可能有人依赖于他们的控件绘制,就像在.NET 1.1中那样。因此诞生了“兼容的文本呈现”。
默认情况下,应用程序中的控件的行为与它们在.NET 1.1中的行为相同(它们是“兼容”)。
您关闭兼容模式,请致电:
Application.SetCompatibleTextRenderingDefault(false);
这使您的应用程序更好,更快,具有更好的国际支持。总结一下:
SetCompatibleTextRenderingDefault(true) SetCompatibleTextRenderingDefault(false)
======================================= ========================================
default opt-in
bad good
the one we don't want to use the one we want to use
uses GDI+ for text rendering uses GDI for text rendering
graphics.MeasureString TextRenderer.MeasureText
graphics.DrawString TextRenderer.DrawText
Behaves same as 1.1 Behaves *similar* to 1.1
Looks better
Localizes better
Faster
注意GDI + TextRenderingHint
与用于GDI字体绘制的相应LOGFONT
Quality之间的映射也很有用:
TextRenderingHint mapped by TextRenderer to LOGFONT quality
======================== =========================================================
ClearTypeGridFit CLEARTYPE_QUALITY (5) (Windows XP: CLEARTYPE_NATURAL (6))
AntiAliasGridFit ANTIALIASED_QUALITY (4)
AntiAlias ANTIALIASED_QUALITY (4)
SingleBitPerPixelGridFit PROOF_QUALITY (2)
SingleBitPerPixel DRAFT_QUALITY (1)
else (e.g.SystemDefault) DEFAULT_QUALITY (0)
以下是GDI +(graphics.DrawString)与GDI(TextRenderer.DrawText)文本呈现的比较:
GDI + :TextRenderingHintClearTypeGridFit
, GDI :CLEARTYPE_QUALITY
:
GDI + :TextRenderingHintAntiAlias
, GDI :ANTIALIASED_QUALITY
:
GDI + :TextRenderingHintAntiAliasGridFit
, GDI :不受支持,使用ANTIALIASED_QUALITY :
GDI + :TextRenderingHintSingleBitPerPixelGridFit
, GDI :PROOF_QUALITY
:
GDI + :TextRenderingHintSingleBitPerPixel
, GDI :DRAFT_QUALITY
:
我觉得奇怪DRAFT_QUALITY
与PROOF_QUALITY
相同,与CLEARTYPE_QUALITY
相同。
另见
答案 1 :(得分:1)
这对我有用。
using namespace Gdiplus;
HDC hDC = ::GetDC( NULL );
int nDPI = ::GetDeviceCaps( hDC, LOGPIXELSY );
::ReleaseDC( NULL, hDC );
REAL fFontHeight = 96 / (REAL)nDPI * 8;
FontFamily fontFamily( L"Arial" );
Gdiplus::Font font( &fontFamily, fFontHeight, UnitPixel );
REAL fMeasuredFontHeight = font.GetHeight( &gr );
事实证明,Gdiplus :: Font虽然以像素为单位指定,但却使用用户的DPI设置来调整生成的字体(即使字体用于在位图中绘制!)。 96的标准DPI是一个很好的值,可以确定正确的比例来调整字体大小。
在上面的代码片段中,所寻求的字体高度为8像素高。
通过所有DPI设置,fMeasuredFontHeight几乎保持不变(大约12)。