草庐IT

c++ - 不能重复使用画笔绘制文本和矩形

coder 2024-02-22 原文

简介及相关信息:

我正在尝试学习使用 XPS Document API 进行打印.

为了简单起见,我决定绘制一个矩形,并在其下方绘制一些文本。

通过 official examples 之后我能够实现我的目标。

问题:

基本上,我已将上述链接提供的 2 个代码示例串联起来。现在想把代码打磨一下,主要是用单画笔画矩形和文字。

重写代码后,出现如下错误:

First-chance exception at 0x7555D3CF in XPS printing.exe: Microsoft C++ exception: SplException::THResultException at memory location 0x002CEF9C.

If there is a handler for this exception, the program may be safely continued.

商会:

下面是我重写的函数。我已经用适当的注释标记了崩溃点。

void XPS_TEST()
{
    IXpsOMObjectFactory *xpsFactory;

    HRESULT hr = S_OK;

    // Init COM for this thread if it hasn't 
    //  been initialized, yet.
    hr = CoInitializeEx(0, COINIT_MULTITHREADED);

    hr = CoCreateInstance(
        __uuidof(XpsOMObjectFactory),
        NULL,
        CLSCTX_INPROC_SERVER,
        __uuidof(IXpsOMObjectFactory),
        reinterpret_cast<LPVOID*>(&xpsFactory));

    if (SUCCEEDED(hr))
    {
        // Declare the variables used in this section.
        IOpcPartUri                   *opcPartUri = NULL;
        IXpsOMPackage                 *xpsPackage = NULL;
        IXpsOMDocumentSequence        *xpsFDS = NULL;
        IXpsOMDocumentCollection      *fixedDocuments = NULL;
        IXpsOMDocument                *xpsFD = NULL;
        IXpsOMPage                    *xpsPage = NULL;
        IXpsOMPageReferenceCollection *pageRefs = NULL;
        IXpsOMPageReference           *xpsPageRef = NULL;

        // test size of the document
        XPS_SIZE pageSize = { 200, 200 };

        // Create the package.
        hr = xpsFactory->CreatePackage(&xpsPackage);

        // Create the URI for the fixed document sequence part and then  
        //  create the fixed document sequence
        hr = xpsFactory->CreatePartUri(
            L"/FixedDocumentSequence.fdseq", &opcPartUri);
        hr = xpsFactory->CreateDocumentSequence(opcPartUri, &xpsFDS);
        // Release this URI to reuse the interface pointer.
        if (NULL != opcPartUri) { opcPartUri->Release(); opcPartUri = NULL; }

        // Create the URI for the document part and then create the document.
        hr = xpsFactory->CreatePartUri(
            L"/Documents/1/FixedDocument.fdoc", &opcPartUri);
        hr = xpsFactory->CreateDocument(opcPartUri, &xpsFD);
        // Release this URI to reuse the interface pointer.
        if (NULL != opcPartUri) { opcPartUri->Release(); opcPartUri = NULL; }

        // Create a blank page.
        hr = xpsFactory->CreatePartUri(
            L"/Documents/1/Pages/1.fpage", &opcPartUri);
        hr = xpsFactory->CreatePage(
            &pageSize,                  // Page size
            L"en-US",                   // Page language
            opcPartUri,                 // Page part name
            &xpsPage);
        // Release this URI to reuse the interface pointer.
        if (NULL != opcPartUri) { opcPartUri->Release(); opcPartUri = NULL; }

        // Create a page reference for the page.
        hr = xpsFactory->CreatePageReference(&pageSize, &xpsPageRef);

        // Add the fixed document sequence to the package.
        hr = xpsPackage->SetDocumentSequence(xpsFDS);

        // Get the document collection of the fixed document sequence
        //  and then add the document to the collection.
        hr = xpsFDS->GetDocuments(&fixedDocuments);
        hr = fixedDocuments->Append(xpsFD);

        // Get the page reference collection from the document
        //  and add the page reference and blank page.
        hr = xpsFD->GetPageReferences(&pageRefs);
        hr = pageRefs->Append(xpsPageRef);
        hr = xpsPageRef->SetPage(xpsPage);

        //======================== draw rectangle ====================//

        XPS_COLOR             xpsColor;
        IXpsOMSolidColorBrush *xpsFillBrush = NULL;
        // the brush I want to reuse !!
        IXpsOMSolidColorBrush *xpsStrokeBrush = NULL;

        // Set the fill brush color to RED.
        xpsColor.colorType = XPS_COLOR_TYPE_SRGB;
        xpsColor.value.sRGB.alpha = 0xFF;
        xpsColor.value.sRGB.red = 0xFF;
        xpsColor.value.sRGB.green = 0x00;
        xpsColor.value.sRGB.blue = 0x00;

        // Use the object factory to create the brush.
        hr = xpsFactory->CreateSolidColorBrush(
            &xpsColor,
            NULL,          // color profile resource
            &xpsFillBrush);
        // The color profile resource parameter is NULL because
        //  this color type does not use a color profile resource.

        // Set the stroke brush color to BLACK.
        xpsColor.colorType = XPS_COLOR_TYPE_SRGB;
        xpsColor.value.sRGB.alpha = 0xFF;
        xpsColor.value.sRGB.red = 0x00;
        xpsColor.value.sRGB.green = 0x00;
        xpsColor.value.sRGB.blue = 0x00;

        // Use the object factory to create the brush.
        hr = xpsFactory->CreateSolidColorBrush(
            &xpsColor,
            NULL, // This color type does not use a color profile resource.
            &xpsStrokeBrush);

        // test rectangle
        XPS_RECT                            rect = { 0, 0, 200, 20 };
        IXpsOMGeometryFigure                *rectFigure;
        IXpsOMGeometry                      *imageRectGeometry;
        IXpsOMGeometryFigureCollection      *geomFigureCollection;

        // Define the start point and create an empty figure.
        XPS_POINT                           origin = { rect.x, rect.y };
        hr = xpsFactory->CreateGeometryFigure(&origin, &rectFigure);
        // Define the segments of the geometry figure.
        //  First, define the type of each segment.
        XPS_SEGMENT_TYPE segmentTypes[3] = 
        {
            XPS_SEGMENT_TYPE_LINE,  // each segment is a straight line
            XPS_SEGMENT_TYPE_LINE,
            XPS_SEGMENT_TYPE_LINE
        };

        // Define the x and y coordinates of each corner of the figure
        //  the start point has already been defined so only the 
        //  remaining three corners need to be defined.
        FLOAT segmentData[6] = 
        {
            rect.x, (rect.y + rect.height),
            (rect.x + rect.width), (rect.y + rect.height),
            (rect.x + rect.width), rect.y
        };

        // Describe if the segments are stroked (that is if the segment lines
        //  should be drawn as a line).
        BOOL segmentStrokes[3] = 
        {
            TRUE, TRUE, TRUE // Yes, draw each of the segment lines.
        };

        // Add the segment data to the figure.
        hr = rectFigure->SetSegments(
            3,
            6,
            segmentTypes,
            segmentData,
            segmentStrokes);

        // Set the closed and filled properties of the figure.
        hr = rectFigure->SetIsClosed(TRUE);
        hr = rectFigure->SetIsFilled(TRUE);

        // Create the geometry object.
        hr = xpsFactory->CreateGeometry(&imageRectGeometry);

        // Get a pointer to the figure collection interface of the geometry...
        hr = imageRectGeometry->GetFigures(&geomFigureCollection);

        // ...and then add the figure created above to this geometry.
        hr = geomFigureCollection->Append(rectFigure);
        // If not needed for anything else, release the rectangle figure.
        rectFigure->Release();

        // when done adding figures, release the figure collection. 
        geomFigureCollection->Release();

        IXpsOMPath                *rectPath = NULL;
        IXpsOMVisualCollection    *pageVisuals = NULL;

        // Create the new path object.
        hr = xpsFactory->CreatePath(&rectPath);

        // Add the geometry to the path.
        //  imageRectGeometry is initialized outside of this example.
        hr = rectPath->SetGeometryLocal(imageRectGeometry);

        // Set the short description of the path to provide
        //  a textual description of the object for accessibility.
        hr = rectPath->SetAccessibilityShortDescription(L"Red Rectangle");

        // Set the fill and stroke brushes to use the brushes 
        //  created in the first section.
        hr = rectPath->SetFillBrushLocal(xpsFillBrush);
        hr = rectPath->SetStrokeBrushLocal(xpsStrokeBrush);

        // Get the visual collection of this page and add this path to it.
        hr = xpsPage->GetVisuals(&pageVisuals);
        hr = pageVisuals->Append(rectPath);

        // If not needed for anything else, release the rectangle path.
        rectPath->Release();

        // When finished with the brushes, release the interface pointers.
        if (NULL != xpsFillBrush) xpsFillBrush->Release();
        //******************** I have commented out below code, ****************//
        //******************** because I plan to use the brush to draw text ****//
        //if (NULL != xpsStrokeBrush) xpsStrokeBrush->Release();
        // When done with the geometry interface, release it.
        imageRectGeometry->Release();

        //========================= draw text =====================//
        GUID                          fontNameGuid;
        WCHAR                         guidString[128] = { 0 };
        WCHAR                         uriString[256] = { 0 };

        IStream                       *fontStream = NULL;
        IOpcPartUri                   *fontUri = NULL;
        IXpsOMFontResource            *fontResource = NULL;

        // Create font stream. 
        hr = xpsFactory->CreateReadOnlyStreamOnFile(
            // I have hardcoded Arial here, just for testing
            L"C:\\Windows\\Fonts\\Arial.ttf",
            &fontStream); 

        // Create new obfuscated part name for this resource using a GUID.
        hr = CoCreateGuid(&fontNameGuid);
        hr = StringFromGUID2(
            fontNameGuid,
            guidString,
            ARRAYSIZE(guidString));

        // Create a URI string for this font resource that will place 
        //  the font part in the /Resources/Fonts folder of the package.
        wcscpy_s(uriString, ARRAYSIZE(uriString), L"/Resources/Fonts/");

        // Create the part name using the GUID string as the name and 
        //  ".odttf" as the extension GUID string start and ends with 
        //  curly braces so they are removed.
        wcsncat_s(uriString, ARRAYSIZE(uriString),
            guidString + 1, wcslen(guidString) - 2);
        wcscat_s(uriString, ARRAYSIZE(uriString), L".odttf");

        // Create the font URI interface.
        hr = xpsFactory->CreatePartUri(
            uriString,
            &fontUri);
        // Create the font resource.
        hr = xpsFactory->CreateFontResource(
            fontStream,
            XPS_FONT_EMBEDDING_OBFUSCATED,
            fontUri,
            FALSE,     // isObfSourceStream
            &fontResource);
        if (NULL != fontUri) fontUri->Release();

        LPCWSTR unicodeString = L"Test string";

        // move test string below our rectangle
        origin.y += 30.0f;

        FLOAT                   fontEmSize = 7.56f;
        IXpsOMGlyphsEditor      *glyphsEditor = NULL;
        IXpsOMGlyphs            *xpsGlyphs = NULL;

        // Create a new Glyphs object and set its properties.
        hr = xpsFactory->CreateGlyphs(fontResource, &xpsGlyphs);
        hr = xpsGlyphs->SetOrigin(&origin);
        hr = xpsGlyphs->SetFontRenderingEmSize(fontEmSize);
        //*************** I GET A CRASH BELOW !!!! ***************//
        hr = xpsGlyphs->SetFillBrushLocal(xpsStrokeBrush); // <<--- 

        // Some properties are inter-dependent so they
        //    must be changed by using a GlyphsEditor.
        hr = xpsGlyphs->GetGlyphsEditor(&glyphsEditor);
        hr = glyphsEditor->SetUnicodeString(unicodeString);
        hr = glyphsEditor->ApplyEdits();

        // Add the new Glyphs object to the page
        hr = pageVisuals->Append(xpsGlyphs);

        // Release interface pointers.
        if (NULL != xpsGlyphs) xpsGlyphs->Release();
        if (NULL != glyphsEditor) glyphsEditor->Release();
        if (NULL != pageVisuals) pageVisuals->Release();
        //******************** Releasing the brush here *******//
        if (NULL != xpsStrokeBrush) xpsStrokeBrush->Release();

        //========================= write to file ====================//
        hr = xpsPackage->WriteToFile(
            L"C:\\Users\\Smiljkovic\\Desktop\\xpsTest.xps",
            NULL,                    // LPSECURITY_ATTRIBUTES
            FILE_ATTRIBUTE_NORMAL,
            FALSE);                  // Optimize Markup Size
        //========================== cleanup ==================//

        // Release interface pointer
        if (NULL != xpsPage) xpsPage->Release();
        if (NULL != pageRefs) pageRefs->Release();
        if (NULL != fixedDocuments) fixedDocuments->Release();
        if (NULL != xpsPageRef) xpsPageRef->Release();
        if (NULL != xpsFD) xpsFD->Release();
        if (NULL != xpsFDS) xpsFDS->Release();
        if (NULL != xpsPackage) xpsPackage->Release();

        xpsFactory->Release();
    }

    // Uninitialize COM when finished
    CoUninitialize();
}

问题:

如何使用同一个画笔(上例中的 xpsStrokeBrush)来绘制文本和矩形轮廓?

最佳答案

根据 SetStrokeBrushLocal documentation :

After you call SetStrokeBrushLocal, the stroke brush lookup key is released and GetStrokeBrushLookup returns a NULL pointer in the lookup parameter.

您可以在画笔上使用Clone,然后再使用它。

但是,如果您打算重复使用画笔,请使用CreateDictionarySetDictionaryLocal,然后Append您的画笔;这将使您可以使用 SetFillBrushLookup

关于c++ - 不能重复使用画笔绘制文本和矩形,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33979012/

有关c++ - 不能重复使用画笔绘制文本和矩形的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  3. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  4. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  5. ruby - 在 Ruby 中使用匿名模块 - 2

    假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

  6. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  7. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  8. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  9. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  10. ruby - 在 64 位 Snow Leopard 上使用 rvm、postgres 9.0、ruby 1.9.2-p136 安装 pg gem 时出现问题 - 2

    我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po

随机推荐