I'm working with Embarcadero RAD Studio XE7 compiler (C++ Builder), in which I'm trying the provided Direct2D API. My purpose is to create applications which provide the exact same rendering as the GDI did, but which also may benefit the new features Direct2D provides, like e.g the colored emojis on Window 10.
In this context, I wrote a small text drawing function, which uses Direct2D to do the job. I also searched about how to configure Direct2D/DirectWrite to draw a text as close as possible to what GDI does.
This resulted to the following function:
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();
}
}
The code above is what I can do closer to the GDI text drawing. There are, however, small differences that I can not correct. Here is a screenshot of a text drawn with the GDI, and with the above function (NOTE that the image below is stretched and should be opened in his real size):
As you can see, the D2D text is longer than the GDI one, and several words, like "humanum", are clearly drawn differently between the both versions. Furthermore the antialiasing is somewhat different around several words, like the first "text" word, including the following comma, which cause these words to appear somewhat blurry again.
However, having a drawing similar but with small visible differences isn't an acceptable option for me. I need a drawing without difference, or at least where the differences are almost not visible (i.e without a thorough comparison).
AFAIK the same font are used, and the correct cleartype mode was applied to DirectWrite. So how can I improve my Direct2D rendering to look even closer to the good old GDI? Is there a way to do that?
NOTE I already found and read several threads speaking about the difference in text quality between Direct2D and GDI, like e.g
Why can't DirectX/DirectWrite/Direct2D text rendering be as sharp as GDI?
Direct2D interface and blurry text issue
Unfortunately, in my case, I already enabled the proposed options to allow Direct2D to draw the text like the GDI (at least I think I did that correctly), but the result is still not good enough to allow me to use it in my projects.
I suggest using CreateGdiCompatibleTextLayout instead, simply because there is no DrawTextInGdiCompatibleWay function variant in Direct2D. It won't necessarily match gdi output exactly, but hopefully will be closer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With