这个项目让你可以去读取并剖析一个PDF文件,并将其外部构造展现出来. PDF文件的格局规范文档可以从Adobe那儿获得到. 这个项目基于“PDF指南,第六版,Adobe便携文档格局1.7 2006年11月”. 它是一个生怕有1310页的大部头. 本文供给了对这份文档的简练概述. 与此相干的项目定义了用来读取息争析PDF文件的C#类. 为了测试这些类,附带的测试顺序PdfFileAnalyzer让你可以去读取一个PDF文件,剖析它并展现和保管后果. 顺序将PDF文件联系成独自每页的描绘,字体,图片和其它工具. 有两品种型的PDF文件不受此顺序的支撑: 加密文件和多代文件.
这个顺序的1.1版本答应天下各地运用点符号作为小数分开符的顺序员来编译和运转顺序.
1.2版本则修复了一个有关运用跨多个援用流来读取PDF文档的问题. 1.2之前的版本对此场景只会以一个工具数字反复的错误而终止运转.
假如你对将PDF文件写入器引入你的使用顺序,那就请读一读 "PDF 文件写入顺序 C# 类库" 这篇文章吧.
PDF格局的文件,借助Adobe Acrobat软件,可以在各类屏幕上显示检查,运用各类打印机打印。可是,假如运用二进制文件编辑器翻开PDF文件,你会发明文件的大部分是不成读的,有小部分是可读的,以下:
1 0 obj <</Lang(en-CA)/MarkInfo<</Marked true>>/Pages 2 0 R /StructTreeRoot 10 0 R/Type/Catalog>> endobj 2 0 obj <</Count 1/Kids[4 0 R]/Type/Pages>> endobj 4 0 obj <</Contents 5 0 R/Group <</CS/DeviceRGB /S/Transparency /Type/Group>> /MediaBox[0 0 612 792] /Parent 2 0 R /Resources <</Font <</F1 6 0 R /F2 8 0 R>> /ProcSet[/PDF/Text/ImageB/ImageC/ImageI]>> /StructParents 0/Tabs/S/Type/Page>> endobj 5 0 obj <</Filter/FlateDecode/Length 2319>> stream . . . endstream endobj
看上去,该文件是由嵌套在“n 0 OBJ ”和“ endobj ”要害词之间的工具构成的,术语PDF也就是直接工具的意思。 “obj”后面的数字是工具编号和第几代工具标识, 双尖括号中的内容表现数据字典工具,中括号中的内容表现数组工具, 以斜杠/ Start的内容表现参数称号 (例如: /Pages)。上例中的第一项 “1 0 obj” 表现文档的目次或许文档的根工具。文档目次的字典工具 “/Pages 2 0 R”,指向定义页码树工具的援用。依照如许推算,编号为2的工具包括指向 “/Kids[4 0 R]”的页面的援用,是一个页面文档。 编号为4的工具是独一的一个页面定义, 页面巨细为612*792点, 换句话说,也就是8.5” * 11” (1” 代表72 点)点。该页面运用了两种字体F1和F2,这两种字体辨别在编号为6和8的工具中定义。该页面的内容在编号为5的工具中描绘,该工具中包括页面画图的流信息,示例中的 “. . .”代表这部分流信息。假如运用二进制文件编辑器翻开PDF文件,会发明这部分流信息看起来是一长串不成读的随机数,缘由是那是紧缩数据。流数据采取Zlib办法紧缩,紧缩方法由字典工具“/Filter /FlateDecode”描绘,被紧缩流的巨细为2319字节。解压这部分流信息,后面几行内容以下所示:
q 37.08 56.424 537.84 679.18 re W* n /P <</MCID 0>> BDC 0.753 g 36.6 465.43 537.96 24.84 re f* EMC /P <</MCID 1/Lang (x-none)>> BDC BT /F1 18 Tf 1 0 0 1 39.6 718.8 Tm 0 g 0 G [(GRA)29(NOTECH LI)-3(MIT)-4(ED)] TJ ET
这是页面描绘言语的一个小例子。 示例中, “re” 代表矩形,“re” 后面的4个数字代表矩形的地位和巨细,顺次为:终点横坐标、终点纵坐标、宽度、高度。
这个容易的例子演示了PDF文件外部完成的整体思绪。从页面条理构造的根工具Start, 每页都定义了诸如字体、图片、内容流的资本,内容流由操作符和绘制页面所需求的参数组成。PDF文件剖析器会发生一个工具汇总文件,该文件包括非流工具的其他一切工具。每一个数据流会被解码并保管为一个独自的文件, 页面描绘流保管为文本格局的文件, 图片流保管为.jpg或.bmp格局的文件,字体流保管为.ttf格局的文件,其他二进制流保管为.bin 格局的文件,文本流保管为.txt格局的文件。经过另外一个剖析进程,流畅难明的页面描绘会被转换为伪C#代码,如上例中的页面描绘被转为:
SaveGraphicsState(); // q Rectangle(37.08, 56.424, 537.84, 679.18); // re ClippingPathEvenOddRule(); // W* NoPaint(); // n BeginMarkedContentPropList("/P", "<</MCID 0>>"); // BDC GrayLevelForNonStroking(0.753); // g Rectangle(36.6, 465.43, 537.96, 24.84); // re FillEvenOddRule(); // f* EndMarkedContent(); // EMC BeginMarkedContentPropList("/P", "<</Lang(x-none)/MCID 1>>"); // BDC BeginText(); // BT SelectFontAndSize("/F1", 18); // Tf TextMatrix(1, 0, 0, 1, 39.6, 718.8); // Tm GrayLevelForNonStroking(0); // g GrayLevelForStroking(0); // G ShowTextWithGlyphPos("[(GRA)29(NOTECH LI)-3(MIT)-4(ED)]"); // TJ EndTextObject(); // ET
文章接下来的部分将对PDF文件的构造息争析进程实行更加具体的描绘,接下来的章节包含:工具定义,文件构造,文件剖析,文件读取,和运用PDF文件剖析器编程。
pdf 文件剖析器能处置大量的文件,这是我在本人的系陀鸹?描浩繁PDF文件的经历。不外,该顺序不支撑加密文件或许多个代文件(在工具不为零之前的第二个数字)。在PDF规格文件当中可用功用的数目长短常明显的。这其实不可能为一个单的个开发者系统地测试一切的功用。假如在全部文件剖析时期该顺序抛出一个异常,将显示一条错误信息,该信息显示源代码模块名和行号。
PDF文件生成多个工具。在PDF文件剖析器项目中每一个PDF工具都有一个对应的类。一切这些工具类都派生于PDFbase类。工具类定义源代码是BasicObjects.cs.确却地PDF工具定义在Adobe pdf文件 规格第三章当中是有效的
Boolean工具是靠PdfBoolean类来完成的. Boolean在PDF上的定义同C#上的是类似的.
Integer 工具是靠PdfInt类来完成的. PDF上的定义同C#上Int32的定义是类似的.
实数工具是靠PdfReal类来完成的. PDF上的定义同C#上的Single定义类似.
String 工具是靠PdfStr类来完成的. PDF上的定义同C#比拟有所分歧. String 是用字节结构出来的,而不是字符. 它被包在圆括号()外面. PdfFileAnalyzer会把包括在圆括号中的C#字符串保管成PDF的字符串. PDF的字符串关于ASCII编码十分有效.
十六进制字符串独享是靠PdfHex类来完成的. 它是由每字节两个十六进制数定义,并包在尖括号外面的字符串. PdfFileAnalyzer 将包括在尖括号中的C#字符串保管成PDF十六进制字符串. 关于 PDF 读取器,字符串和十六进制字符串工具可用于同种目标. 字符串 (AB) 同等于<4142>. PDF 十六进制字符串关于恣意编码的场景十分有效.
Name 工具是靠PdfName类来完成的. Name 工具是由打头的正斜杠前面随着一些字符构成的. 例如 /Width. Named 工具用作参数称号. PdfFileAnalyzer 将正斜杠扫尾的C#字符串保管成Name工具.
Null 工具是靠PdfNull类来完成的. PDF 关于null的定义根本上同C#中的是一样的.
Array 工具是靠 PdfArray 类来完成的. PDF 数组是一个封装在一堆中括号中的工具的聚集. 一个数组的工具可所以除流以外的任何工具.PdfFileAnalyzer 将一个C#数组中的工具保管成PdfBase类
. 由于一切的工具都承继自PdfBase,一切在这个数组中保管多品种型的工具没有啥问题. 当数组工具被转换成一个字符串时(运用ToString()办法), 顺序会在首位添加中括号. 数组可所以空的. 下面是一个有六个工具的数组示例: [120 9.56 true null (string) <414243>].
Dictionary 工具是靠PdfDict类完成的. PDF 字典是一组被包入一对双尖括号中的键值对聚集. Dictionary 的键是一个工具的称号,而值则可所以除流以外的任何工具. PdfFileAnalyzer 将一个键值对保管到PdfPair类中. 键是一个C#字符串,而值则是一个PdfBase.PdfDict 类有一个PdfPair类的数组. Dictionary 可以用键来拜访. 因此键值对的次序没有啥意义. PdfFileAnalyzer 用键来对键值对实行排序. 下面是一个有三个键值对的字典: <</CropBox [0 0 612 792] /Rotate 0 /Type /Page>>.
Stream 工具是靠PdfStream来完成的. Streams 被用来处置面善言语,图形和字体. PDF Stream 由一个字典和一个字节省构成. 字典中定义了流的参数. 比方流工具中字典的一个键值对 /Filter. PDF 文档定义了10品种型的过滤器. PdfFileAnalyzer 支撑了4种. 这是我发明在实践场景中只会被用到那4种. 紧缩过滤器 FlateDecode 是如今的PDF写入器最长被用到的过滤器. FlateDecode支撑ZLib解紧缩. LZWDecode 紧缩过滤器在过来些年用的比拟多. 为了能读取比拟老的PDF文件, 我们的顺序支撑这个过滤器. ASCII85Decode 过滤器将可被打印的ASCII转换成二进制位. DCTDecode 用于JPEG图象的紧缩.PdfFileAnalyzer 为前三种完成了解紧缩. DCTDecode 流则以文件扩大名.jpg保管. 它是一个可以被展现的图片文件.
Object 流在PDF 1.5中被引入. 它是一个包括多个直接工具(鄙人面会描绘道)的流. 上面描绘的Stream 工具一次只紧缩一个流. Object 流会将一切包括出去的流紧缩到一个紧缩域中.
多援用流在PDF 1.5中被引入. 它是一个包括多援用表格的流,下文会描绘到.
内联图片工具是靠 PdfInlineImage来完成的. 它是一个带有一个流的流. 内联图片是页面描绘言语的一部分. 它由BI-扫尾图形, ID-图形数据和EI-开头图形这三个操作符构成. BI 和 ID 之间的区域是一个图形字典,而ID 和 EI 之间的区域则包括图形数据.
直接工具是靠 PdfIndirectObject完成的. 它是一个PDF文档的首要结构块. 直接工具是任何被包在 “n 0 obj” 和 “endobj”之间的工具. 其它工具可以经过设定“n 0 R”来援用直接工具. “n”代表工具编号. “0”代表生成编号. 这个顺序不支撑0以外的生成编号. PDF 标准答应其它的编号. 多代生成的理念答应PDF的修正操作是在保存原有文件的根底上追加变卦.
工具援用时一种援用直接工具的办法. 例如 /Pages 2 0 R 是目次工具中的字典里的一项. 它是一个指向 /Pages 工具的指针. pages工具是编号为2的直接工具.
操作符和要害词不被以为是PDF工具. 而PdfFileAnalyzer 顺序有一个PdfOp 和一个PdfKeyword 类可以从中失掉 PdfBase 的类. 在转换过程当中,转换器为每个可用的字符序列创立了一个 PdfOp 或许PdfKeyword . Pdf文件标准的附录A-操作符总结中列出了一切的操作符. 列表中有73个操作符. 下面是一些操作符的示例: BT-打头的文本工具, G-用于做记号的设置灰度操作, m-Mobile到, re-矩形和Tc-设置字符间距. 下面是要害词的示例: stream, obj, endobj, xref.
PDF文件由四个部分组成: 头部Header , 主体body, 多援用cross-reference 和附带署名 trailer signature.
Header: 头部是文件的署名. 它必需是 %PDF-1.x , x 从 0 到 7.
Body: 主体区域包括一切的直接工具.
Cross-reference: 多援用是一个指向一切直接工具的文件地位指针列表. 有两品种型的多援用表格. 原始的类型有ASCII字符构成. 旧式的是一个包括一个直接工具的流. 信息以二进制数字编码. 在多援用表格的完毕部分有一个附件字典. 一个文件可以有超越一个的多援用区域.
Trailer signature: 附带署名由要害词“startxref”, 最初一个多援用表格的偏移位, 和完毕署名 %%EOF 构成. 请留意: 附带署名是多援用区域的一部分.
PDF 文件是一个字节的序列. 一些字节有特别的意义.
空格被定义成: null, tab, 换行, 换页, 回车和距离.
分开符被定义成: (, ), <, >, [, ], {, }, /, %, 和空格字符.
文件转换是由PdfParser 类来完成的. Start实行转换进程是,顺序会设置文件需求被转换区域的地位. ParseNextItem() 是提取下一个工具的办法.
剖析器跳过空格符和注释。假如下一个字节是“(”,判别工具为一个字符串。假如下一个字节是“[”,判别工具是一个数组。假如接下来的两个字节是“<<”,判别工具是一个字典。假如下一个字节是“<”,判别工具是一个十六进制字符串。假如下一个字节是“/”,判别工具是一个称号。假如下一个字节不是上述任何一种,剖析器会收集随后的字节直到发明定界符。定界符不是以后标志符的一部分。标志符可所以整数,实数,操作符或要害词。在整数的状况下,顺序将进一步搜刮工具援用“n 0 R”或直接工具“n 0 obj”中 n 为该整数的工具。从 ParseNextItem() 前往的值是第4节“工具的定义”中所述的恰当工具。工具的类作为 PdfBase 类前往。
在数组或字典的状况下,顺序将履行递归挪用 ParseNextItem() 来剖析数组或字典的外部工具。
PdfDocument 类是 PDF 文件剖析的首要类。进口办法是 ReadPdfFile(String FileName)。顺序以二进制读取的方法翻开 PDF 文件(一次一个字节)。
文件剖析Start于反省头部署名 %PDF-1.x(x为0到7)和开头署名%%EOF。有人会以为,一切的 PDF 生成器会把头部署名放在文件的零地位,开头署名放在文件的最初。不幸的是,实践并不是如斯。顺序必需在文件的两头搜刮这两个署名。假如头部署名不在零地位,一切直接工具的文件地位的指针也必需调剂。
就在开头署名的后面有一个指向最初一个穿插援用表Start地位的指针。
本文中的一切译文仅用于进修和交换目标,转载请务必注明文章译者、出处、和本文链接。 2KB翻译任务按照 CC 协议,假如我们的任务有进犯到您的权益,请实时联络我们。2KB项目(www.2kb.com,源码交易平台),提供担保交易、源码交易、虚拟商品、在家创业、在线创业、任务交易、网站设计、软件设计、网络兼职、站长交易、域名交易、链接买卖、网站交易、广告买卖、站长培训、建站美工等服务