Sdílet prostřednictvím


Vykreslení pomocí vlastního rendereru textu

Rozložení textu DirectWrite lze nakreslit vlastním vykreslovačem textu odvozeným z IDWriteTextRenderer. Vlastní renderer je nutný k využití některých pokročilých funkcí DirectWrite, jako je vykreslování na rastrový obrázek nebo povrch GDI, vložené objekty a klientské kreslicí efekty. Tento kurz popisuje metody IDWriteTextRenderera poskytuje ukázkovou implementaci, která používá Direct2D k vykreslení textu pomocí rastrové výplně.

Tento kurz obsahuje následující části:

Váš vlastní textový renderer musí implementovat metody zděděné z IUnknown kromě metod uvedených na IDWriteTextRenderer referenční stránce a níže.

Úplný zdrojový kód pro renderer vlastního textu naleznete v CustomTextRenderer.cpp a CustomTextRenderer.h soubory DirectWrite Hello World Sample.

Konstruktor

Váš vlastní renderer textu bude potřebovat konstruktor. Tento příklad používá k vykreslení textu plné i rastrové Direct2D štětce.

Z tohoto důvodu konstruktor přebírá parametry nalezené v následující tabulce s popisy.

Parametr Popis
pD2DFactory Ukazatel na objekt ID2D1Factory, který se použije k vytvoření potřebných prostředků Direct2D.
pRT Ukazatel na objekt ID2D1HwndRenderTarget, na který bude text vykreslen.
pOutlineBrush Ukazatel na ID2D1SolidColorBrush, který se použije k vykreslení obrysu textu
pFillBrush Ukazatel na ID2D1BitmapBrush, který bude použit k vyplnění textu.

 

Tyto budou uloženy konstruktorem, jak je znázorněno v následujícím kódu.

CustomTextRenderer::CustomTextRenderer(
    ID2D1Factory* pD2DFactory, 
    ID2D1HwndRenderTarget* pRT, 
    ID2D1SolidColorBrush* pOutlineBrush, 
    ID2D1BitmapBrush* pFillBrush
    )
:
cRefCount_(0), 
pD2DFactory_(pD2DFactory), 
pRT_(pRT), 
pOutlineBrush_(pOutlineBrush), 
pFillBrush_(pFillBrush)
{
    pD2DFactory_->AddRef();
    pRT_->AddRef();
    pOutlineBrush_->AddRef();
    pFillBrush_->AddRef();
}

DrawGlyphRun()

DrawGlyphRun metoda je hlavní metodou zpětného volání rendereru textu. Předává se sada glyfů, které se mají vykreslit spolu s informacemi, jako je počátek základní linie a režim měření. Také předá objekt efektu výkresu klienta, který se použije na spuštění glyphu. Další informace najdete v tématu Jak přidat efekty kreslení klienta do rozložení textu.

Tato implementace vykreslovacího modulu textu vykresluje běhy glyfů jejich převedením na Direct2D geometrie a poté nakreslí a vyplní geometrie. Skládá se z následujících kroků.

  1. Vytvořte objekt ID2D1PathGeometry a potom pomocí metody ID2D1PathGeometry::Open načtěte objekt ID2D1GeometrySink.

    // Create the path geometry.
    ID2D1PathGeometry* pPathGeometry = NULL;
    hr = pD2DFactory_->CreatePathGeometry(
            &pPathGeometry
            );
    
    // Write to the path geometry using the geometry sink.
    ID2D1GeometrySink* pSink = NULL;
    if (SUCCEEDED(hr))
    {
        hr = pPathGeometry->Open(
            &pSink
            );
    }
    
  2. DWRITE_GLYPH_RUN, který se předá DrawGlyphRun, obsahuje objekt IDWriteFontFace s názvem fontFace, který představuje řez písma pro celý běh glyfů. Předejte obrys běhu glyfů do jímky geometrie pomocí metody IDWriteFontFace::GetGlyphRunOutline, jak je ukázáno v následujícím kódu.

    // Get the glyph run outline geometries back from DirectWrite and place them within the
    // geometry sink.
    if (SUCCEEDED(hr))
    {
        hr = glyphRun->fontFace->GetGlyphRunOutline(
            glyphRun->fontEmSize,
            glyphRun->glyphIndices,
            glyphRun->glyphAdvances,
            glyphRun->glyphOffsets,
            glyphRun->glyphCount,
            glyphRun->isSideways,
            glyphRun->bidiLevel%2,
            pSink
            );
    }
    
  3. Po vyplnění geometrické jímky ji zavřete.

    // Close the geometry sink
    if (SUCCEEDED(hr))
    {
        hr = pSink->Close();
    }
    
  4. Původ sekvence glyfů musí být upraven tak, aby se vykresloval z výchozí základní linie, jak je znázorněno v následujícím kódu.

    // Initialize a matrix to translate the origin of the glyph run.
    D2D1::Matrix3x2F const matrix = D2D1::Matrix3x2F(
        1.0f, 0.0f,
        0.0f, 1.0f,
        baselineOriginX, baselineOriginY
        );
    

    baselineOriginX a baselineOriginY se předávají jako parametry metodě zpětného volání DrawGlyphRun.

  5. Vytvořte transformovanou geometrii pomocí metody ID2D1Factory::CreateTransformedGeometry, a to předáním geometrie cesty a matice překladu.

    // Create the transformed geometry
    ID2D1TransformedGeometry* pTransformedGeometry = NULL;
    if (SUCCEEDED(hr))
    {
        hr = pD2DFactory_->CreateTransformedGeometry(
            pPathGeometry,
            &matrix,
            &pTransformedGeometry
            );
    }
    
  6. Nakonec nakreslete obrys transformované geometrie a vyplňte ji pomocí ID2D1RenderTarget::D rawGeometry a ID2D1RenderTarget::FillGeometry metody a Direct2D štětce uložené jako členské proměnné.

        // Draw the outline of the glyph run
        pRT_->DrawGeometry(
            pTransformedGeometry,
            pOutlineBrush_
            );
    
        // Fill in the glyph run
        pRT_->FillGeometry(
            pTransformedGeometry,
            pFillBrush_
            );
    
  7. Nyní, když jste dokončili kreslení, nezapomeňte vyčistit objekty vytvořené v této metodě.

    SafeRelease(&pPathGeometry);
    SafeRelease(&pSink);
    SafeRelease(&pTransformedGeometry);
    

DrawUnderline() a DrawStrikethrough()

IDWriteTextRenderer má také zpětná volání pro kreslení podtržení a přeškrtnutí. Tento příklad nakreslí jednoduchý obdélník pro podtržení nebo přeškrtnutí, ale je možné nakreslit i jiné tvary.

Kreslení podtržení pomocí Direct2D se skládá z následujících kroků.

  1. Nejprve vytvořte D2D1_RECT_F strukturu velikosti a tvaru podtržení. DWRITE_UNDERLINE struktura, která je předána metodě zpětného volání DrawUnderline, poskytuje posun, šířku a tloušťku podtržení.

    D2D1_RECT_F rect = D2D1::RectF(
        0,
        underline->offset,
        underline->width,
        underline->offset + underline->thickness
        );
    
  2. Dále vytvořte objekt ID2D1RectangleGeometry pomocí metody ID2D1Factory::CreateRectangleGeometry a inicializované struktury D2D1_RECT_F.

    ID2D1RectangleGeometry* pRectangleGeometry = NULL;
    hr = pD2DFactory_->CreateRectangleGeometry(
            &rect, 
            &pRectangleGeometry
            );
    
  3. Stejně jako u spuštění glyfů musí být původ geometrie podtržení přeložen na základě hodnot původu základní linie pomocí metody CreateTransformedGeometry.

    // Initialize a matrix to translate the origin of the underline
    D2D1::Matrix3x2F const matrix = D2D1::Matrix3x2F(
        1.0f, 0.0f,
        0.0f, 1.0f,
        baselineOriginX, baselineOriginY
        );
    
    ID2D1TransformedGeometry* pTransformedGeometry = NULL;
    if (SUCCEEDED(hr))
    {
        hr = pD2DFactory_->CreateTransformedGeometry(
            pRectangleGeometry,
            &matrix,
            &pTransformedGeometry
            );
    }
    
  4. Nakonec nakreslete obrys transformované geometrie a vyplňte ji pomocí metod ID2D1RenderTarget::DrawGeometry a ID2D1RenderTarget::FillGeometry a štětců Direct2D uložených jako členské proměnné.

        // Draw the outline of the glyph run
        pRT_->DrawGeometry(
            pTransformedGeometry,
            pOutlineBrush_
            );
    
        // Fill in the glyph run
        pRT_->FillGeometry(
            pTransformedGeometry,
            pFillBrush_
            );
    
  5. Nyní, když jste dokončili kreslení, nezapomeňte vyčistit objekty vytvořené v této metodě.

    SafeRelease(&pRectangleGeometry);
    SafeRelease(&pTransformedGeometry);
    

Proces provádění přeškrtnutí je stejný. Přeškrtnutí však bude mít jiný posun a pravděpodobně jinou šířku a tloušťku.

Přichycení pixelů, Pixely na DPI a Transformace

IsPixelSnappingDisabled()

Tato metoda je volána k určení, zda je funkce přichytávání pixelů zakázána. Doporučené výchozí nastavení je FALSEa to je výstup tohoto příkladu.

*isDisabled = FALSE;

GetCurrentTransform()

Tento příklad se vykreslí do cíle vykreslení Direct2D, takže předáte transformaci z cíle vykreslení pomocí ID2D1RenderTarget::GetTransform.

//forward the render target's transform
pRT_->GetTransform(reinterpret_cast<D2D1_MATRIX_3X2_F*>(transform));

GetPixelsPerDip()

Tato metoda se volá k získání počtu pixelů na pixel nezávislý na zařízení (DIP).

float x, yUnused;

pRT_->GetDpi(&x, &yUnused);
*pixelsPerDip = x / 96;

DrawInlineObject()

Vlastní textový renderer má také zpětné volání pro kreslení vložených objektů. V tomto příkladu DrawInlineObject vrátí E_NOTIMPL. Vysvětlení, jak nakreslit vložené objekty, je nad rámec tohoto kurzu. Další informace najdete v tématu Jak přidat vložené objekty do rozložení textu.

Destruktor

Je důležité uvolnit všechny ukazatele, které byly používány vlastní třídou rendereru textu.

CustomTextRenderer::~CustomTextRenderer()
{
    SafeRelease(&pD2DFactory_);
    SafeRelease(&pRT_);
    SafeRelease(&pOutlineBrush_);
    SafeRelease(&pFillBrush_);
}

Použití vlastního rendereru textu

Při vykreslování pomocí vlastního rendereru používáte metodu IDWriteTextLayout::Draw, která přebírá jako argument rozhraní zpětného volání odvozené z IDWriteTextRenderer, jak je znázorněno v následujícím kódu.

// Draw the text layout using DirectWrite and the CustomTextRenderer class.
hr = pTextLayout_->Draw(
        NULL,
        pTextRenderer_,  // Custom text renderer.
        origin.x,
        origin.y
        );

Metoda IDWriteTextLayout::Draw volá metody vlastního rendereru, které zadáváte jako zpětné volání. DrawGlyphRun, DrawUnderline, DrawInlineObjecta DrawStrikethrough metody popsané výše provádějí funkce kreslení.