Direct2D - Как нарисовать текст как можно ближе к рендерингу GDI - PullRequest
0 голосов
/ 19 ноября 2018

Я работаю с компилятором 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 , что изображение ниже растянуто и должно быть открыто в его реальном размере):

enter image description here

Как вы можете видеть, текст D2D длиннее, чем текст GDI, и несколько слов, например "humanum", четко различаются в обеих версиях. Кроме того, сглаживание несколько отличается в отношении нескольких слов, например, первого «текстового» слова, включая следующую запятую, что заставляет эти слова выглядеть несколько размытыми.

Однако иметь похожий рисунок, но с небольшими видимыми различиями, для меня неприемлемо. Мне нужен рисунок без различий, или, по крайней мере, там, где различия почти не видны (т.е. без тщательного сравнения).

AFAIK используется тот же шрифт, и к DirectWrite был применен правильный режим cleartype. Так как же улучшить мой рендеринг Direct2D, чтобы он выглядел еще ближе к старому доброму GDI? Есть ли способ сделать это?

ПРИМЕЧАНИЕ Я уже нашел и прочитал несколько веток, рассказывающих о разнице в качестве текста между Direct2D и GDI, например, например,

Почему визуализация текста в DirectX / DirectWrite / Direct2D не может быть такой же четкой, как в GDI?

Проблема интерфейса Direct2D и размытого текста

К сожалению, в моем случае я уже включил предложенные опции, чтобы позволить Direct2D рисовать текст как GDI (по крайней мере, я думаю, что я сделал это правильно), но результат все еще не достаточно хорош, чтобы позволить мне использовать его в моих проектах.

1 Ответ

0 голосов
/ 05 декабря 2018

Я предлагаю использовать CreateGdiCompatibleTextLayout вместо этого просто потому, что в Direct2D нет варианта функции DrawTextInGdiCompatibleWay (). Это не обязательно будет точно соответствовать выводу gdi, но, надеюсь, будет ближе.

...