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

时间:2012-04-10 22:32:36

标签: c# pdf

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

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

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

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

我浏览了ISO specification for PDF,但文件格式对我来说似乎太复杂了,只需解析第1页结束的位置。另一方面,线性化PDF的工具几乎肯定知道第1页的结束位置。

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

我也认为这不会帮助我使用AP Split等工具将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
    << /Linearized 1.0 % Version
     /L 54567   % File length
     /H [475 598] % Primary hint stream offset and length (part 5)
     /O 45      % Object number of first page’s page object (part 6)
     /E 5437    % Offset of end of first page
     /N 11      % Number of pages in document
     /T 52786 % Offset of first entry in main cross-reference table (part 11)
    >>
    endobj

在此示例中,第一页的末尾位于字节偏移5437.此数据结构非常简单,可以使用几乎任何语言进行解析。 “43 0 obj”事物给出了该字典(43)的ID和世代号(线性化文件总是为零)。字典本身被&lt;&lt;&lt;和&gt;&gt;,其间是键值对(键有斜杠,如“/ 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+(?<offset>\d+).+>>");
  if (!match.Success) throw new InvalidDataException("PDF does not have a proper linearization dictionary");
  return int.Parse(match.Groups["offset"].Value);
}

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

1 个答案:

答案 0 :(得分:3)

线性化词典可以帮助你解决这个问题。

包含E参数

所需的字典
  

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

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

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