使用自訂文字轉譯器呈現
DirectWrite文字配置可由衍生自IDWriteTextRenderer的自訂文字轉譯器繪製。 需要自訂轉譯器,才能利用DirectWrite的一些進階功能,例如轉譯至點陣圖或 GDI 表面、内嵌物件和用戶端繪圖效果。 本教學課程說明 IDWriteTextRenderer的方法,並提供使用 Direct2D 轉譯點陣圖填滿文字的範例實作。
本教學課程包含下列部分:
- 建構函式
- DrawGlyphRun ()
- DrawUnderline () 和 DrawStrikethrough ()
- 圖元貼齊、每個 DIP 的圖元和轉換
- DrawInlineObject ()
- 解構函式
- 使用自訂文字轉譯器
除了 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 幾何,然後繪製並填滿幾何,以轉譯字元執行。 這包含下列步驟。
建立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 ); }
傳遞至DrawGlyphRun的DWRITE_GLYPH_RUN包含IDWriteFontFace物件,名為fontFace,代表整個字元執行的字型臉部。 使用 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 ); }
填滿幾何接收器之後,請將其關閉。
// Close the geometry sink if (SUCCEEDED(hr)) { hr = pSink->Close(); }
字元執行的原點必須轉譯,才能從正確的基準原點轉譯,如下列程式碼所示。
// 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和baselineOriginY會當做參數傳遞至DrawGlyphRun回呼方法。
使用 ID2D1Factory::CreateTransformedGeometry 方法來建立轉換的幾何,並傳遞路徑幾何和轉譯矩陣。
// Create the transformed geometry ID2D1TransformedGeometry* pTransformedGeometry = NULL; if (SUCCEEDED(hr)) { hr = pD2DFactory_->CreateTransformedGeometry( pPathGeometry, &matrix, &pTransformedGeometry ); }
最後,繪製已轉換幾何的外框,並使用 ID2D1RenderTarget::D rawGeometry 和 ID2D1RenderTarget::FillGeometry 方法,以及儲存為成員變數的 Direct2D 筆刷來填滿它。
// Draw the outline of the glyph run pRT_->DrawGeometry( pTransformedGeometry, pOutlineBrush_ ); // Fill in the glyph run pRT_->FillGeometry( pTransformedGeometry, pFillBrush_ );
現在您已完成繪圖,別忘了清除此方法中建立的物件。
SafeRelease(&pPathGeometry); SafeRelease(&pSink); SafeRelease(&pTransformedGeometry);
DrawUnderline () 和 DrawStrikethrough ()
IDWriteTextRenderer 也有回呼來繪製底線和刪除線。 本範例會繪製底線或刪除線的簡單矩形,但可以繪製其他圖形。
使用 Direct2D 繪製底線包含下列步驟。
首先,建立底線大小和形狀的 D2D1_RECT_F 結構。 傳遞至DrawUnderline回呼方法的DWRITE_UNDERLINE結構會提供底線的位移、寬度和粗細。
D2D1_RECT_F rect = D2D1::RectF( 0, underline->offset, underline->width, underline->offset + underline->thickness );
接下來,使用ID2D1Factory::CreateRectangleGeometry方法和初始化的 D2D1_RECT_F結構,建立ID2D1RectangleGeometry物件。
ID2D1RectangleGeometry* pRectangleGeometry = NULL; hr = pD2DFactory_->CreateRectangleGeometry( &rect, &pRectangleGeometry );
如同字元執行,必須使用 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 ); }
最後,繪製已轉換幾何的外框,並使用 ID2D1RenderTarget::D rawGeometry 和 ID2D1RenderTarget::FillGeometry 方法,以及儲存為成員變數的 Direct2D 筆刷來填滿它。
// Draw the outline of the glyph run pRT_->DrawGeometry( pTransformedGeometry, pOutlineBrush_ ); // Fill in the glyph run pRT_->FillGeometry( pTransformedGeometry, pFillBrush_ );
現在您已完成繪圖,別忘了清除此方法中建立的物件。
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::D raw 方法轉譯自訂轉譯器,此方法會採用衍生自 IDWriteTextRenderer 的回呼介面作為引數,如下列程式碼所示。
// Draw the text layout using DirectWrite and the CustomTextRenderer class.
hr = pTextLayout_->Draw(
NULL,
pTextRenderer_, // Custom text renderer.
origin.x,
origin.y
);
IDWriteTextLayout::D raw方法會呼叫您提供的自訂轉譯器回呼方法。 DrawGlyphRun、DrawUnderline、DrawInlineObject和DrawStrikethrough方法會執行繪圖函式。