use*_*994 3 text gdi+ dpi draw
我正在使用GDI +绘制文本.我最近注意到,当DPI更改时,此文本会自动缩放.有没有办法使GDI +文本绘图独立于DPI?例如,我想绘制最多20像素的文本,无论DPI如何.可能吗?这该怎么做?
下面是一个示例代码.我想绘制具有常量大小的第一个文本,无论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;
}
Run Code Online (Sandbox Code Playgroud)
问候
我想提一些与你的问题略有不同的东西.你不应该再使用Graphics.DrawStringGDI +了.它在.NET 2中被弃用.相反,Microsoft创建了TextRenderer.DrawString.
在.NET中有两种绘制文本的方法:
graphics.MeasureString和graphics.DrawString)TextRenderer.MeasureText和TextRenderer.DrawText)在.NET 1.1中,一切都使用GDI +进行文本渲染.但是有一些问题:
- 由于GDI +的某种无状态特性会导致一些性能问题,其中将设置设备上下文,然后在每次调用之后恢复原始设备上下文.
- 用于Windows/Uniscribe和Avalon(Windows Presentation Foundation)的国际文本的整形引擎已经多次更新,但尚未针对GDI +进行更新,这导致对新语言的国际渲染支持不具有相同的质量水平.
所以他们知道他们想要改变.NET框架以停止使用GDI +的文本渲染系统,并使用GDI.起初他们希望他们可以简单地改变:
graphics.DrawString
Run Code Online (Sandbox Code Playgroud)
调用旧DrawTextAPI而不是GDI +.但它们无法使文本包装和间距与GDI +完全匹配.所以他们不得不继续graphics.DrawString打电话给GDI +(兼容原因;那些打电话的人graphics.DrawString会突然发现他们的文字没有像过去那样包装).
TextRenderer创建了一个新的静态类来包装GDI文本呈现.它有两种方法:
TextRenderer.MeasureText
TextRenderer.DrawText
Run Code Online (Sandbox Code Playgroud)
注意:
-TextRenderer是GDI的包装器
-graphics.DrawString仍然是GDI +的包装器
然后是如何处理所有现有.NET控件的问题,例如:
LabelButtonTextBox他们希望将它们切换到使用TextRenderer(即GDI),但他们必须小心.可能有些人依赖于他们的控件绘制,就像在.NET 1.1中那样.因此诞生了" 兼容的文本渲染 ".
默认情况下,应用程序中的控件的行为与它们在.NET 1.1中的行为相同(它们是" 兼容的 ").
您通过调用以下命令关闭兼容模式:
Application.SetCompatibleTextRenderingDefault(false);
Run Code Online (Sandbox Code Playgroud)
这使您的应用程序更好,更快,具有更好的国际支持.总结一下:
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
Run Code Online (Sandbox Code Playgroud)
注意GDI + TextRenderingHint与用于GDI字体绘制的相应LOGFONT质量之间的映射也很有用:
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)
Run Code Online (Sandbox Code Playgroud)
这里是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.
也可以看看
小智 2
这对我有用。
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 );
Run Code Online (Sandbox Code Playgroud)
事实证明,Gdiplus::Font 尽管以像素为单位指定,但仍使用用户的 DPI 设置来调整生成的字体(即使该字体用于在位图中绘制!)。标准 DPI 96 是一个很好的值,可以用来确定正确的比例来调整字体大小。
在上面的代码片段中,寻求的字体高度是 8 像素高。
在所有 DPI 设置中,fMeasuredFontHeight 几乎保持不变(约为 12)。