Нельзя повторно использовать кисть для рисования как текста, так и прямоугольника.

ВВЕДЕНИЕ И СООТВЕТСТВУЮЩАЯ ИНФОРМАЦИЯ:

Я пытаюсь научиться печатать с API документа XPS.

Для простого начала я решил нарисовать прямоугольник и немного текста под ним.

После прохождения официальные примеры Я смог достичь своей цели.

ПРОБЛЕМА:

По сути, я объединил 2 примера кода, приведенных по ссылке выше. Теперь я хотел отшлифовать код, в основном, используя одну кисть для рисования как прямоугольника, так и текста.

Переписав код, я получаю следующую ошибку:

Исключение первого шанса в 0x7555D3CF в XPS printing.exe: исключение Microsoft C ++: SplException :: THResultException в ячейке памяти 0x002CEF9C.

Если есть обработчик для этого исключения, программа может быть безопасно продолжена.

SSCCEE:

Ниже приведена функция, которую я переписал. Я отметил точку сбоя с соответствующими комментариями.

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 из приведенного выше примера) для рисования текста и контура прямоугольника?

4

Решение

в SetStrokeBrushLocal документация:

После вызова SetStrokeBrushLocal, ключ поиска мазка кисти отпускается, и GetStrokeBrushLookup возвращает нулевой указатель в параметре поиска.

Вы могли бы использовать Clone на кисти перед использованием.

Но, если вы планируете повторно использовать кисти, используйте CreateDictionary, SetDictionaryLocal а потом Append твоя кисть там; который позволит вам использовать SetFillBrushLookup,

3

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]