Я работаю с компилятором Embarcadero RAD Studio XE7 (C ++ Builder), в котором я пробую предоставленный Direct2D API. Моя цель состоит в том, чтобы создавать приложения, которые обеспечивают точно такой же рендеринг, как и GDI, но которые также могут принести пользу новым функциям, предоставляемым Direct2D, таким как, например, цветные эмодзи в Window 10.
В этом контексте я написал небольшую функцию рисования текста, которая использует Direct2D для выполнения этой работы. Я также искал, как настроить Direct2D / DirectWrite для рисования текста как можно ближе к тому, что делает GDI.
Это привело к следующей функции:
void DrawText_Direct2D(const std::wstring& text, const TRect& rect, TColor bgColor,
TFont* pFont, TCanvas* pCanvas)
{
if (!pFont || !pCanvas)
return;
// fill destination canvas background with provided color
WGDIHelper::Fill(pCanvas, rect, bgColor);
::D2D1_RECT_F drawRect;
drawRect.left = rect.Left;
drawRect.top = rect.Top;
drawRect.right = rect.Right;
drawRect.bottom = rect.Bottom;
// get Direct2D destination canvas
std::unique_ptr<TDirect2DCanvas> pD2DCanvas(new TDirect2DCanvas(pCanvas->Handle, rect));
// configure Direct2D font
pD2DCanvas->Font->Height = pFont->Height;
pD2DCanvas->Font->Name = pFont->Name;
pD2DCanvas->Font->Orientation = pFont->Orientation;
pD2DCanvas->Font->Pitch = pFont->Pitch;
pD2DCanvas->Font->Style = pFont->Style;
// get DirectWrite text format object
_di_IDWriteTextFormat pFormat = pD2DCanvas->Font->Handle;
// found it?
if (!pFormat)
return;
// get (or create) the DirectWrite factory
_di_IDWriteFactory pDirectWrite = ::DWriteFactory(DWRITE_FACTORY_TYPE_SHARED);
if (!pDirectWrite)
return;
// configure and apply new rendering parameters for DirectWrite
_di_IDWriteRenderingParams renderParams;
pDirectWrite->CreateCustomRenderingParams(1.0f, 0.0f, 0.0f, DWRITE_PIXEL_GEOMETRY_RGB,
DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL, &renderParams);
pD2DCanvas->RenderTarget->SetTextRenderingParams(renderParams);
// set antialiasing mode
pD2DCanvas->RenderTarget->SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE);
::ID2D1SolidColorBrush* pBrush = NULL;
WColor color(pFont->Color);
// create solid color brush
pD2DCanvas->RenderTarget->CreateSolidColorBrush(color.GetD2DColor(), &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_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);
try
{
pD2DCanvas->BeginDraw();
// draw the text
pD2DCanvas->RenderTarget->DrawText(text.c_str(), text.length(), pFormat, drawRect, pBrush,
D2D1_DRAW_TEXT_OPTIONS_NONE);
}
__finally
{
pD2DCanvas->EndDraw();
}
}
Код выше - это то, что я могу сделать ближе к рисованию текста GDI. Однако есть небольшие отличия, которые я не могу исправить. Вот снимок экрана с текстом, нарисованным с помощью GDI и с вышеуказанной функцией ( NOTE , что изображение ниже растянуто и должно быть открыто в его реальном размере):
Как вы можете видеть, текст D2D длиннее, чем текст GDI, и несколько слов, например "humanum", четко различаются в обеих версиях. Кроме того, сглаживание несколько отличается в отношении нескольких слов, например, первого «текстового» слова, включая следующую запятую, что заставляет эти слова выглядеть несколько размытыми.
Однако иметь похожий рисунок, но с небольшими видимыми различиями, для меня неприемлемо. Мне нужен рисунок без различий, или, по крайней мере, там, где различия почти не видны (т.е. без тщательного сравнения).
AFAIK используется тот же шрифт, и к DirectWrite был применен правильный режим cleartype. Так как же улучшить мой рендеринг Direct2D, чтобы он выглядел еще ближе к старому доброму GDI? Есть ли способ сделать это?
ПРИМЕЧАНИЕ Я уже нашел и прочитал несколько веток, рассказывающих о разнице в качестве текста между Direct2D и GDI, например, например,
Почему визуализация текста в DirectX / DirectWrite / Direct2D не может быть такой же четкой, как в GDI?
Проблема интерфейса Direct2D и размытого текста
К сожалению, в моем случае я уже включил предложенные опции, чтобы позволить Direct2D рисовать текст как GDI (по крайней мере, я думаю, что я сделал это правильно), но результат все еще не достаточно хорош, чтобы позволить мне использовать его в моих проектах.