我正在使用Embarcadero RAD Studio(10.2 Tokyo starter)和Windows GDI创建一个c ++项目,通过DrawText()函数绘制文本。
我最近看到Windows 10提供了一个新的" Segoe UI Emoji"字体,可能允许文本函数绘制彩色表情符号。我发现了几个使用Direct2D的例子,但没有一个使用纯GDI函数。
我还尝试了一个简单的代码,如下所示:
HDC hDC = ::GetDC(Handle);
std::auto_ptr<TCanvas> pCanvas(new TCanvas());
pCanvas->Handle = hDC;
pCanvas->Brush->Color = clWhite;
pCanvas->Brush->Style = bsSolid;
pCanvas->FillRect(TRect(0, 0, ClientWidth, ClientHeight));
const std::wstring text = L"Test ";
TRect textRect(10, 10, ClientWidth - 10, ClientHeight - 10);
hFont = ::CreateFont(-40,
0,
0,
0,
FW_DONTCARE,
FALSE,
FALSE,
FALSE,
DEFAULT_CHARSET,
OUT_OUTLINE_PRECIS,
CLIP_DEFAULT_PRECIS,
CLEARTYPE_QUALITY,
VARIABLE_PITCH,
L"Segoe UI Emoji");
::SelectObject(hDC, hFont);
::DrawTextW(hDC,
text.c_str(),
text.length(),
&textRect,
DT_LEFT | DT_TOP | DT_SINGLELINE);
::DeleteObject(hFont);
输出结果在符号方面听起来不错,但它们是以黑白两种颜色绘制的,没有颜色,如下面的屏幕截图所示:
我找不到任何其他可能允许使用彩色符号而不是黑色和白色绘制文本的选项。有没有办法在GDI DrawText()函数中激活颜色的支持,如果是的话,怎么做?或者只有Direct2D可以绘制彩色表情符号?
于2017年10月30日编辑
由于GDI无法完成这项工作(不幸的是,正如我所想),我在这里发布了上述代码的Direct2D版本,这对我有用。
const std::wstring text = L"Test ";
HDC hDC = ::GetDC(Handle);
std::auto_ptr<TCanvas> pGDICanvas(new TCanvas());
pGDICanvas->Handle = hDC;
pGDICanvas->Brush->Color = clWhite;
pGDICanvas->Brush->Style = bsSolid;
pGDICanvas->FillRect(TRect(0, 0, ClientWidth, ClientHeight));
::D2D1_RECT_F textRect;
textRect.left = 10;
textRect.top = 10;
textRect.right = ClientWidth - 10;
textRect.bottom = ClientHeight - 10;
std::auto_ptr<TDirect2DCanvas> pCanvas(new TDirect2DCanvas(hDC, TRect(0, 0, ClientWidth, ClientHeight)));
// configure Direct2D font
pCanvas->Font->Size = 40;
pCanvas->Font->Name = L"Segoe UI Emoji";
pCanvas->Font->Orientation = 0;
pCanvas->Font->Pitch = System::Uitypes::TFontPitch::fpVariable;
pCanvas->Font->Style = TFontStyles();
// get DirectWrite text format object
_di_IDWriteTextFormat pFormat = pCanvas->Font->Handle;
if (!pFormat)
return;
pCanvas->RenderTarget->SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE);
::D2D1_COLOR_F color;
color.r = 0.0f;
color.g = 0.0f;
color.b = 0.0f;
color.a = 1.0f;
::ID2D1SolidColorBrush* pBrush = NULL;
// create solid color brush, use pen color if rect is completely filled with outline
pCanvas->RenderTarget->CreateSolidColorBrush(color, &pBrush);
if (!pBrush)
return;
// set horiz alignment
pFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING);
// set vert alignment
pFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_NEAR);
// set reading direction
pFormat->SetReadingDirection(DWRITE_READING_DIRECTION_LEFT_TO_RIGHT);
// set word wrapping mode
pFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
IDWriteInlineObject* pInlineObject = NULL;
::DWRITE_TRIMMING trimming;
trimming.delimiter = 0;
trimming.delimiterCount = 0;
trimming.granularity = DWRITE_TRIMMING_GRANULARITY_NONE;
// set text trimming
pFormat->SetTrimming(&trimming, pInlineObject);
pCanvas->BeginDraw();
pCanvas->RenderTarget->DrawText(text.c_str(), text.length(), pFormat, textRect, pBrush,
D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT);
pCanvas->EndDraw();
当然,此代码仅在当前最新版本的Windows 10及更高版本上绘制彩色表情符号。在以前的版本中,文本将如上绘制(并且代码可能无法编译)。
答案 0 :(得分:3)
GDI不支持彩色字体(即使你使用完整的Uniscribe路线),如果你想要彩色字体支持,你必须使用Direct2D。有意义的是,较简单的GDI API不支持颜色字体,因为颜色字体需要使用OpenType标签,并且没有DrawText / TextOut提供该级别的控制,Uniscribe允许这样的标签,但是根本没有扩展到支持颜色字体。 / p>
答案 1 :(得分:1)
您可以使用DirectWrite将彩色表情符号绘制到内存DC中的位图上,然后将BitBlt()绘制到目标DC上。基本上,您需要实现自定义IDWriteTextRenderer类并使用渲染器调用IDWriteTextLayout :: Draw(),然后复制结果。在您的类中,从IDWriteFactory检索IDWriteGdiInterop并调用IDWriteGdiInterop :: CreateBitmapRenderTarget()以获取位图渲染目标;调用IDWriteFactory :: CreateMonitorRenderingParams()来获取渲染参数,并调用IDWriteFactory :: CreateTextFormat()来设置文本格式。唯一重要的方法是DrawGlyphRun(),你可以通过IDWriteFactory2 :: TranslateColorGlyphRun()得到IDWriteColorGlyphRunEnumerator,并且每次运行颜色,调用IDWriteBitmapRenderTarget :: DrawGlyphRun()来为你完成工作。 只需记住在窗口大小/位置更改时更新渲染目标/参数。 您可以参考此MSDN文档:
渲染到GDI曲面 https://msdn.microsoft.com/en-us/library/windows/desktop/ff485856(v=vs.85).aspx