DirectWrite allows inserting objects in a block of text, e.g. images, as shown in the picture.
Clik here to view.

MFC Support for DirectWrite (Part 4) – Inline Images
Let’s see how can be done!
Implement IDWriteInlineObject interface methods to insert inline images
Once we have created a CD2DTextLayout object, remains the following to do:
- Define a class for implementing IDWriteInlineObject interface, e.g. CInlineImage. We can derive it from IDWriteInlineObject then override and implement IDWriteInlineObject and IUnknown methods. However, if we already are using MFC, it’s a little bit handier to derive from CCmdTarget, then use MFC’s interface maps DECLARE_INTERFACE_MAP, BEGIN_INTERFACE_PART and so on.
class CInlineImage : public CCmdTarget { public: CInlineImage(); virtual ~CInlineImage(); HRESULT Create(CHwndRenderTarget* pRenderTarget, UINT nResID, LPCTSTR pszResType); HRESULT Create(CHwndRenderTarget* pRenderTarget, LPCTSTR pszFileName); BOOL IsValid(); operator IDWriteInlineObject*(); public: DECLARE_INTERFACE_MAP() BEGIN_INTERFACE_PART(InlineImage, IDWriteInlineObject) STDMETHOD(Draw)(void*, IDWriteTextRenderer*, FLOAT, FLOAT, BOOL, BOOL, IUnknown*); STDMETHOD(GetMetrics)(DWRITE_INLINE_OBJECT_METRICS*); STDMETHOD(GetOverhangMetrics)(DWRITE_OVERHANG_METRICS*); STDMETHOD(GetBreakConditions)(DWRITE_BREAK_CONDITION*, DWRITE_BREAK_CONDITION*); CHwndRenderTarget* m_pRenderTarget; CD2DBitmap* m_pBitmap; END_INTERFACE_PART(InlineImage) };
Detailed implementation can be found in the demo application attached to this article. Here is listed just an implementation example of overridden IDWriteInlineObject::Draw.
STDMETHODIMP CInlineImage::XInlineImage::Draw(void* clientDrawingContext, IDWriteTextRenderer* textRenderer, FLOAT fOriginX, FLOAT fOriginY, BOOL bIsSideways, BOOL bIsRightToLeft, IUnknown* clientDrawingEffect) { METHOD_PROLOGUE(CInlineImage, InlineImage); ASSERT_VALID(m_pRenderTarget); ASSERT_VALID(m_pBitmap); if(m_pRenderTarget->IsValid() && m_pBitmap->IsValid()) { CD2DSizeF sizeBitmap = m_pBitmap->GetSize(); m_pRenderTarget->DrawBitmap(m_pBitmap, CD2DRectF(fOriginX, fOriginY, fOriginX + sizeBitmap.width, fOriginY + sizeBitmap.height)); } return S_OK; }
- Create and initialize a CInlineImage object.
class CDirectWriteDemoView : public CView { // ... CInlineImage m_inlineImage; // ... };
int CDirectWriteDemoView::OnCreate(LPCREATESTRUCT lpCreateStruct) { // ... // Enable D2D support for this window EnableD2DSupport(); CHwndRenderTarget* pRenderTarget = GetRenderTarget(); // create inline image objects HRESULT hr = m_inlineImageRings.Create(pRenderTarget, IDB_RINGS, T("PNG")); ASSERT(SUCCEEDED(hr)); // ... }
- Pass the CInlineImage object to IDWriteTextLayout::SetInlineObject before drawing the text layout.
LRESULT CDirectWriteDemoView::OnDraw2D(WPARAM wParam, LPARAM lParam) { CHwndRenderTarget* pRenderTarget = (CHwndRenderTarget*)lParam; // ... // init the inline objects _InitInlineObjects(pRenderTarget, spTextLayout); // Draw the text in the render target. pRenderTarget->DrawTextLayout(CD2DPointF(), // upper-left corner of the text spTextLayout.get(), // text layout object &CD2DSolidColorBrush // brush used for text (pRenderTarget, D2D1::ColorF(D2D1::ColorF::DarkRed))); }
void CDirectWriteDemoView::_InitInlineObjects(CHwndRenderTarget* pRenderTarget, const std::shared_ptr<CD2DTextLayout> spTextLayout) { // ... CDirectWriteDemoDoc* pDoc = _GetDocument(); DWRITE_TEXT_RANGE textRange; if(pDoc->GetTextRange(_T("[IMAGE:RINGS]"), textRange) && m_inlineImageRings.IsValid()) { spTextLayout->Get()->SetInlineObject(m_inlineImageRings, textRange); } // ... }
Demo application
Download: MFC Support for DirectWrite Demo (Part 4).zip (13)
Notes
- CInlineImage class implementation is intentionally left as simple as possible, for learning purpose. Of course, it can be improved, for example, by scaling images to fit the text height.
- Pictures used in the demo application are taken from http://www.icondrawer.com/gift-icons.php
Resources and related articles
- Codexpert: Direc2D and DirectWrite topics
- MSDN: How to Add Inline Objects to a Text Layout
- MSDN: IDWriteTextLayout::SetInlineObject method
- MSDN: IDWriteInlineObject interface
- Codeproject: An introduction to MFC’s COM Interface Macros
- MSDN TN038: MFC/OLE IUnknown Implementation