共用方式為


使用自訂文字渲染器進行渲染

DirectWrite的文本布局,可以由衍生自 IDWriteTextRenderer的自訂文字渲染器繪製。 需要自定義轉譯器才能利用 DirectWrite 的一些進階功能,例如轉譯至位圖或 GDI 表面、內嵌物件和用戶端繪圖效果。 本教學課程介紹 IDWriteTextRenderer的方法,並提供一個使用 Direct2D 繪製具有位圖填充文字的範例實作。

本教學課程包含下列部分:

您的自定義文字轉譯器除了 IDWriteTextRenderer 參考頁面和下方所列的方法之外,還必須實作繼承自 IUnknown 的方法。

如需自定義文字轉譯器的完整原始程式碼,請參閱 DirectWrite Hello World 範例的 CustomTextRenderer.cpp 和 CustomTextRenderer.h 檔案。

建構函式

您的自定義文字轉譯器將需要建構函式。 本範例使用實心和點陣圖 Direct2D 筆刷來渲染文字。

因此,建構函式會使用下表中列出的參數及其描述。

參數 描述
pD2DFactory 指向 ID2D1Factory 物件的指標,該物件將用於建立所需的任何 Direct2D 資源。
pRT 指向將用於轉譯文字的 ID2D1HwndRenderTarget 物件的指標。
pOutlineBrush ID2D1SolidColorBrush 指標,將用來繪製文字大綱
pFillBrush 將用於填滿文字的 ID2D1BitmapBrush 指標

 

這些會由建構函式儲存,如下列程式代碼所示。

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 方法是文字轉譯器的主要回呼方法。 它會傳遞要呈現的字形序列,並附加如基準原點和測量模式等資訊。 它還會傳遞用戶端繪圖效果物件,以應用於字形串。 如需詳細資訊,請參閱 如何將用戶端繪圖效果新增至文字配置 主題。

此文字轉譯器實作會將字形行轉換成 Direct2D 幾何體,然後繪製和填充這些幾何體。 這包含下列步驟。

  1. 建立 ID2D1PathGeometry 對象,然後使用 ID2D1PathGeometry::Open 方法來擷取 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. 傳遞至 DrawGlyphRunDWRITE_GLYPH_RUN 包含一個名為 fontFaceIDWriteFontFace 物件,代表整個字形群的字型面。 使用 IDWriteFontFace::GetGlyphRunOutline 方法,將字型的外框放入幾何圖形接收器中,如下列程式碼所示。

    // 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. 填滿幾何接收器之後,關閉它。

    // Close the geometry sink
    if (SUCCEEDED(hr))
    {
        hr = pSink->Close();
    }
    
  4. 字形運行的起源必須被轉換,才能從正確的基準線原點呈現,如下列程式碼所示。

    // 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
        );
    

    baselineOriginXbaselineOriginY 作為參數傳遞至 DrawGlyphRun 回呼方法。

  5. 使用 ID2D1Factory::CreateTransformedGeometry 方法來建立已轉換的幾何,並傳遞路徑幾何和轉譯矩陣。

    // Create the transformed geometry
    ID2D1TransformedGeometry* pTransformedGeometry = NULL;
    if (SUCCEEDED(hr))
    {
        hr = pD2DFactory_->CreateTransformedGeometry(
            pPathGeometry,
            &matrix,
            &pTransformedGeometry
            );
    }
    
  6. 最後,繪製轉換後幾何圖形的輪廓,並使用 ID2D1RenderTarget::DrawGeometryID2D1RenderTarget::FillGeometry 方法,以及儲存為成員變數的 Direct2D 筆刷來填充。

        // Draw the outline of the glyph run
        pRT_->DrawGeometry(
            pTransformedGeometry,
            pOutlineBrush_
            );
    
        // Fill in the glyph run
        pRT_->FillGeometry(
            pTransformedGeometry,
            pFillBrush_
            );
    
  7. 現在您已完成繪圖,別忘了清除在此方法中建立的物件。

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

DrawUnderline() 和 DrawStrikethrough()

IDWriteTextRenderer 也有用於繪製底線和刪除線的回呼函數。 本範例會繪製底線或刪除線用的簡單矩形,但也可以畫其他圖形。

使用 Direct2D 繪製底線包含下列步驟。

  1. 首先,建立底線大小和形狀的 D2D1_RECT_F 結構。 傳遞至 DrawUnderline 回呼方法的 DWRITE_UNDERLINE 結構會提供底線的位移、寬度和粗細。

    D2D1_RECT_F rect = D2D1::RectF(
        0,
        underline->offset,
        underline->width,
        underline->offset + underline->thickness
        );
    
  2. 接下來,使用 ID2D1Factory::CreateRectangleGeometry 方法和初始化 D2D1_RECT_F 結構,建立 ID2D1RectangleGeometry 物件。

    ID2D1RectangleGeometry* pRectangleGeometry = NULL;
    hr = pD2DFactory_->CreateRectangleGeometry(
            &rect, 
            &pRectangleGeometry
            );
    
  3. 如同字元執行,底線幾何的原點必須使用 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. 最後,繪製已轉換幾何的輪廓,並使用 ID2D1RenderTarget::DrawGeometryID2D1RenderTarget::FillGeometry 方法,以及作為成員變數儲存的 Direct2D 筆刷來填充它。

        // Draw the outline of the glyph run
        pRT_->DrawGeometry(
            pTransformedGeometry,
            pOutlineBrush_
            );
    
        // Fill in the glyph run
        pRT_->FillGeometry(
            pTransformedGeometry,
            pFillBrush_
            );
    
  5. 現在您已完成繪圖,別忘了清除在此方法中建立的物件。

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

繪製刪除線的程式相同。 不過,刪除線會有不同的位移,而且寬度和厚度可能不同。

圖元貼齊、每個 DIP 像素和轉換

IsPixelSnappingDisabled()

此方法用於判斷是否已停用像素貼齊。 建議的預設值 FALSE,而這是此範例的輸出。

*isDisabled = FALSE;

GetCurrentTransform()

此範例呈現到 Direct2D 呈現目標,因此需將轉換從呈現目標轉傳。請使用 ID2D1RenderTarget::GetTransform

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

GetPixelsPerDip()

此方法被呼叫以取得每個裝置獨立圖元(DIP)的像素數。

float x, yUnused;

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

DrawInlineObject()

自訂文本渲染器也有用於繪製內嵌物件的回呼函式。 在此範例中,DrawInlineObject 會傳回E_NOTIMPL。 如何繪製內嵌物件的說明已超出本教學課程的範圍。 如需詳細資訊,請參閱 如何將內嵌物件新增至文字配置 主題。

破壞者

請務必釋放自定義文字轉譯器類別使用的任何指標。

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

使用自訂文本呈現器

您可以藉由使用 IDWriteTextLayout::Draw 方法來使用自定義轉譯器進行轉譯,此方法接受衍生自 IDWriteTextRenderer 的回呼介面, 作為引數,如下列程式碼所示。

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

IDWriteTextLayout::Draw 方法會呼叫您提供的自訂回呼渲染器方法。 DrawGlyphRunDrawUnderlineDrawInlineObject,以及上述 DrawStrikethrough 方法執行繪圖函式。