# 七、附录 d：`SimpleTextRenderer`代码列表

下面的代码示例是基于构建一个需要打印的应用程序而修改的 SimpleTextRenderer 类。这些代码大部分来自微软视窗 8 示例。我已经更改了格式，以更好地适应这本书的页面，但它的可读性远不如微软提供的原版。

simpletextrenderer . h

```cpp
    #pragma once
    #include "DirectXBase.h"
    #include <PrintPreview.h>
    enum class DrawTypes {    Rendering, Preview,  Printing  };

    // RAII (Resource Acquisition Is Initialization) class for manually
    // acquiring/releasing the D2D lock.
    class D2DFactoryLock {
    public:
    D2DFactoryLock(_In_ ID2D1Factory* d2dFactory) {
         DX::ThrowIfFailed(
              d2dFactory->QueryInterface(IID_PPV_ARGS(&m_d2dMultithread))
              );
         m_d2dMultithread->Enter();
         }
    ~D2DFactoryLock() {
         m_d2dMultithread->Leave();
         }
    private:
         Microsoft::WRL::ComPtr<ID2D1Multithread> m_d2dMultithread;
    };

    // Renders or prints drawings using Direct2D
    ref class SimpleTextRenderer sealed : public DirectXBase {
    public:
         SimpleTextRenderer();
         // DirectXBase methods.
         virtual void CreateDeviceIndependentResources() override;
         virtual void CreateDeviceResources() override;
         virtual void CreateWindowSizeDependentResources() override;
         virtual void Render() override;
         void Update(float timeTotal, float timeDelta);
    internal:
         // These two methods return immutable resources shared amongst contexts
         SimpleTextRenderer(
              _In_ D2D1_RECT_F targetBox,
              _In_ ID2D1DeviceContext* d2dContext,
              _In_ DrawTypes type,
              _In_ SimpleTextRenderer^ myParent
              );
        void UpdateTargetBox(_In_ D2D1_RECT_F& targetBox);
        void Draw(_In_ float scale);
         void CreatePrintControl(_In_  IPrintDocumentPackageTarget* docPackageTarget,
                    _In_  D2D1_PRINT_CONTROL_PROPERTIES* printControlProperties);
         HRESULT ClosePrintControl();

         void DrawPreviewSurface(_In_  float width, _In_  float height, _In_  float scale,
              _In_  D2D1_RECT_F contentBox, _In_  uint32 desiredJobPage,
              _In_  IPrintPreviewDxgiPackageTarget* previewTarget);
         void PrintPage(_In_ uint32 pageNumber, _In_ D2D1_RECT_F imageableArea,
              _In_ D2D1_SIZE_F pageSize, _In_opt_ IStream* pagePrintTicketStream);
    private:
         Microsoft::WRL::ComPtr<ID2D1SolidColorBrush> m_blackBrush;
         bool m_renderNeeded;
         // The main print control
         Microsoft::WRL::ComPtr<ID2D1PrintControl> m_d2dPrintControl;
        float m_margin;  // The margin size is in DIPs.
        D2D1_RECT_F m_targetBox; // Region to format for.
        DrawTypes m_type; // Record of context type, screen/preview/printing
    };

```

simpletextrenderer . cpp

```cpp
    #include "pch.h"
    #include "SimpleTextRenderer.h"

    using namespace D2D1;
    using namespace DirectX;
    using namespace Microsoft::WRL;
    using namespace Windows::Foundation;
    using namespace Windows::Foundation::Collections;
    using namespace Windows::UI::Core;
    SimpleTextRenderer::SimpleTextRenderer() :
         m_renderNeeded(true),
         m_type(DrawTypes::Rendering),  // By default the context is rendering to screen
         m_margin(96.0f)           // Default margin size
    {}

    SimpleTextRenderer::SimpleTextRenderer(_In_ D2D1_RECT_F targetBox,
         _In_ ID2D1DeviceContext* d2dContext, _In_ DrawTypes type,
         _In_ SimpleTextRenderer^ myParent) {
    m_margin = 96.0f;
    m_d2dContext = d2dContext;
    m_type = type;
    UpdateTargetBox(targetBox);
    DX::ThrowIfFailed(
         d2dContext->CreateSolidColorBrush(
         D2D1::ColorF(D2D1::ColorF::Black),
         &m_blackBrush));
    }

    void SimpleTextRenderer::CreateDeviceIndependentResources() {
         DirectXBase::CreateDeviceIndependentResources();
    }

    void SimpleTextRenderer::CreateDeviceResources() {
         DirectXBase::CreateDeviceResources();
         DX::ThrowIfFailed(
              m_d2dContext->CreateSolidColorBrush(
                    ColorF(ColorF::Black),
                    &m_blackBrush
                    )
              );
    }

    void SimpleTextRenderer::CreateWindowSizeDependentResources() {
         DirectXBase::CreateWindowSizeDependentResources();
         // Make the target box the whole screen
         D2D1_SIZE_F size = m_d2dContext->GetSize();   
         m_targetBox = D2D1::RectF(0, 0, size.width, size.height);
    }

    void SimpleTextRenderer::Update(float timeTotal, float timeDelta) {
         (void) timeTotal; // Unused parameter.
         (void) timeDelta; // Unused parameter.
    }

    void SimpleTextRenderer::Render() {
    m_d2dContext->BeginDraw();
    // Microsoft check that the current screen is not snapped here but we will
    // assume it is not.
    // Render page context.
    Draw(1.0f);
    // We ignore D2DERR_RECREATE_TARGET here. This error indicates that the device
    // is lost. It will be handled during the next call to Present.
    HRESULT hr = m_d2dContext->EndDraw();
    if (hr != D2DERR_RECREATE_TARGET) DX::ThrowIfFailed(hr);
    // We are accessing D3D resources directly in Present() without D2D's knowledge,
    // so we must manually acquire the D2D factory lock.
    //
    // Note: it's absolutely critical that the factory lock be released upon
    // exiting this function, or else the entire app will deadlock. This is
    // ensured via the following RAII class.
    D2DFactoryLock factoryLock(m_d2dFactory.Get());
    Present();
    }
    void SimpleTextRenderer::UpdateTargetBox(_In_ D2D1_RECT_F& targetBox) {
        m_targetBox = targetBox;
    }

      // Draws the scene to a rendering device context or a printing device context.
      void SimpleTextRenderer::Draw(_In_ float scale)

```

{

if(m _ type = = draw types::Rendering){//如果渲染到屏幕，则清除为矢车菊蓝色

m _ D2 dconte-> clear(D2 D1::colorf(D2 D1::colorf::cornflower))；}

else if(m _ type = = draw types::Preview){//打印时不清除

m _ D2 dconte-> clear(D2 D1::colorf(D2 D1::colorf::white))；}

//预览时我们使用比例矩阵来缩小图像。

//屏幕渲染或打印比例为 1.f。

m _ d2d context-> SetTransform(d2d 1::Matrix3x2F(1/scale，0，0，1/scale，0，0))；

//这是绘制图表的地方。下面是一个图案

//以彩色圆圈为例:

D2D1 _ ELLIPSE ell

for(float y = 0；y < 16y++){ 0

for(float x = 0；x < 16x++){ 0

ell = D2D1::椭圆(D2D1::Point2F(x * 50.0f，y * 50.0f)，100.0f，100.0 f)；

m _ black rush-> set color(D2 D1::colorf(

(x * 16.0f) / 256.0f，

(y * 16.0f) / 256.0f，

((x+y)* 8.0f)/256.0 f))；

m _ d2d context-> draw elliplex(ell，m _ blackBrush。get())；

}

}

}

HRESULT SimpleTextRenderer::ClosePrintControl(){ 0

return(m _ d2dPrintControl = = null ptr)？s _ OK:m _ d2d print control-> Close()；

}

void SimpleTextRenderer::CreatePrintControl(_ In _ iprintdockagetarget * docPackageTarget，_ In _ d2d 1 _ PRINT _ CONTROL _ PROPERTIES * printControlProperties){ 0

//显式释放现有的 D2D 打印控件。

m _ D2 dpprintcontrol = zero tr：

DX::throwifffailed(

m _ d2d device-> CreatePrintControl(m _ wic factory。Get()，

docpackage target print control properties，& m _ D2 dprincontrol)；

}

void SimpleTextRenderer::draw preview surface(_In_ float 宽度，_ In _ float 高度，

_In_ float scale，_In_ D2D1_RECT_F contentBox，_ In _ uint32 desiredJobPage，

_ in _ iprinpreviewdxgipackagetarget * preview target)

{

d2d factory lock factory lock(m _ d2d factory。get())；

cd3d 11 _ texture 2d _ desc texture desec(DXGI _ FORMAT _ b8g 8r 8 a 8 _ unrom，static _ cast<uint32>(ceil(width * m _ dpi/96))，</uint32>

static_cast <uint32>(天花板(高度* m_dpi / 96))，1，1，</uint32>

d3d 11 _ BIND _ RENDER _ TARGET | d3d 11 _ BIND _ SHADER _ RESOURCE)；

comptr〔t0〕纹理；

dx::throwiffailed(m _ d3d vice-> create texture 2d(& texture desc，zero tr，& texture))；

//创建给定大小的 DXGI 预览曲面。

comptr<idxgisurface>dx GIS surface；</idxgisurface>

DX::ThrowIfFailed(纹理。as<idxgisurface>(& dxgiSurface))；</idxgisurface>

//为渲染预览表面创建新的 D2D 设备上下文。D2D

//设备上下文是有状态的，因此唯一的设备上下文必须是

//用于每个线程。

comptr<id2d1devicecontext>D2 dconte；</id2d1devicecontext>

DX::ThrowIfFailed(m _ d2d device-> CreateDeviceContext(

d2d 1 _ DEVICE _ CONTEXT _ OPTIONS _ NONE，& d2d CONTEXT))；

//同时更新预览表面的 DPI。

d2dContext->SetDpi(m_dpi，m _ dpi)；

//建议使用屏幕 DPI，以便在打印预览中获得更好的保真度和性能。

D2 D1 _ bitmap _ properties 1 bitmap properties = D2 D1::bitmap properties 1(

d2d 1 _ 位图 _ 选项 _ 目标| D2D1 _ 位图 _ 选项 _ 无法 _ 绘制，

D2D1::像素格式(dxgi _ format _ b8g8 r8 a 8 _ unom、D2 D1 _ alpha _ mode _ preplied)；

//创建绘制页面内容的表面位图。

comptr<id2d1bitmap1>D2 dssurfacebitmap；</id2d1bitmap1>

DX::throwifffailed(

D2 dcontext-> createbitmapfromdxgissurface(dxgissurface)。Get()，

&bitmapProperties，& D2 dssurfacebitmap)；

D2 dcontext-> settarget(D2 dssurfacebitmap)。get())；

//创建并初始化页面渲染器上下文以进行预览。

simpletext enderer ^ preview text enders = ref new simpletext enders(content box，d2dContext.Get()、DrawTypes::Preview，this)；

D2 dcontext-> begin draw()；

//在预览图面上绘制页面内容。

preview text runs-> draw(缩放)：

//文档源处理 D2DERR _ RECREATETARGET，这里抛出就可以了。

dx::throwiffailed(D2 dcontext-> end raw())；

//必须通过用于创建 DXGI 表面的相同 DPI，才能正确打印

//预览。

DX::throwifffailed(

previewTarget->DrawPage(所需作业版本，dxgisurface)。Get()、m_dpi、m_dpi)

);

}

void SimpleTextRenderer::PrintPage(_ In _ uint 32 页码，

_ in _ D2 D1 _ rect _ f image table area，_In_ D2D1_SIZE_F pageSize，

_ In _ opt _ iStream * page printicket stream)

{

//创建一个新的 D2D 设备上下文来生成打印命令列表。

// D2D 设备上下文是有状态的，因此唯一的设备上下文必须

//用于每个线程。

comptr<id2d1devicecontext>D2 dconte；</id2d1devicecontext>

DX::throwifffailed(

m _ d2d DEVICE-> CreateDeviceContext(d2d 1 _ DEVICE _ CONTEXT _ OPTIONS _ NONE，&d2dContext)

);

ComPtr <id2d1commandlist>打印命令列表；</id2d1commandlist>

DX::throwifffailed(

d2dContext->CreateCommandList（&printCommandList）

);

d2dcontext->

//为打印创建并初始化页面渲染器上下文。

//在这种情况下，我们希望使用已经有的位图源

//嵌入其中的颜色上下文。因此，我们将空值传递给

//颜色上下文参数。

simpletext enderer ^ printpagerenderercontext = ref new simpletext enderer(imageablearea，d2dContext)。Get()，

DrawTypes::Printing，this)；

D2 dcontext-> begin draw()；

//在命令列表上绘制页面内容。

//下面 1.0f 表示打印内容不缩放。

//“drawing types::Printing”下面表示是打印案例。

printpagerenderercontext-> draw(1.0f)；

//文档源处理 D2DERR _ RECREATETARGET，这里抛出就可以了。

dx::throwiffailed(D2 dcontext-> end raw())；

DX::ThrowIfFailed(printCommandList-> Close())；

DX::ThrowIfFailed(m _ d2dPrintControl-> AddPage(printCommandList。Get()，pageSize，

pageprinticket stream))；

}