# 七、附录 d:`SimpleTextRenderer`代码列表 下面的代码示例是基于构建一个需要打印的应用程序而修改的 SimpleTextRenderer 类。这些代码大部分来自微软视窗 8 示例。我已经更改了格式,以更好地适应这本书的页面,但它的可读性远不如微软提供的原版。 simpletextrenderer . h ```cpp #pragma once #include "DirectXBase.h" #include 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 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 m_blackBrush; bool m_renderNeeded; // The main print control Microsoft::WRL::ComPtr 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(ceil(width * m _ dpi/96)), static_cast (天花板(高度* m_dpi / 96)),1,1, 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 预览曲面。 comptrdx GIS surface; DX::ThrowIfFailed(纹理。as(& dxgiSurface)); //为渲染预览表面创建新的 D2D 设备上下文。D2D //设备上下文是有状态的,因此唯一的设备上下文必须是 //用于每个线程。 comptrD2 dconte; 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); //创建绘制页面内容的表面位图。 comptrD2 dssurfacebitmap; 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 设备上下文是有状态的,因此唯一的设备上下文必须 //用于每个线程。 comptrD2 dconte; DX::throwifffailed( m _ d2d DEVICE-> CreateDeviceContext(d2d 1 _ DEVICE _ CONTEXT _ OPTIONS _ NONE,&d2dContext) ); ComPtr 打印命令列表; 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)); }