如何确定线性化PDF文件中第一页的大小(以字节为单位)?

9
我知道可以“线性化”PDF文件,例如使用Acrobat SDK或商业工具。这也被称为“优化为Web”,它重新排列PDF,以便第一页能够尽快加载。以这种方式提供的PDF显示更快,因为PDF查看器不必等待整个PDF下载完毕。
更新:根据下面的答案,我现在意识到,线性化的PDF不仅仅是重新排列,而且还包含有关其自身结构的元数据,以“线性化字典”的形式。
我有一个应用程序,在其中我希望预取几个PDF(查询结果),以期望用户会想要查看其中之一。如果我的客户端可以下载每个搜索结果的第一页,只有第一页,那将是很棒的。当用户选择其中一个时,第一页可以立即显示,其余部分可以在后台下载。
我正在寻找一般解决方案,可用于服务器端(Windows或Linux)预处理我的PDF,以便我可以单独存储和提供第一页和其余部分。实际上,我只需要知道PDF中显示第一页所需的最后一个字节在哪里。如果我知道了这个数字,其他所有问题都迎刃而解。
我已经浏览了PDF的ISO规范,但是文件格式对我来说似乎太复杂了,无法简单地解析出第一页在哪里结束。另一方面,线性化PDF的工具几乎肯定知道第一页在哪里结束。
我不感兴趣将PDF分成多个部分提供给客户端的复杂性;这部分已经解决,因为客户端是应用程序,而不是浏览器,并且我有完全的控制权。
我也不认为使用AP Split等工具将PDF拆分为“第一页”PDF和完整PDF会对我有所帮助。如果我这样做,那么我将无法欺骗客户端查看器,让它认为它是一个单独的PDF文件,当我用完整PDF替换“第一页”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"指定了该字典的ID(43)和一代号(对于线性化文件始终为零)。字典本身被<<和>>包围,之间是键值对(键带有斜杠,如"/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
另一个注意事项:我曾经看到过在标题和线性化字典开始之间有垃圾字节的PDF文件。 - Bobrovsky
1个回答

4
线性化字典可以帮助您解决此问题。该字典需要包含参数E,即第一页的结尾(例如F.1部分的结尾)相对于文件开头的偏移量。请注意,并非每个具有线性化字典的文件都实际上是线性化的(生成器故障、线性化后更改等)。因此,如果您的文件未经过验证以正确进行线性化,则可能无法使用所述方法。有关线性化字典的更多信息,请参阅PDF参考中的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接