たとえば、Acrobat SDK や商用ツールを使用して、PDF ファイルを「線形化」できることを知っています。これは「Web 用に最適化」とも呼ばれ、ページ 1 をできるだけ速くロードできるように PDF を再配置します。PDF ビューアーは PDF 全体がダウンロードされるのを待つ必要がないため、この方法で提供された PDF はより迅速に表示されます。
更新:以下の回答に基づいて、線形化された PDF は再配置されるだけでなく、「線形化辞書」の形式で独自の構造に関するメタデータも含まれていることがわかりました。
ユーザーがそのうちの 1 つを表示することを期待して、複数の PDF (クエリの結果) をプリフェッチするアプリケーションがあります。私のクライアントが、検索結果ごとに 1 ページだけをダウンロードできたら最高です。ユーザーがそれらのいずれかを選択すると、ページ 1 が即座に表示され、残りはバックグラウンドでダウンロードされます。
サーバー側 (Windows または Linux) で使用して PDF を前処理できる一般的なソリューションを探しています。これにより、ページ 1 と残りの部分を別々に保存して提供できます。実際、私が知る必要があるのは、ページ 1 を適切に表示するために必要な最後のバイトが PDF のどこにあるかだけです。この番号を取得できれば、他のすべてが続きます。
PDFのISO 仕様を参照しましたが、ファイル形式が複雑すぎて、ページ 1 がどこで終わるかを簡単に解析できません。一方、PDF を線形化するツールは、ページ 1 がどこで終了するかをほぼ確実に認識している必要があります。
PDF を分割してクライアントに提供することの複雑さには興味がありません。クライアントはブラウザーではなくアプリであるため、この部分は既に解決されており、私は完全に制御できます。
また、 AP Splitなどのツールを使用して PDF を「ページ 1」PDF と完全な PDFに分割することも役に立たないと思います。その場合、クライアント ビューアーをだまして単一の PDF ファイルであると認識させることはできず、「ページ 1」の PDF を完全な PDF に置き換えると、顕著なちらつきが発生します。
ヘルプやポインタをいただければ幸いです。
解決策(以下のBobrovskyの回答に基づく):
適切に線形化された PDF は、「%PDF-1.7」などのヘッダー行 (PDF 仕様のセクション 7.5.2 で定義) で始まり、その後に少なくとも 4 つのバイナリ文字 (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 を自分で線形化するので、これは問題ではありません。