如何确定线性化PDF文件中第1页的范围(以字节为单位)?

我知道我可以“线性化”PDF文件,例如使用Acrobat SDK或使用商业工具。 这也称为“针对网络优化”,它重新排列PDF,以便第1页可以尽快加载。 以这种方式提供的PDF显示得更快,因为PDF查看器不必等待下载整个PDF。

更新:基于下面的答案,我现在意识到线性化的PDF不仅重新排列,而且还包含有关其自身结构的元数据,以“线性化字典”的forms。

我有一个应用程序,我想预取几个PDF(查询的结果),以期用户希望看到其中一个。 如果我的客户端可以为每个搜索结果下载第1页,只有第1页,那将是非常棒的。 当用户选择其中一个时,可以立即显示第1页,其余部分可以在后台下载。

我正在寻找可以用于服务器端(Windows或Linux)来预处理我的PDF的通用解决方案,以便我可以分别存储和提供第1页和其余部分。 真的,我需要知道的是PDF中的哪一个是正确显示第1页所需的最后一个字节。如果我可以有这个数字,那么其他所有内容都是如此。

我已经浏览了PDF的ISO规范,但文件格式似乎太复杂,我无法简单地解析第1页结束的位置。 另一方面,线性化PDF的工具几乎肯定知道第1页的结束位置。

我对客户提供PDF文件的复杂性并不感兴趣; 这部分已经解决,因为客户端是一个应用程序,而不是一个浏览器,我完全控制。

我也认为它不会帮助我使用AP拆分工具将PDF 拆分为“第1页”PDF和完整的PDF。 如果我这样做,那么我将无法欺骗客户端查看器认为它是单个PDF文件,并且当我用完整的PDF替换“第1页”PDF时会有明显的闪烁。

任何帮助或指针赞赏。

解决方案 (基于Bobrovsky的答案):

正确线性化的PDF以标题行开头(在PDF规范的7.5.2节中定义),例如“%PDF-1.7”,后跟至少四个二进制字符的注释行(定义为128或更高的字节值) 。 例如:

%PDF-1.7 %¤¤¤¤ 

此标题后面紧跟着线性化字典(在PDF规范的附录F中定义)。 一个例子:

  43 0 obj <> endobj 

在这个例子中,第一页的末尾是字节偏移5437.这个数据结构很简单,可以使用几乎任何语言进行解析。 “43 0 obj”事物给出了该字典(43)的ID和世代号(线性化文件总是为零)。 字典本身被<>包围,其间是键值对(键有斜杠,如“/ E”)。

这是一个使用正则表达式查找相关数字的C#方法:

 public int GetPageOneLength(byte[] data) { // According to ISO PDF spec: "The linearization parameter dictionary shall be entirely contained within the first 1024 bytes of the PDF file" (p. 679) string preamble = new string(ASCIIEncoding.ASCII.GetChars(data, 0, 1024)); // Note that the binary section on line 2 of the header will be entirely converted to question martks ('?') var match = Regex.Match(preamble, @"<<\w*/Linearized.+/E\s+(?\d+).+>>"); if (!match.Success) throw new InvalidDataException("PDF does not have a proper linearization dictionary"); return int.Parse(match.Groups["offset"].Value); } 

注意Bobrovsky警告说文件可能包含线性化字典,但可能没有正确线性化(可能是因为增量编辑?)。 在我的情况下,这不是问题,因为我将自己线性化所有PDF。

线性化词典应该对此有所帮助。

包含E参数所需的字典

相对于文件开头的第一页末尾(示例F.1中第6部分的结尾)的偏移量。

请注意,并非每个带有线性化字典的文件都实际上是线性化的(损坏的生成器,线性化后的更改等)。因此,如果未validation文件是否正确线性化,则可能无法使用所描述的方法。

有关线性化字典的更多信息,请参阅PDF参考中的F.2.2线性化参数字典(第2部分)