直接用 rendertarget 的 DrawText 方法显示文字的话无法为文字增加描边,用路径对象配合字体字形进行显示,并在内部用画刷填充的话可以达到描边的效果。
首先初始化的时候创建字体,要显示中文的话需要选择支持中文的字体,否则会因为找不到字模而显示为”囗”,这里选择了黑体作为样例。渲染的时候根据要显示的内容获取对应字模,并以此创建路径对象,创建完成后将其绘制到合适的位置,同时用指定颜色填充内部即可。
附上代码:
void Init()
{
...
hr = DWriteCreateFactory(
DWRITE_FACTORY_TYPE_SHARED,
__uuidof(m_pDWriteFactory),
reinterpret_cast<IUnknown **>(&m_pDWriteFactory)
);
IDWriteFontFile *pFontFiles{ nullptr };
hr = m_pDWriteFactory->CreateFontFileReference(
L"simhei.ttf", NULL, &pFontFiles
);
assert(SUCCEEDED(hr));
IDWriteFontFile *fontFileArray[] = { pFontFiles };
hr = m_pDWriteFactory->CreateFontFace(
DWRITE_FONT_FACE_TYPE_TRUETYPE,
ARRAYSIZE(fontFileArray), // file count
fontFileArray,
0,
DWRITE_FONT_SIMULATIONS_NONE,
&m_pFontFace
);
assert(SUCCEEDED(hr));
SafeRelease(&pFontFiles);
...
}
void DrawText(
const wchar_t * string,
unsigned int stringLength,
IDWriteTextFormat * textFormat,
const Rectangle & layoutRect
)
{
UINT* pCodePoints = new UINT[stringLength];
UINT16* pGlyphIndices = new UINT16[stringLength];
ZeroMemory(pCodePoints, sizeof(UINT) * stringLength);
ZeroMemory(pGlyphIndices, sizeof(UINT16) * stringLength);
for (int i = 0; i < stringLength; ++i)
{
pCodePoints[i] = string[i];
}
HRESULT hr;
// 确认字形是否存在
hr = m_pFontFace->GetGlyphIndicesW(pCodePoints, stringLength, pGlyphIndices);
// 将文字描边储存至路径几何对象, 18.0f 为字号大小
hr = m_pDirect2dFactory->CreatePathGeometry(&m_pPathGeometry);
hr = m_pPathGeometry->Open(&m_pGeometrySink);
hr = m_pFontFace->GetGlyphRunOutline(18.0f, pGlyphIndices,
NULL, NULL, stringLength, FALSE, FALSE, m_pGeometrySink
);
hr = m_pGeometrySink->Close();
IDWriteTextLayout* pTextLayout = NULL;
// 获取文本尺寸
hr = m_pDWriteFactory->CreateTextLayout(string, stringLength, textFormat, 0.0f, 0.0f, &pTextLayout);
DWRITE_TEXT_METRICS textMetrics;
hr = pTextLayout->GetMetrics(&textMetrics);
SafeRelease(&pTextLayout);
D2D1_MATRIX_3X2_F old;
D2D1_RECT_F bounds;
m_pRenderTarget->GetTransform(&old);
m_pPathGeometry->GetBounds(old, &bounds);
m_pRenderTarget->SetTransform(D2D1::Matrix3x2F::Translation(
layoutRect.GetLeft() + (layoutRect.GetWidth() - bounds.right + bounds.left + textMetrics.left) / 2.0f,
layoutRect.GetBottom() - (layoutRect.GetHeight() - bounds.bottom + bounds.top) / 2.0f));
m_pRenderTarget->DrawGeometry(m_pPathGeometry, m_pBlackBrush, 1.0f);
m_pRenderTarget->FillGeometry(m_pPathGeometry, m_pWhiteBrush);
m_pRenderTarget->SetTransform(old);
SafeDeleteArray(&pCodePoints);
SafeDeleteArray(&pGlyphIndices);
SafeRelease(&m_pGeometrySink);
SafeRelease(&m_pPathGeometry);
}
