一、XPS文档介绍
XPS格式化文档:XPS文档是XML Paper Specification(XML纸张规范)的缩写,是一种用于描述和打印电子文档的文件格式。XPS文档使用XML语法来描述文档的内容、布局和格式,可以保留文档的原始格式和布局,同时也支持高质量的打印输出。并非纯粹的结构化数据,XPS文档即能包含一些特定的格式和元数据,又能存储图像和字体等非结构化数据,图1为打印机驱动生成的XPS文档。
图1 XPS文档示意图
1.XPS文档目前广泛运用于:
(1)打印和出版业:XPS文档可以用于打印和出版,以保持文档的格式和布局的完整性。它们可以用于创建书籍、杂志、手册、宣传册等。
(2)商务和办公环境:XPS文档可以用于创建和共享各种商务文档,如报告、合同、演示文稿、传单等。它们可以在不同的设备和操作系统之间进行无缝的共享和查看。
(3)教育和培训:教育机构和培训中心可以使用XPS文档来创建课程材料、教科书、学习资源等。这些文档可以包含图表、图像、表格等多种形式的内容。
(4)设计和艺术:XPS文档可以用于设计和艺术领域,如平面设计、插图、艺术作品等。它们可以保持图像和颜色的高质量显示。
(5)政府和法律部门:政府机构和法律部门可以使用XPS文档来创建和共享各种法律文档、政策文件、报告等。这些文档可以提供安全和可靠的信息存储和传输。
(6)医疗保健:XPS文档可以用于医疗保健领域,如医学报告、病历、处方等。它们可以保持敏感的医疗数据的安全性和完整性。
(7)云计算/云桌面:虚拟打印机技术。
二、 XPS文档的结构
XPS文档解压后的文件如图2所示。
图2 XPS文档解压后的文件
- _rels文件夹:这个文件夹包含了与文档中其他部分的关系的XML文件。它定义了文档中各个部分之间的关联关系,如FixedDocumentSequence与FixedDocument之间的关系。
- DiscardControl.xml:这个文件包含了丢弃控制信息,用于指定哪些部分的内容可以被丢弃,以减小文档的大小。应用程序可以根据这个文件来判断是否需要加载或显示某些内容。
- Documents文件夹:这个文件夹包含了文档中的所有固定文档(FixedDocument)。每个固定文档都是一个独立的XML文件,描述了文档的结构和内容。
- Resources文件夹:这个文件夹包含了文档中使用的资源文件,如字体文件、图像文件等。这些资源文件可以被固定文档引用和使用。
- FixedDocumentSequence.fdseq:这个文件定义了文档中包含的所有固定文档的顺序。它包含了多个FixedDocumentReference元素,每个元素引用一个固定文档。
三、 XPS文档解析
图3 XPS文档的某个页面视觉元素示意
XPS文档的解析主要是提取下面的视觉元素:
- Package(包):XPS文档以一个ZIP格式的包开始,它包含了文档的所有内容。包中的主要文件是FixedDocumentSequence.fdseq和FixedDocument.fdoc,它们定义了文档的结构和内容。
- FixedDocumentSequence(固定文档序列):FixedDocumentSequence.fdseq文件定义了文档中包含的所有固定文档的顺序。它包含了多个FixedDocumentReference元素,每个元素引用一个固定文档。
- FixedDocument(固定文档):FixedDocument.fdoc文件定义了一个固定文档的结构和内容。它包含了多个Page元素,每个元素代表一个页面。
- Page(页面):Page元素定义了一个页面的结构和内容。它包含了多个Canvas元素,每个元素代表一个绘图层。
- Canvas(画布):Canvas元素是页面上的一个绘图层,用于组织和定位其他元素。它可以包含多个其他元素,如Path、Glyphs、Image等。
- Path(路径):Path元素定义了一个图形路径,可以用于绘制线条、曲线、矩形等。它包含了一系列的路径命令,如MoveTo、LineTo、ArcTo等。
- Glyphs(字形):Glyphs元素用于显示文本内容,它可以指定字体、字号、字形索引等属性。
- Image(图像):Image元素用于显示图像内容,它可以引用外部的图像文件,或者内嵌在XPS文档中的图像数据。
以下是使用C++提取XPS文档中的视觉元素的代码示例,包括注释说明:
#include <iostream>
#include <string>
#include <Windows.h>
#include <Msxpsdk.h>
int main()
{
// 打开XPS文档
std::wstring xpsFilePath = L"path_to_xps_file.xps";
IXpsOMObjectFactory* xpsFactory;
CoCreateInstance(__uuidof(XpsOMObjectFactory), NULL, CLSCTX_INPROC_SERVER, __uuidof(IXpsOMObjectFactory), reinterpret_cast<LPVOID*>(&xpsFactory));
IXpsOMPackage* xpsPackage;
xpsFactory->CreatePackageFromFile(xpsFilePath.c_str(), FALSE, &xpsPackage);
// 获取FixedDocumentSequence
IXpsOMDocumentSequence* documentSequence;
xpsPackage->GetDocumentSequence(&documentSequence);
// 遍历FixedDocumentSequence中的FixedDocuments
IXpsOMDocumentCollection* documentCollection;
documentSequence->GetDocuments(&documentCollection);
UINT32 documentCount;
documentCollection->GetCount(&documentCount);
for (UINT32 i = 0; i < documentCount; i++)
{
IXpsOMDocument* document;
documentCollection->GetAt(i, &document);
// 获取FixedDocument中的页面
IXpsOMPageReferenceCollection* pageReferenceCollection;
document->GetPageReferences(&pageReferenceCollection);
UINT32 pageReferenceCount;
pageReferenceCollection->GetCount(&pageReferenceCount);
for (UINT32 j = 0; j < pageReferenceCount; j++)
{
IXpsOMPageReference* pageReference;
pageReferenceCollection->GetAt(j, &pageReference);
// 获取页面
IXpsOMPage* page;
pageReference->GetPage(&page);
// 获取页面上的画布
IXpsOMCanvas* canvas;
page->GetVisuals(&canvas);
// 遍历画布上的子元素
IXpsOMVisualCollection* visualCollection;
canvas->GetVisuals(&visualCollection);
UINT32 visualCount;
visualCollection->GetCount(&visualCount);
for (UINT32 k = 0; k < visualCount; k++)
{
IXpsOMVisual* visual;
visualCollection->GetAt(k, &visual);
// 处理视觉元素,可以根据需要进行操作
XPS_OBJECT_TYPE type;
visual->GetType(&type);
if (type == XPS_OBJECT_TYPE_GLYPHS) {
IXpsOMGlyphs* pGlyphs = NULL;
hr = pVisualCollection->QueryInterface(IID_IXpsOMGlyphs, (void**)&pGlyphs);
LPWSTR unicodeString = NULL;
pGlyphs->GetUnicodeString(&unicodeString);
std::cout << "unicodeString " << unicodeString << std::endl;
}
// 释放视觉元素
visual->Release();
}
// 释放画布上的子元素集合
visualCollection->Release();
// 释放画布
canvas->Release();
// 释放页面
page->Release();
}
// 释放页面引用集合
pageReferenceCollection->Release();
// 释放文档
document->Release();
}
// 释放文档集合
documentCollection->Release();
// 释放FixedDocumentSequence
documentSequence->Release();
// 释放XPS文档
xpsPackage->Release();
xpsFactory->Release();
return 0;
}
```
上述代码使用Windows API和XPS SDK来打开XPS文档,并遍历文档中的固定文档和页面,提取每个页面上的画布和其子元素,然后对视觉元素进行处理。你可以根据需要在处理视觉元素的部分添加自己的代码逻辑。