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

本文关键字:范围 字节 为单位 线性化 何确定 PDF 文件 | 更新日期: 2023-09-27 18:30:52

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

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

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

我正在寻找一种可以在服务器端(Windows 或 Linux)使用来预处理我的 PDF 的通用解决方案,以便我可以单独存储和提供第 1 页和其余部分。真的,我只需要知道 PDF 中正确显示第 1 页所需的最后一个字节的位置。如果我能有这个数字,其他一切都在后面。

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

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

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

任何帮助或指示表示赞赏。

解决方案(基于下面博布罗夫斯基的回答):

正确线性化的 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和世代号(线性化文件总是零)。字典本身由<<和>>包围,它们之间是键值对(键具有斜杠,如"/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。

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

线性化字典应该可以帮助您解决这个问题。

需要包含E参数的字典

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

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

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