[ATL/WTL]_[Gdiplus]_[关于使用Graphics::DrawString替换DrawText的说明]

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/infoworld/article/details/83183528

场景

  1. 在开发WTLMFC程序时, 绘制文本往往会使用标准的CDC::DrawText函数, 其实也就是调用了GDIDrawText函数, 但是这个函数绘制出来的文字显示出来的效果会比记事本显示的效果差?什么原因呢.

  2. GDI在绘制文本, 线条时总是感觉比较粗糙, 边缘总是有锯齿, 不够平滑.

说明

  1. 因为GDI绘制图形时并没有消除锯齿的效果, 绘制出来的文本线条边缘是不平滑的, 这种情况如果在分辨率不高时没问题, 但是如果屏幕分辨率高了, 就很明显看出来一个字符各个部分粗细不一. 自从Gdiplus出来之后, 为了界面显示更美观, 直接切换使用Gdiplus, 使用Graphics来绘制是最好的, 不止线条还有图形.

  2. Graphics设置文本质量等级的方法SetTextRenderingHint, 用来设置是否具备AntiAlias(抗锯齿). 注意Hinting 意思是微调, 指示Gdiplus会根据绘制区域和绘制文本的大小, 位置进行微调, 比如字体的宽度, 字符间距等.
    使用这种效果可能会导致字体变形. TextRenderingHintClearTypeGridFit对于大部分LCD显示器提供最好的显示质量, 但是它只适用在小字号的字体上. 如果使用大字号并不合适. TextRenderingHintAntiAlias 对于旋转字体提供最好的质量, 无关大小号字体. 当然这个属性也会耗费最多的性能. TextRenderingHintSystemDefault 会根据系统性能来调整, 性能好的时候其实和TextRenderingHintAntiAlias 是一样的效果.

enum TextRenderingHint
{
    TextRenderingHintSystemDefault = 0,            // Glyph with system default rendering hint
    TextRenderingHintSingleBitPerPixelGridFit,     // Glyph bitmap with hinting
    TextRenderingHintSingleBitPerPixel,            // Glyph bitmap without hinting
    TextRenderingHintAntiAliasGridFit,             // Glyph anti-alias bitmap with hinting
    TextRenderingHintAntiAlias,                    // Glyph anti-alias bitmap without hinting
    TextRenderingHintClearTypeGridFit              // Glyph CT bitmap with hinting
};

例子

  1. 以下例子说明了DrawText使用的两种情形, 使用Graphics::DrawString都可以替换, 而且绘制质量更高.

图示
在这里插入图片描述

HFONT GetFont(int pixel,bool bold,const wchar_t* font_name)
{
	LOGFONT lf; 
	memset(&lf, 0, sizeof(LOGFONT)); // zero out structure 
	lf.lfHeight = pixel; // request a 8-pixel-height font
	if(bold)
	{
		lf.lfWeight = FW_BOLD;  
	}
	lstrcpy(lf.lfFaceName, font_name); // request a face name "Arial"

	HFONT font = ::CreateFontIndirect(&lf);
	return font;
}
	
LRESULT OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
	CPaintDC dc(m_hWnd);

	//auto font = GetFont(16,true,L"Arial");
	//dc.SelectFont(font);

	// Gdi
	std::wstring str_connect_via_usb_(L"Connect via USB");
	CSize size;
	dc.GetTextExtent(str_connect_via_usb_.c_str(),str_connect_via_usb_.size(),&size);
	CRect rect_str;
	rect_str.left = 0;
	rect_str.right = size.cx;
	rect_str.top = 0;
	rect_str.bottom = size.cy;
	dc.DrawText(str_connect_via_usb_.c_str(),str_connect_via_usb_.size(),&rect_str, DT_LEFT);

	// Gdiplus
	Gdiplus::Graphics graphics(dc);
	Gdiplus::FontFamily fontFamily(L"Arial");
	Gdiplus::Font font_normal_bold_(&fontFamily,16,Gdiplus::FontStyleBold,Gdiplus::UnitPixel);

	Gdiplus::RectF rect_connect_via_usb_;
	graphics.MeasureString(str_connect_via_usb_.c_str(),str_connect_via_usb_.size(),&font_normal_bold_,
		Gdiplus::PointF(0,0),&rect_connect_via_usb_);
	rect_connect_via_usb_.Y = rect_str.bottom+10;

	Gdiplus::StringFormat stringFormat;
	stringFormat.SetAlignment(Gdiplus::StringAlignmentNear);
	// https://docs.microsoft.com/en-us/windows/desktop/api/gdiplusstringformat/nf-gdiplusstringformat-stringformat-generictypographic
	const Gdiplus::StringFormat* pStringFormat = Gdiplus::StringFormat::GenericTypographic();
	graphics.SetTextRenderingHint(Gdiplus::TextRenderingHintSystemDefault);
	graphics.DrawString(str_connect_via_usb_.c_str(),str_connect_via_usb_.size(),
		&font_normal_bold_,rect_connect_via_usb_,pStringFormat,
		&Gdiplus::SolidBrush(Gdiplus::Color(0,0,0)));

	// Gdi
	std::wstring str_desc(L"Language ID is set to neutral language, which means that the current language associated with the calling thread is used.");
	CRect rect_desc;
	rect_desc.top = rect_connect_via_usb_.Y+rect_connect_via_usb_.Height+10;
	rect_desc.right = 300;
	int height = dc.DrawText(str_desc.c_str(),str_desc.size(), &rect_desc,
		DT_TOP| DT_WORDBREAK|DT_EDITCONTROL | DT_LEFT | DT_NOPREFIX|DT_CALCRECT);
	dc.DrawText(str_desc.c_str(),str_desc.size(), &rect_desc,
		DT_TOP| DT_WORDBREAK|DT_EDITCONTROL | DT_LEFT | DT_NOPREFIX);

	// Gdiplus
	Gdiplus::RectF rectf_desc;
	Gdiplus::RectF rectf_desc_temp;
	rectf_desc_temp.Width = 300;
	graphics.MeasureString(str_desc.c_str(),str_desc.size(),&font_normal_bold_,
		rectf_desc_temp,&rectf_desc);
	rectf_desc.Y = rect_desc.bottom+10;
	graphics.SetTextRenderingHint(Gdiplus::TextRenderingHintAntiAlias);
	graphics.DrawString(str_desc.c_str(),str_desc.size(),
		&font_normal_bold_,rectf_desc,pStringFormat,
		&Gdiplus::SolidBrush(Gdiplus::Color(0,0,0)));

	auto desktopDc = ::GetDC(NULL);
	auto horizontalDPI = GetDeviceCaps(desktopDc,LOGPIXELSX);  
	auto verticalDPI = GetDeviceCaps(desktopDc,LOGPIXELSY); 

	return 0;
}

参考

TextRenderingHint Enumeration

猜你喜欢

转载自blog.csdn.net/infoworld/article/details/83183528
WTL