// This method takes an attributed string and outputs a GlyphLayout data
    // structure that contains the glyph number and location of each inidividual glyph
    void getGlyphLayout (const AttributedString& text, GlyphLayout& glyphLayout)
    {
        // For now we are creating the DirectWrite Factory, System Font Collection,
        // D2D Factory and GDI Render target every time we layout text.
        // This is inefficient and we may be loading and unloading libraries each layout.
        // These four things should be created once at application startup and be destroyed
        // when the application exits. I'm not sure where the best place to do this so
        // for now I will just use the inefficient method.

        IDWriteFactory* dwFactory = nullptr;
        HRESULT hr = DWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory),
            reinterpret_cast<IUnknown**>(&dwFactory));

        IDWriteFontCollection* dwFontCollection = nullptr;
        hr = dwFactory->GetSystemFontCollection (&dwFontCollection);

        // To add color to text, we need to create a D2D render target
        // Since we are not actually rendering to a D2D context we create a temporary GDI render target
        ID2D1Factory *d2dFactory = nullptr;
        hr = D2D1CreateFactory (D2D1_FACTORY_TYPE_SINGLE_THREADED, &d2dFactory);
        D2D1_RENDER_TARGET_PROPERTIES d2dRTProp = D2D1::RenderTargetProperties(
            D2D1_RENDER_TARGET_TYPE_SOFTWARE,
            D2D1::PixelFormat(
            DXGI_FORMAT_B8G8R8A8_UNORM,
            D2D1_ALPHA_MODE_IGNORE),
            0,
            0,
            D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE,
            D2D1_FEATURE_LEVEL_DEFAULT
            );
        ID2D1DCRenderTarget* d2dDCRT = nullptr;
        hr = d2dFactory->CreateDCRenderTarget (&d2dRTProp, &d2dDCRT);

        // Initially we set the paragraph up with a default font and then apply the attributed string ranges later
        Font defaultFont;
        const float defaultFontHeightToEmSizeFactor = getFontHeightToEmSizeFactor (defaultFont, *dwFontCollection);
        // We should probably be detecting the locale instead of hard coding it to en-us
        String localeName("en-us");

        // We multiply the font height by the size factor so we layout text at the correct size
        IDWriteTextFormat* dwTextFormat = nullptr;
        hr = dwFactory->CreateTextFormat (
            defaultFont.getTypefaceName().toWideCharPointer(),
            dwFontCollection,
            DWRITE_FONT_WEIGHT_REGULAR,
            DWRITE_FONT_STYLE_NORMAL,
            DWRITE_FONT_STRETCH_NORMAL,
            defaultFont.getHeight() * defaultFontHeightToEmSizeFactor,
            localeName.toWideCharPointer(),
            &dwTextFormat
            );

        // Paragraph Attributes
        // Set Paragraph Alignment
        if (text.getTextAlignment() == AttributedString::left)
            dwTextFormat->SetTextAlignment (DWRITE_TEXT_ALIGNMENT_LEADING);
        if (text.getTextAlignment() == AttributedString::right)
            dwTextFormat->SetTextAlignment (DWRITE_TEXT_ALIGNMENT_TRAILING);
        if (text.getTextAlignment() == AttributedString::center)
            dwTextFormat->SetTextAlignment (DWRITE_TEXT_ALIGNMENT_CENTER);
        // DirectWrite cannot justify text, default to left alignment
        if (text.getTextAlignment() == AttributedString::justified)
            dwTextFormat->SetTextAlignment (DWRITE_TEXT_ALIGNMENT_LEADING);
        // Set Word Wrap
        if (text.getWordWrap() == AttributedString::none)
            dwTextFormat->SetWordWrapping (DWRITE_WORD_WRAPPING_NO_WRAP);
        if (text.getWordWrap() == AttributedString::byWord)
            dwTextFormat->SetWordWrapping (DWRITE_WORD_WRAPPING_WRAP);
        // DirectWrite does not support wrapping by character, default to wrapping by word
        if (text.getWordWrap() == AttributedString::byChar)
            dwTextFormat->SetWordWrapping (DWRITE_WORD_WRAPPING_WRAP);
        // DirectWrite does not automatically set reading direction
        // This must be set correctly and manually when using RTL Scripts (Hebrew, Arabic)
        if (text.getReadingDirection() == AttributedString::rightToLeft)
            dwTextFormat->SetReadingDirection (DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);

        IDWriteTextLayout* dwTextLayout = nullptr;
        hr = dwFactory->CreateTextLayout (
            text.getText().toWideCharPointer(),
            text.getText().length(),
            dwTextFormat,
            glyphLayout.getWidth(),
            glyphLayout.getHeight(),
            &dwTextLayout
            );

        // Character Attributes
        int numCharacterAttributes = text.getCharAttributesSize();
        for (int i = 0; i < numCharacterAttributes; ++i)
        {
            Attr* attr = text.getCharAttribute (i);
            // Character Range Error Checking
            if (attr->range.getStart() > text.getText().length()) continue;
            if (attr->range.getEnd() > text.getText().length()) attr->range.setEnd (text.getText().length());
            if (attr->attribute == Attr::font)
            {
                AttrFont* attrFont = static_cast<AttrFont*>(attr);
                DWRITE_TEXT_RANGE dwRange;
                dwRange.startPosition = attrFont->range.getStart();
                dwRange.length = attrFont->range.getLength();
                dwTextLayout->SetFontFamilyName (attrFont->font.getTypefaceName().toWideCharPointer(), dwRange);
                // We multiply the font height by the size factor so we layout text at the correct size
                const float fontHeightToEmSizeFactor = getFontHeightToEmSizeFactor (attrFont->font, *dwFontCollection);
                dwTextLayout->SetFontSize (attrFont->font.getHeight() * fontHeightToEmSizeFactor, dwRange);
            }
            if (attr->attribute == Attr::foregroundColour)
            {
                AttrColour* attrColour = static_cast<AttrColour*>(attr);
                DWRITE_TEXT_RANGE dwRange;
                dwRange.startPosition = attrColour->range.getStart();
                dwRange.length = attrColour->range.getLength();
                ID2D1SolidColorBrush* d2dBrush = nullptr;
                d2dDCRT->CreateSolidColorBrush (D2D1::ColorF (D2D1::ColorF(attrColour->colour.getFloatRed(),
                    attrColour->colour.getFloatGreen(), attrColour->colour.getFloatBlue(),
                    attrColour->colour.getFloatAlpha())), &d2dBrush);
                // We need to call SetDrawingEffect with a legimate brush to get DirectWrite to break text based on colours
                dwTextLayout->SetDrawingEffect (d2dBrush, dwRange);
                safeRelease (&d2dBrush);
            }
        }

        UINT32 actualLineCount = 0;
        hr = dwTextLayout->GetLineMetrics (nullptr, 0, &actualLineCount);
        // Preallocate GlyphLayout Line Array
        glyphLayout.setNumLines (actualLineCount);
        HeapBlock <DWRITE_LINE_METRICS> dwLineMetrics (actualLineCount);
        hr = dwTextLayout->GetLineMetrics (dwLineMetrics, actualLineCount, &actualLineCount);
        int location = 0;
        // Create GlyphLine structures for each line in the layout
        for (UINT32 i = 0; i < actualLineCount; ++i)
        {
            // Get string range
            Range<int> lineStringRange (location, (int) location + dwLineMetrics[i].length);
            location = dwLineMetrics[i].length;
            GlyphLine* glyphLine = new GlyphLine();
            glyphLine->setStringRange (lineStringRange);
            glyphLayout.addGlyphLine (glyphLine);
        }

        // To copy glyph data from DirectWrite into our own data structures we must create our
        // own CustomTextRenderer. Instead of passing the draw method an actual graphics context,
        // we pass it the GlyphLayout object that needs to be filled with glyphs.
        CustomDirectWriteTextRenderer* textRenderer = nullptr;
        textRenderer = new CustomDirectWriteTextRenderer();
        hr = dwTextLayout->Draw (
            &glyphLayout,
            textRenderer,
            glyphLayout.getX(),
            glyphLayout.getY()
            );

        safeRelease (&textRenderer);
        safeRelease (&dwTextLayout);
        safeRelease (&dwTextFormat);
        safeRelease (&d2dDCRT);
        safeRelease (&d2dFactory);
        safeRelease (&dwFontCollection);
        safeRelease (&dwFactory);
    }
void nf_free(nf_font_t font)
{
	if(font)
	{
		IDWriteTextFormat * format = (IDWriteTextFormat*)font;
		format->Release();
	}

	nf_ctx_free();
}
Beispiel #3
0
int CDirectWriteRenderer::GetFitCharCount(LPCWSTR pText, int Length, int Width, CDirectWriteFont &Font)
{
	if (pText == nullptr || Length == 0)
		return 0;
	if (m_pRenderTarget == nullptr)
		return 0;

	int FitCharCount = 0;

	IDWriteFactory *pFactory = m_System.GetDWriteFactory();

	if (pFactory != nullptr) {
		IDWriteTextFormat *pTextFormat = Font.GetTextFormat();

		if (pTextFormat != nullptr) {
			IDWriteTextLayout *pTextLayout;

			pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING);
			pTextFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
			if (Length < 0)
				Length = ::lstrlenW(pText);
			HRESULT hr = pFactory->CreateTextLayout(
				pText,
				Length,
				pTextFormat,
				static_cast<float>(Width),
				m_pRenderTarget->GetSize().height,
				&pTextLayout);
			if (SUCCEEDED(hr)) {
				Util::CTempBuffer<DWRITE_CLUSTER_METRICS, 256> ClusterMetrics(Length);
				UINT32 ClusterCount;

				hr = pTextLayout->GetClusterMetrics(ClusterMetrics.GetBuffer(), Length, &ClusterCount);
				if (SUCCEEDED(hr)) {
					float Pos = 0.0f;

					for (UINT32 i = 0; i < ClusterCount; i++) {
						Pos += ClusterMetrics[i].width;
						if (static_cast<int>(std::ceil(Pos)) > Width)
							break;
						FitCharCount += ClusterMetrics[i].length;
					}
				}

				pTextLayout->Release();
			}

			pTextFormat->Release();
		}

		pFactory->Release();
	}

	return FitCharCount;
}
Beispiel #4
0
bool CDirectWriteRenderer::GetTextMetrics(
	LPCWSTR pText, int Length, CDirectWriteFont &Font, TextMetrics *pMetrics)
{
	if (pText == nullptr || pMetrics == nullptr)
		return false;
	if (m_pRenderTarget == nullptr)
		return false;

	HRESULT hr = E_UNEXPECTED;
	IDWriteFactory *pFactory = m_System.GetDWriteFactory();

	if (pFactory != nullptr) {
		IDWriteTextFormat *pTextFormat = Font.GetTextFormat();

		if (pTextFormat != nullptr) {
			D2D1_SIZE_F Size;
			IDWriteTextLayout *pTextLayout;

			pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING);
			pTextFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
			if (Length < 0)
				Length = ::lstrlenW(pText);
			Size = m_pRenderTarget->GetSize();
			hr = pFactory->CreateTextLayout(
				pText,
				Length,
				pTextFormat,
				Size.width,
				Size.height,
				&pTextLayout);
			if (SUCCEEDED(hr)) {
				DWRITE_TEXT_METRICS Metrics;

				hr = pTextLayout->GetMetrics(&Metrics);
				if (SUCCEEDED(hr)) {
					pMetrics->Width = Metrics.width;
					pMetrics->WidthIncludingTrailingWhitespace = Metrics.widthIncludingTrailingWhitespace;
					pMetrics->Height = Metrics.height;
				}

				pTextLayout->Release();
			}

			pTextFormat->Release();
		}

		pFactory->Release();
	}

	return SUCCEEDED(hr);
}
Beispiel #5
0
void Graphics::GDrawText(int x, int y, wchar_t* text, wchar_t* fontName, int fontSize, DWRITE_FONT_STYLE style, D2D1_COLOR_F color)
{
	ID2D1SolidColorBrush* brush;
	IDWriteTextFormat* textFormat;
	UINT32 textLength;
	
	textLength = (UINT32)wcslen(text);

	writeFactory->CreateTextFormat(fontName, NULL, DWRITE_FONT_WEIGHT_REGULAR, style, DWRITE_FONT_STRETCH_NORMAL, fontSize, L"en-us", &textFormat);
	textFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING);
	
	renderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::White), &brush);
	renderTarget->DrawTextW(text, textLength, textFormat, D2D1::RectF(x, y, fontSize * textLength, y + fontSize), brush);

	SafeRelease(&brush);
	SafeRelease(&textFormat);
}
Beispiel #6
0
    void
DWriteContext::SetFont(const LOGFONTW &logFont)
{
    SafeRelease(&mTextFormat);
    mLastHFont = NULL;

    HRESULT hr = SetLOGFONT(logFont, 0.f);

    if (SUCCEEDED(hr))
	hr = mTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING);

    if (SUCCEEDED(hr))
	hr = mTextFormat->SetParagraphAlignment(
		DWRITE_PARAGRAPH_ALIGNMENT_CENTER);

    if (SUCCEEDED(hr))
	hr = mTextFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
}
Beispiel #7
0
bool CDirectWriteRenderer::GetFontMetrics(CDirectWriteFont &Font, FontMetrics *pMetrics)
{
	if (pMetrics == nullptr)
		return false;
	if (m_pRenderTarget == nullptr)
		return false;

	HRESULT hr = E_UNEXPECTED;
	IDWriteTextFormat *pTextFormat = Font.GetTextFormat();

	if (pTextFormat != nullptr) {
		IDWriteFontCollection *pFontCollection;

		hr = pTextFormat->GetFontCollection(&pFontCollection);
		if (SUCCEEDED(hr)) {
			WCHAR szName[256];

			hr = pTextFormat->GetFontFamilyName(szName, lengthof(szName));
			if (SUCCEEDED(hr)) {
				UINT32 Index;
				BOOL fExists;

				hr = pFontCollection->FindFamilyName(szName, &Index, &fExists);
				if (SUCCEEDED(hr)) {
					IDWriteFontFamily *pFontFamily;

					hr = pFontCollection->GetFontFamily(Index, &pFontFamily);
					if (SUCCEEDED(hr)) {
						IDWriteFont *pFont;

						hr = pFontFamily->GetFirstMatchingFont(
							pTextFormat->GetFontWeight(),
							pTextFormat->GetFontStretch(),
							pTextFormat->GetFontStyle(),
							&pFont);
						if (SUCCEEDED(hr)) {
							DWRITE_FONT_METRICS Metrics;

							pFont->GetMetrics(&Metrics);
							const float Ratio = pTextFormat->GetFontSize() / static_cast<float>(Metrics.designUnitsPerEm);
							pMetrics->Ascent = Metrics.ascent * Ratio;
							pMetrics->Descent = Metrics.descent * Ratio;
							pMetrics->LineGap = Metrics.lineGap * Ratio;

							pFont->Release();
						}

						pFontFamily->Release();
					}
				}
			}
		}

		pFontCollection->Release();
	}

	return SUCCEEDED(hr);
}
Beispiel #8
0
// 创建字体格式
IDWriteTextFormat*		TextFormatCache::CreateTextFormat(const TextFormat& font){
#ifdef _DEBUG
	TextFormatCache::Map::iterator itr = s_mapTextCache.find(font);
	if (itr != s_mapTextCache.end()){
		_cwprintf(L"目标字体已存在.\n");
		return itr->second;
	}
	if (!s_ppDWriteFactory){
		_cwprintf(L"s_ppDWriteFactory未初始化.\n");
		return NULL;
	}
	if (!(*s_ppDWriteFactory)){

		_cwprintf(L"DWriteFactory未初始化.\n");
		return NULL;
	}
#endif
	IDWriteTextFormat* pTF;
	
	(*s_ppDWriteFactory)->CreateTextFormat(
		font.font_name.c_str(),
		s_pCollection,
		DWRITE_FONT_WEIGHT_NORMAL,
		DWRITE_FONT_STYLE_NORMAL,
		DWRITE_FONT_STRETCH_NORMAL,
		font.font_size * (96.0f / 72.f),
		L"", //locale
		&pTF
		);
	if (pTF){
		pTF->SetTextAlignment(font.font_alignment);
	}
#ifdef _DEBUG
	else
		_cwprintf(L"IDWriteTextFormat 创建失败.\n");
#endif
	s_mapTextCache.insert(Map::value_type(font, pTF));
	return pTF;
}
    void setTextFormatProperties (const AttributedString& text, IDWriteTextFormat& format)
    {
        DWRITE_TEXT_ALIGNMENT alignment = DWRITE_TEXT_ALIGNMENT_LEADING;
        DWRITE_WORD_WRAPPING wrapType = DWRITE_WORD_WRAPPING_WRAP;

        switch (text.getJustification().getOnlyHorizontalFlags())
        {
            case Justification::left:                   break;
            case Justification::right:                  alignment = DWRITE_TEXT_ALIGNMENT_TRAILING; break;
            case Justification::horizontallyCentred:    alignment = DWRITE_TEXT_ALIGNMENT_CENTER; break;
            case Justification::horizontallyJustified:  break; // DirectWrite cannot justify text, default to left alignment
            default:                                    jassertfalse; break; // Illegal justification flags
        }

        switch (text.getWordWrap())
        {
            case AttributedString::none:      wrapType = DWRITE_WORD_WRAPPING_NO_WRAP; break;
            case AttributedString::byWord:    break;
            case AttributedString::byChar:    break; // DirectWrite doesn't support wrapping by character, default to word-wrap
            default:                          jassertfalse; break; // Illegal flags!
        }

        // DirectWrite does not automatically set reading direction
        // This must be set correctly and manually when using RTL Scripts (Hebrew, Arabic)
        if (text.getReadingDirection() == AttributedString::rightToLeft)
        {
            format.SetReadingDirection (DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);

            switch (text.getJustification().getOnlyHorizontalFlags())
            {
                case Justification::left:      alignment = DWRITE_TEXT_ALIGNMENT_TRAILING; break;
                case Justification::right:     alignment = DWRITE_TEXT_ALIGNMENT_LEADING;  break;
                default: break;
            }
        }

        format.SetTextAlignment (alignment);
        format.SetWordWrapping (wrapType);
    }
	IDWriteTextFormat* createTextFormat(IDWriteFactory1* writeFactory, const char* fontName, bool alignmentCenterX, bool alignmentCenterY)
	{
		IDWriteTextFormat* textFormat;

		// Create a DirectWrite text format object.
		DX::ThrowIfFailed(
			writeFactory->CreateTextFormat(
			Utils::convertStringToWString(fontName).c_str(),//Gabriola
			NULL,
			DWRITE_FONT_WEIGHT_REGULAR,
			DWRITE_FONT_STYLE_NORMAL,
			DWRITE_FONT_STRETCH_NORMAL,
			64.f,
			L"en-US", // Locale
			&textFormat
			)
			);

		// Center the text horizontally and vertically.
		textFormat->SetTextAlignment(alignmentCenterX ? DWRITE_TEXT_ALIGNMENT_CENTER : DWRITE_TEXT_ALIGNMENT_LEADING);
		textFormat->SetParagraphAlignment(alignmentCenterY ? DWRITE_PARAGRAPH_ALIGNMENT_CENTER : DWRITE_PARAGRAPH_ALIGNMENT_NEAR);

		return textFormat;
	}
Beispiel #11
0
bool CDirectWriteRenderer::DrawText(
	LPCWSTR pText, int Length, const RECT &Rect,
	CDirectWriteFont &Font, CDirectWriteBrush &Brush, unsigned int Flags)
{
	if (pText == nullptr)
		return false;
	if (m_pRenderTarget == nullptr)
		return false;

	bool fOK = false;

	IDWriteTextFormat *pTextFormat = Font.GetTextFormat();

	if (pTextFormat != nullptr) {
		ID2D1Brush *pBrush = Brush.GetBrush();

		if (pBrush != nullptr) {
			pTextFormat->SetTextAlignment(
				(Flags & DRAW_TEXT_ALIGN_HORZ_CENTER) != 0 ?
					DWRITE_TEXT_ALIGNMENT_CENTER :
				(Flags & DRAW_TEXT_ALIGN_RIGHT) != 0 ?
					DWRITE_TEXT_ALIGNMENT_TRAILING :
				((Flags & DRAW_TEXT_ALIGN_JUSTIFIED) != 0
					&& Util::OS::IsWindows8OrLater()) ?
					DWRITE_TEXT_ALIGNMENT_JUSTIFIED :
					DWRITE_TEXT_ALIGNMENT_LEADING);
			pTextFormat->SetParagraphAlignment(
				(Flags & DRAW_TEXT_ALIGN_VERT_CENTER) != 0 ?
					DWRITE_PARAGRAPH_ALIGNMENT_CENTER :
				(Flags & DRAW_TEXT_ALIGN_BOTTOM) != 0 ?
					DWRITE_PARAGRAPH_ALIGNMENT_FAR :
					DWRITE_PARAGRAPH_ALIGNMENT_NEAR);
			pTextFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
			DWRITE_TRIMMING Trimming = {DWRITE_TRIMMING_GRANULARITY_NONE, 0, 0};
			pTextFormat->SetTrimming(&Trimming, nullptr);

			m_pRenderTarget->DrawText(
				pText,
				Length >= 0 ? Length : ::lstrlenW(pText),
				pTextFormat,
				D2DRectF(Rect),
				pBrush);
			fOK = true;

			pBrush->Release();
		}

		pTextFormat->Release();
	}

	return fOK;
}
HRESULT SaveToImageFile()
{
    HRESULT hr = S_OK;


    //
    // Create Factories
    //

    IWICImagingFactory *pWICFactory = NULL;
    ID2D1Factory *pD2DFactory = NULL;
    IDWriteFactory *pDWriteFactory = NULL;
    IWICBitmap *pWICBitmap = NULL;
    ID2D1RenderTarget *pRT = NULL;
    IDWriteTextFormat *pTextFormat = NULL;
    ID2D1PathGeometry *pPathGeometry = NULL;
    ID2D1GeometrySink *pSink = NULL;
    ID2D1GradientStopCollection *pGradientStops = NULL;
    ID2D1LinearGradientBrush *pLGBrush = NULL;
    ID2D1SolidColorBrush *pBlackBrush = NULL;
    IWICBitmapEncoder *pEncoder = NULL;
    IWICBitmapFrameEncode *pFrameEncode = NULL;
    IWICStream *pStream = NULL;

    hr = CoCreateInstance(
        CLSID_WICImagingFactory,
        NULL,
        CLSCTX_INPROC_SERVER,
        IID_IWICImagingFactory,
        reinterpret_cast<void **>(&pWICFactory)
        );

    if (SUCCEEDED(hr))
    {
        hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &pD2DFactory);
    }

    if (SUCCEEDED(hr))
    {
        hr = DWriteCreateFactory(
            DWRITE_FACTORY_TYPE_SHARED,
            __uuidof(pDWriteFactory),
            reinterpret_cast<IUnknown **>(&pDWriteFactory)
            );
    }

    //
    // Create IWICBitmap and RT
    //

    static const UINT sc_bitmapWidth = 640;
    static const UINT sc_bitmapHeight = 480;
    if (SUCCEEDED(hr))
    {
        hr = pWICFactory->CreateBitmap(
            sc_bitmapWidth,
            sc_bitmapHeight,
            GUID_WICPixelFormat32bppBGR,
            WICBitmapCacheOnLoad,
            &pWICBitmap
            );
    }

    if (SUCCEEDED(hr))
    {
        hr = pD2DFactory->CreateWicBitmapRenderTarget(
            pWICBitmap,
            D2D1::RenderTargetProperties(),
            &pRT
            );
    }

    if (SUCCEEDED(hr))
    {
        //
        // Create text format
        //

        static const WCHAR sc_fontName[] = L"Calibri";
        static const FLOAT sc_fontSize = 50;

        hr = pDWriteFactory->CreateTextFormat(
            sc_fontName,
            NULL,
            DWRITE_FONT_WEIGHT_NORMAL,
            DWRITE_FONT_STYLE_NORMAL,
            DWRITE_FONT_STRETCH_NORMAL,
            sc_fontSize,
            L"", //locale
            &pTextFormat
            );
    }
    if (SUCCEEDED(hr))
    {
        pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER);

        pTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER);

        //
        // Create a path geometry representing an hour glass
        //

        hr = pD2DFactory->CreatePathGeometry(&pPathGeometry);
    }
    if (SUCCEEDED(hr))
    {
        hr = pPathGeometry->Open(&pSink);
    }
    if (SUCCEEDED(hr))
    {
        pSink->SetFillMode(D2D1_FILL_MODE_ALTERNATE);

        pSink->BeginFigure(
            D2D1::Point2F(0, 0),
            D2D1_FIGURE_BEGIN_FILLED
            );

        pSink->AddLine(D2D1::Point2F(200, 0));

        pSink->AddBezier(
            D2D1::BezierSegment(
                D2D1::Point2F(150, 50),
                D2D1::Point2F(150, 150),
                D2D1::Point2F(200, 200))
            );

        pSink->AddLine(D2D1::Point2F(0, 200));

        pSink->AddBezier(
            D2D1::BezierSegment(
                D2D1::Point2F(50, 150),
                D2D1::Point2F(50, 50),
                D2D1::Point2F(0, 0))
            );

        pSink->EndFigure(D2D1_FIGURE_END_CLOSED);

        hr = pSink->Close();
    }
    if (SUCCEEDED(hr))
    {
        //
        // Create a linear-gradient brush
        //

        static const D2D1_GRADIENT_STOP stops[] =
        {
            {   0.f,  { 0.f, 1.f, 1.f, 1.f }  },
            {   1.f,  { 0.f, 0.f, 1.f, 1.f }  },
        };

        hr = pRT->CreateGradientStopCollection(
            stops,
            ARRAYSIZE(stops),
            &pGradientStops
            );
    }
    if (SUCCEEDED(hr))
    {
        hr = pRT->CreateLinearGradientBrush(
            D2D1::LinearGradientBrushProperties(
                D2D1::Point2F(100, 0),
                D2D1::Point2F(100, 200)),
            D2D1::BrushProperties(),
            pGradientStops,
            &pLGBrush
            );
    }
    if (SUCCEEDED(hr))
    {
        hr = pRT->CreateSolidColorBrush(
            D2D1::ColorF(D2D1::ColorF::Black),
            &pBlackBrush
            );
    }
    if (SUCCEEDED(hr))
    {
        //
        // Render into the bitmap
        //

        pRT->BeginDraw();

        pRT->Clear(D2D1::ColorF(D2D1::ColorF::White));

        D2D1_SIZE_F rtSize = pRT->GetSize();

        // Set the world transform to a 45 degree rotation at the center of the render target
        // and write "Hello, World".
        pRT->SetTransform(
            D2D1::Matrix3x2F::Rotation(
                45,
                D2D1::Point2F(
                    rtSize.width / 2,
                    rtSize.height / 2))
                );

        static const WCHAR sc_helloWorld[] = L"Hello, World!";
        pRT->DrawText(
            sc_helloWorld,
            ARRAYSIZE(sc_helloWorld) - 1,
            pTextFormat,
            D2D1::RectF(0, 0, rtSize.width, rtSize.height),
            pBlackBrush);

        //
        // Reset back to the identity transform
        //
        pRT->SetTransform(D2D1::Matrix3x2F::Translation(0, rtSize.height - 200));

        pRT->FillGeometry(pPathGeometry, pLGBrush);

        pRT->SetTransform(D2D1::Matrix3x2F::Translation(rtSize.width - 200, 0));

        pRT->FillGeometry(pPathGeometry, pLGBrush);

        hr = pRT->EndDraw();
    }
    if (SUCCEEDED(hr))
    {

        //
        // Save image to file
        //

        hr = pWICFactory->CreateStream(&pStream);
    }

    WICPixelFormatGUID format = GUID_WICPixelFormatDontCare;
    if (SUCCEEDED(hr))
    {
        static const WCHAR filename[] = L"output.png";
        hr = pStream->InitializeFromFilename(filename, GENERIC_WRITE);
    }
    if (SUCCEEDED(hr))
    {
        hr = pWICFactory->CreateEncoder(GUID_ContainerFormatPng, NULL, &pEncoder);
    }
    if (SUCCEEDED(hr))
    {
        hr = pEncoder->Initialize(pStream, WICBitmapEncoderNoCache);
    }
    if (SUCCEEDED(hr))
    {
        hr = pEncoder->CreateNewFrame(&pFrameEncode, NULL);
    }
    if (SUCCEEDED(hr))
    {
        hr = pFrameEncode->Initialize(NULL);
    }
    if (SUCCEEDED(hr))
    {
        hr = pFrameEncode->SetSize(sc_bitmapWidth, sc_bitmapHeight);
    }
    if (SUCCEEDED(hr))
    {
        hr = pFrameEncode->SetPixelFormat(&format);
    }
    if (SUCCEEDED(hr))
    {
        hr = pFrameEncode->WriteSource(pWICBitmap, NULL);
    }
    if (SUCCEEDED(hr))
    {
        hr = pFrameEncode->Commit();
    }
    if (SUCCEEDED(hr))
    {
        hr = pEncoder->Commit();
    }

    SafeRelease(&pWICFactory);
    SafeRelease(&pD2DFactory);
    SafeRelease(&pDWriteFactory);
    SafeRelease(&pWICBitmap);
    SafeRelease(&pRT);
    SafeRelease(&pTextFormat);
    SafeRelease(&pPathGeometry);
    SafeRelease(&pSink);
    SafeRelease(&pGradientStops);
    SafeRelease(&pLGBrush);
    SafeRelease(&pBlackBrush);
    SafeRelease(&pEncoder);
    SafeRelease(&pFrameEncode);
    SafeRelease(&pStream);

    return hr;
}
void ImageWindow::OnPaint()
{
	Mutex::Locker locker( frontBufferMutex  );

	// Nothing to do
	if( frames.IsEmpty() )
		return;

	if( !frames.PeekFront(0)->ready )
		return;

	Ptr<Frame> currentFrame = frames.PopFront();

	Ptr<Frame> nextFrame = NULL;

	if( !frames.IsEmpty() )
		nextFrame = frames.PeekFront(0);
	
	while( nextFrame && nextFrame->ready )
	{
		// Free up the current frame since it's been removed from the deque
		currentFrame = frames.PopFront();

		if( frames.IsEmpty() )
			break;

		nextFrame = frames.PeekFront(0);
	}

	if( currentFrame->imageData )
		greyBitmap->CopyFromMemory( NULL, currentFrame->imageData, currentFrame->width );

	if( currentFrame->colorImageData )
		colorBitmap->CopyFromMemory( NULL, currentFrame->colorImageData, currentFrame->colorPitch );

	pRT->BeginDraw();

	pRT->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED); 

	pRT->Clear( D2D1::ColorF(D2D1::ColorF::Black) );

	// This will mirror our image
	D2D1_MATRIX_3X2_F m;
	m._11 = -1; m._12 = 0;
	m._21 = 0; m._22 = 1;
	m._31 = 0; m._32 = 0;
	pRT->SetTransform( m );

	ID2D1SolidColorBrush* whiteBrush;

	pRT->CreateSolidColorBrush( D2D1::ColorF(D2D1::ColorF::White, 1.0f), &whiteBrush );

	if( currentFrame->imageData )
	{
		pRT->FillOpacityMask( greyBitmap, whiteBrush, 
			D2D1_OPACITY_MASK_CONTENT_TEXT_NATURAL, 
			D2D1::RectF( -(FLOAT)resolution.width, 0.0f, (FLOAT)0.0f, (FLOAT)resolution.height ), 
			//D2D1::RectF( 0.0f, 0.0f, (FLOAT)0.0f, (FLOAT)resolution.height ), 
			D2D1::RectF( 0.0f, 0.0f, (FLOAT)resolution.width, (FLOAT)resolution.height ) );
	}
	else if( currentFrame->colorImageData )
	{
		pRT->DrawBitmap( colorBitmap,
			D2D1::RectF( -(FLOAT)resolution.width, 0.0f, (FLOAT)0.0f, (FLOAT)resolution.height ) );

	}

	pRT->SetTransform(D2D1::Matrix3x2F::Identity());

	whiteBrush->Release();

	Array<CirclePlot>::Iterator it;

	for( it = currentFrame->plots.Begin(); it != currentFrame->plots.End(); ++it )
	{
		ID2D1SolidColorBrush* aBrush;

		pRT->CreateSolidColorBrush( D2D1::ColorF( it->r, it->g, it->b), &aBrush );

		D2D1_ELLIPSE ellipse;
		ellipse.point.x = it->x;
		ellipse.point.y = it->y;
		ellipse.radiusX = it->radius;
		ellipse.radiusY = it->radius;

		if( it->fill )
			pRT->FillEllipse( &ellipse, aBrush );
		else
			pRT->DrawEllipse( &ellipse, aBrush );

		aBrush->Release();
	}

	static const WCHAR msc_fontName[] = L"Verdana";
	static const FLOAT msc_fontSize = 20;

	IDWriteTextFormat* textFormat = NULL;

	// Create a DirectWrite text format object.
	pDWriteFactory->CreateTextFormat(
		msc_fontName,
		NULL,
		DWRITE_FONT_WEIGHT_NORMAL,
		DWRITE_FONT_STYLE_NORMAL,
		DWRITE_FONT_STRETCH_NORMAL,
		msc_fontSize,
		L"", //locale
		&textFormat
		);

	D2D1_SIZE_F renderTargetSize = pRT->GetSize();

	Array<TextPlot>::Iterator textIt;
	for( textIt = currentFrame->textLines.Begin(); textIt != currentFrame->textLines.End(); ++textIt )
	{
		ID2D1SolidColorBrush* aBrush;

		pRT->CreateSolidColorBrush( D2D1::ColorF( textIt->r, textIt->g, textIt->b), &aBrush );

		WCHAR* tmpString = (WCHAR*)calloc( textIt->text.GetLength(),  sizeof( WCHAR ) );
		for( unsigned i = 0; i < textIt->text.GetLength(); ++i )
		{
			tmpString[i] = (WCHAR)textIt->text.GetCharAt( i );
		}
					
		pRT->DrawText( tmpString, (UINT32)textIt->text.GetLength(), textFormat,
			D2D1::RectF(textIt->x, textIt->y, renderTargetSize.width, renderTargetSize.height), aBrush );

		free( tmpString );

		aBrush->Release();
	}

	if( textFormat )
		textFormat->Release();

	pRT->EndDraw();

	pRT->Flush();
}
Beispiel #14
0
static void fontDialogDrawSampleText(struct fontDialog *f, ID2D1RenderTarget *rt)
{
	D2D1_COLOR_F color;
	D2D1_BRUSH_PROPERTIES props;
	ID2D1SolidColorBrush *black;
	IDWriteFont *font;
	IDWriteLocalizedStrings *sampleStrings;
	BOOL exists;
	WCHAR *sample;
	WCHAR *family;
	IDWriteTextFormat *format;
	D2D1_RECT_F rect;
	HRESULT hr;

	color.r = 0.0;
	color.g = 0.0;
	color.b = 0.0;
	color.a = 1.0;
	ZeroMemory(&props, sizeof (D2D1_BRUSH_PROPERTIES));
	props.opacity = 1.0;
	// identity matrix
	props.transform._11 = 1;
	props.transform._22 = 1;
	hr = rt->CreateSolidColorBrush(
		&color,
		&props,
		&black);
	if (hr != S_OK)
		logHRESULT(L"error creating solid brush", hr);

	font = (IDWriteFont *) cbGetItemData(f->styleCombobox, (WPARAM) f->curStyle);
	hr = font->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_SAMPLE_TEXT, &sampleStrings, &exists);
	if (hr != S_OK)
		exists = FALSE;
	if (exists) {
		sample = fontCollectionCorrectString(f->fc, sampleStrings);
		sampleStrings->Release();
	} else
		sample = L"The quick brown fox jumps over the lazy dog.";

	// DirectWrite doesn't allow creating a text format from a font; we need to get this ourselves
	family = cbGetItemText(f->familyCombobox, f->curFamily);
	hr = dwfactory->CreateTextFormat(family,
		NULL,
		font->GetWeight(),
		font->GetStyle(),
		font->GetStretch(),
		// typographic points are 1/72 inch; this parameter is 1/96 inch
		// fortunately Microsoft does this too, in https://msdn.microsoft.com/en-us/library/windows/desktop/dd371554%28v=vs.85%29.aspx
		f->curSize * (96.0 / 72.0),
		// see http://stackoverflow.com/questions/28397971/idwritefactorycreatetextformat-failing and https://msdn.microsoft.com/en-us/library/windows/desktop/dd368203.aspx
		// TODO use the current locale again?
		L"",
		&format);
	if (hr != S_OK)
		logHRESULT(L"error creating IDWriteTextFormat", hr);
	uiFree(family);

	rect.left = 0;
	rect.top = 0;
	rect.right = realGetSize(rt).width;
	rect.bottom = realGetSize(rt).height;
	rt->DrawText(sample, wcslen(sample),
		format,
		&rect,
		black,
		// TODO really?
		D2D1_DRAW_TEXT_OPTIONS_NONE,
		DWRITE_MEASURING_MODE_NATURAL);

	format->Release();
	if (exists)
		uiFree(sample);
	black->Release();
}
Beispiel #15
0
HRESULT SaveToImageFile(PlotData **data
						, unsigned int imageWidth, unsigned int imageHeight
						, float rangeX, float rangeY
						, float leftMargin, float bottomMargin
						, float xTick, float yTick)
{
    HRESULT hr = S_OK;
    //
    // Create Factories
    //

    IWICImagingFactory *pWICFactory = NULL;
    ID2D1Factory *pD2DFactory = NULL;
    IDWriteFactory *pDWriteFactory = NULL;
    IWICBitmap *pWICBitmap = NULL;
    ID2D1RenderTarget *pRT = NULL;
    IDWriteTextFormat *pTextFormat = NULL;
    ID2D1SolidColorBrush *pSolidBrush = NULL;
    IWICBitmapEncoder *pEncoder = NULL;
    IWICBitmapFrameEncode *pFrameEncode = NULL;
    IWICStream *pStream = NULL;

    hr = CoCreateInstance(
        CLSID_WICImagingFactory,
        NULL,
        CLSCTX_INPROC_SERVER,
        IID_IWICImagingFactory,
        reinterpret_cast<void **>(&pWICFactory)
        );

    if (SUCCEEDED(hr))
    {
        hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &pD2DFactory);
    }

    if (SUCCEEDED(hr))
    {
        hr = DWriteCreateFactory(
            DWRITE_FACTORY_TYPE_SHARED,
            __uuidof(pDWriteFactory),
            reinterpret_cast<IUnknown **>(&pDWriteFactory)
            );
    }

    //
    // Create IWICBitmap and RT
    //

    if (SUCCEEDED(hr))
    {
        hr = pWICFactory->CreateBitmap(
			imageWidth,
			imageHeight,
            GUID_WICPixelFormat32bppBGR,
            WICBitmapCacheOnLoad,
            &pWICBitmap
            );
    }

    if (SUCCEEDED(hr))
    {
        hr = pD2DFactory->CreateWicBitmapRenderTarget(
            pWICBitmap,
            D2D1::RenderTargetProperties(),
            &pRT
            );
    }

    if (SUCCEEDED(hr))
    {
        //
        // Create text format
        //

        static const WCHAR sc_fontName[] = L"Arial";
        static const FLOAT sc_fontSize = 20;

        hr = pDWriteFactory->CreateTextFormat(
            sc_fontName,
            NULL,
            DWRITE_FONT_WEIGHT_NORMAL,
            DWRITE_FONT_STYLE_NORMAL,
            DWRITE_FONT_STRETCH_NORMAL,
            sc_fontSize,
            L"", //locale
            &pTextFormat
            );
    }
    if (SUCCEEDED(hr))
    {
        pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER);

        pTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER);

        //
        // Create a path geometry representing an hour glass
        //

    }
    if (SUCCEEDED(hr))
    {
        hr = pRT->CreateSolidColorBrush(
            D2D1::ColorF(D2D1::ColorF::Black),
            &pSolidBrush
            );
    }
    if (SUCCEEDED(hr))
    {
        //
        // Render into the bitmap
        //

        pRT->BeginDraw();

        pRT->Clear(D2D1::ColorF(D2D1::ColorF::White));

        D2D1_SIZE_F rtSize = pRT->GetSize();


        //static const WCHAR sc_helloWorld[] = L"Hello, World!";
        //pRT->DrawText(
        //    sc_helloWorld,
        //    ARRAYSIZE(sc_helloWorld) - 1,
        //    pTextFormat,
        //    D2D1::RectF(0, 0, rtSize.width, rtSize.height),
        //    pBlackBrush);

		float scaleX = (rtSize.width - leftMargin) / rangeX;
		float scaleY = (rtSize.height - bottomMargin) / rangeY;
        //
        // Reset back to the identity transform
        //
		pRT->DrawLine(D2D1::Point2F(leftMargin, 0.0f), D2D1::Point2F(leftMargin, rtSize.height - bottomMargin), pSolidBrush);
		pRT->DrawLine(D2D1::Point2F(leftMargin, rtSize.height - bottomMargin), D2D1::Point2F(rtSize.width, rtSize.height - bottomMargin), pSolidBrush);

		pSolidBrush->SetColor(D2D1::ColorF(D2D1::ColorF::LightGray, 0.4f));
		size_t countTicks = rangeY / yTick;
		for(size_t tick = 1; tick <= countTicks; ++tick)
		{
			float y = rtSize.height - bottomMargin - static_cast<float>(tick) * yTick * scaleY;
			pRT->DrawLine(D2D1::Point2F(leftMargin - 3.0f, y), D2D1::Point2F(rtSize.width, y), pSolidBrush);
		}
		countTicks = rangeX / xTick;
		for(size_t tick = 1; tick <= countTicks; ++tick)
		{
			float x = leftMargin + static_cast<float>(tick) * xTick * scaleX;
			pRT->DrawLine(D2D1::Point2F(x, 0.0f), D2D1::Point2F(x, rtSize.height - bottomMargin + 3.0f), pSolidBrush);
		}

		//D2D1_MATRIX_3X2_F rotation = D2D1::Matrix3x2F::Rotation(-90.0f);
		D2D1_MATRIX_3X2_F translation = D2D1::Matrix3x2F::Translation(leftMargin, rtSize.height - bottomMargin);
		//D2D1_MATRIX_3X2_F scale = D2D1::Matrix3x2F::Scale(D2D1::SizeF(600.0f, 1.0f));
		pRT->SetTransform(translation);
		GraphData(data, pD2DFactory, pRT, pSolidBrush, scaleX, scaleY );

        hr = pRT->EndDraw();
    }
    if (SUCCEEDED(hr))
    {

        //
        // Save image to file
        //

        hr = pWICFactory->CreateStream(&pStream);
    }

    WICPixelFormatGUID format = GUID_WICPixelFormatDontCare;
    if (SUCCEEDED(hr))
    {
        static const WCHAR filename[] = L"output.png";
        hr = pStream->InitializeFromFilename(filename, GENERIC_WRITE);
    }
    if (SUCCEEDED(hr))
    {
        hr = pWICFactory->CreateEncoder(GUID_ContainerFormatPng, NULL, &pEncoder);
    }
    if (SUCCEEDED(hr))
    {
        hr = pEncoder->Initialize(pStream, WICBitmapEncoderNoCache);
    }
    if (SUCCEEDED(hr))
    {
        hr = pEncoder->CreateNewFrame(&pFrameEncode, NULL);
    }
    if (SUCCEEDED(hr))
    {
        hr = pFrameEncode->Initialize(NULL);
    }
    if (SUCCEEDED(hr))
    {
        hr = pFrameEncode->SetSize(imageWidth, imageHeight);
    }
    if (SUCCEEDED(hr))
    {
        hr = pFrameEncode->SetPixelFormat(&format);
    }
    if (SUCCEEDED(hr))
    {
        hr = pFrameEncode->WriteSource(pWICBitmap, NULL);
    }
    if (SUCCEEDED(hr))
    {
        hr = pFrameEncode->Commit();
    }
    if (SUCCEEDED(hr))
    {
        hr = pEncoder->Commit();
    }

    SafeRelease(&pWICFactory);
    SafeRelease(&pD2DFactory);
    SafeRelease(&pDWriteFactory);
    SafeRelease(&pWICBitmap);
    SafeRelease(&pRT);
    SafeRelease(&pTextFormat);
    SafeRelease(&pSolidBrush);
    SafeRelease(&pEncoder);
    SafeRelease(&pFrameEncode);
    SafeRelease(&pStream);

    return hr;
}
Beispiel #16
0
int _tmain(int argc, _TCHAR* argv[])
{
    HRESULT hr = S_OK;

    // Create a Direct2D factory.
    CHECKHR(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &g_pD2DFactory));

    // Create a DirectWrite factory.
    CHECKHR(DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory),
        reinterpret_cast<IUnknown**>(&g_pDWriteFactory)));

    // Create a WIC factory
    IWICImagingFactory* pWICFactory = NULL;

    CHECKHR(CoInitialize(nullptr));
    CHECKHR(CoCreateInstance(CLSID_WICImagingFactory1, nullptr, CLSCTX_INPROC_SERVER,
        IID_IWICImagingFactory, (LPVOID*)&pWICFactory));

    // Create an IWICBitmap and RT
    IWICBitmap* pWICBitmap = NULL;
    static const UINT sc_bitmapWidth = 640;
    static const UINT sc_bitmapHeight = 480;

    CHECKHR(pWICFactory->CreateBitmap(sc_bitmapWidth, sc_bitmapHeight, GUID_WICPixelFormat32bppBGR,
        WICBitmapCacheOnLoad,
        &pWICBitmap));

    // Set the render target type to D2D1_RENDER_TARGET_TYPE_DEFAULT to use software rendering.
    CHECKHR(g_pD2DFactory->CreateWicBitmapRenderTarget(
        pWICBitmap, D2D1::RenderTargetProperties(), &g_pRenderTarget));

    // Create text format and a path geometry representing an hour glass. 
    IDWriteTextFormat*  pTextFormat = NULL;
    static const WCHAR sc_fontName[] = L"Calibri";
    static const FLOAT sc_fontSize = 50;

    CHECKHR(g_pDWriteFactory->CreateTextFormat(
        sc_fontName,
        NULL,
        DWRITE_FONT_WEIGHT_NORMAL,
        DWRITE_FONT_STYLE_NORMAL,
        DWRITE_FONT_STRETCH_NORMAL,
        sc_fontSize,
        L"", //locale
        &pTextFormat
        ));

    CHECKHR(pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER));
    CHECKHR(pTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER));

    // Create a path geometry
    ID2D1PathGeometry* pPathGeometry = NULL;
    ID2D1GeometrySink* pSink = NULL;

    CHECKHR(g_pD2DFactory->CreatePathGeometry(&pPathGeometry));
    CHECKHR(pPathGeometry->Open(&pSink));

    pSink->SetFillMode(D2D1_FILL_MODE_ALTERNATE);

    pSink->BeginFigure(
        D2D1::Point2F(0, 0),
        D2D1_FIGURE_BEGIN_FILLED
        );

    pSink->AddLine(D2D1::Point2F(200, 0));

    pSink->AddBezier(
        D2D1::BezierSegment(
        D2D1::Point2F(150, 50),
        D2D1::Point2F(150, 150),
        D2D1::Point2F(200, 200))
        );

    pSink->AddLine(D2D1::Point2F(0, 200));

    pSink->AddBezier(
        D2D1::BezierSegment(
        D2D1::Point2F(50, 150),
        D2D1::Point2F(50, 50),
        D2D1::Point2F(0, 0))
        );

    pSink->EndFigure(D2D1_FIGURE_END_CLOSED);

    CHECKHR(pSink->Close());

    // Create GradientStopCollection
    ID2D1GradientStopCollection *pGradientStops = NULL;
    static const D2D1_GRADIENT_STOP stops[] =
    {
        { 0.f, { 0.f, 1.f, 1.f, 1.f } },
        { 1.f, { 0.f, 0.f, 1.f, 1.f } },
    };

    CHECKHR(g_pRenderTarget->CreateGradientStopCollection(
        stops,
        ARRAYSIZE(stops),
        &pGradientStops
        ));

    ID2D1LinearGradientBrush* pLGBrush = NULL;
    ID2D1SolidColorBrush* pBlackBrush = NULL;

    CHECKHR(g_pRenderTarget->CreateLinearGradientBrush(
        D2D1::LinearGradientBrushProperties(
        D2D1::Point2F(100, 0),
        D2D1::Point2F(100, 200)),
        D2D1::BrushProperties(),
        pGradientStops,
        &pLGBrush
        ));

    CHECKHR(g_pRenderTarget->CreateSolidColorBrush(
        D2D1::ColorF(D2D1::ColorF::Black),
        &pBlackBrush
        ));

    // Render into the bitmap.
    g_pRenderTarget->BeginDraw();
    g_pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White));
    D2D1_SIZE_F rtSize = g_pRenderTarget->GetSize();

    // Set the world transform to a 45 degree rotation at the center of the render target
    // and write "Hello, World".
    g_pRenderTarget->SetTransform(
        D2D1::Matrix3x2F::Rotation(
        45,
        D2D1::Point2F(
        rtSize.width / 2,
        rtSize.height / 2))
        );

    static const WCHAR sc_helloWorld[] = L"Hello, World!";
    g_pRenderTarget->DrawText(
        sc_helloWorld,
        ARRAYSIZE(sc_helloWorld) - 1,
        pTextFormat,
        D2D1::RectF(0, 0, rtSize.width, rtSize.height),
        pBlackBrush);

    // Reset back to the identity transform.
    g_pRenderTarget->SetTransform(D2D1::Matrix3x2F::Translation(0, rtSize.height - 200));
    g_pRenderTarget->FillGeometry(pPathGeometry, pLGBrush);
    g_pRenderTarget->SetTransform(D2D1::Matrix3x2F::Translation(rtSize.width - 200, 0));
    g_pRenderTarget->FillGeometry(pPathGeometry, pLGBrush);
    CHECKHR(g_pRenderTarget->EndDraw());

    // Save the image to a file.
    IWICStream* pStream = NULL;
    CHECKHR(pWICFactory->CreateStream(&pStream));

    // Use InitializeFromFilename to write to a file. If there is need to write inside the memory, use InitializeFromMemory. 
    static const WCHAR filename[] = L"output.png";
    CHECKHR(pStream->InitializeFromFilename(filename, GENERIC_WRITE));

    IWICBitmapEncoder* pEncoder = NULL;
    CHECKHR(pWICFactory->CreateEncoder(GUID_ContainerFormatPng, NULL, &pEncoder));
    CHECKHR(pEncoder->Initialize(pStream, WICBitmapEncoderNoCache));

    IWICBitmapFrameEncode* pFrameEncode = NULL;
    CHECKHR(pEncoder->CreateNewFrame(&pFrameEncode, NULL));

    // Use IWICBitmapFrameEncode to encode the bitmap into the picture format you want.
    CHECKHR(pFrameEncode->Initialize(NULL));
    CHECKHR(pFrameEncode->SetSize(sc_bitmapWidth, sc_bitmapHeight));

    WICPixelFormatGUID format = GUID_WICPixelFormatDontCare;
    CHECKHR(pFrameEncode->SetPixelFormat(&format));
    CHECKHR(pFrameEncode->WriteSource(pWICBitmap, NULL));
    CHECKHR(pFrameEncode->Commit());
    CHECKHR(pEncoder->Commit());

    return 0;
}