Direct2D - How to draw a text as close as possible to GDI rendering











up vote
1
down vote

favorite












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):



enter image description here



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.










share|improve this question




























    up vote
    1
    down vote

    favorite












    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):



    enter image description here



    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.










    share|improve this question


























      up vote
      1
      down vote

      favorite









      up vote
      1
      down vote

      favorite











      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):



      enter image description here



      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.










      share|improve this question















      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):



      enter image description here



      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.







      text render draw difference directwrite






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 19 at 21:53

























      asked Nov 19 at 20:48









      Jean-Milost Reymond

      502418




      502418





























          active

          oldest

          votes











          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53382408%2fdirect2d-how-to-draw-a-text-as-close-as-possible-to-gdi-rendering%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown






























          active

          oldest

          votes













          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes
















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.





          Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


          Please pay close attention to the following guidance:


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53382408%2fdirect2d-how-to-draw-a-text-as-close-as-possible-to-gdi-rendering%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Feedback on college project

          Futebolista

          Albești (Vaslui)