Technical Article

DelphiでのOfficeアプリケーションからのハイブリッド参照PDFの処理

エンタープライズ向けのドキュメントソリューションを開発する際、ハイエンドのAdobeソフトウェアからバグの多いオープンソースライブラリや仮想プリンタドライバまで、多種多様なツールによって生成されたPDFに必然的に遭遇することになります。あなたが直面する最も悪名高い構造上の問題の1つは、「ハイブリッド参照」PDFです。

この記事では、ハイブリッド参照とは何か、なぜ特定のOfficeアプリケーションがそれらを生成するのか、そしてDelphiと堅牢なPDFライブラリを使用してこれらの構造をプログラムで解析および修復する方法について説明します。

PDF相互参照テーブルの進化

ファイル全体を解析することなく、オブジェクト(フォント、画像、ページ)をすばやく見つけるために、PDFは相互参照テーブル(XRef)を使用します。初期のPDF仕様(PDF 1.4以前)では、これはファイルの最後にある文字通りのASCIIテキストテーブルでした。

PDF 1.5以降、Adobeは相互参照ストリーム(XRefStm)を導入し、相互参照データをバイナリストリームに圧縮して、ファイルサイズを大幅に縮小しました。しかし、古いPDFリーダーとの下位互換性のために、一部のジェネレータはハイブリッド参照PDFを生成し始めました。これらのファイルには、古いスタイルのASCII XRefテーブルと新しいスタイルのXRefストリームの両方が含まれています。

ハイブリッド参照の問題点

ハイブリッドファイルは理論上は有効ですが、多くのPDFジェネレータ(特に古いOfficeスイートのレガシーな「PDFとして保存」プラグイン)はそれらを誤って書き込みます。よくあるバグは、`startxref`ポインタの誤ったバイトオフセットを書き込んだり、XRefテーブルが間違った世代番号を指す切断されたオブジェクトストリームを作成したりすることです。

Delphiアプリケーションが厳密なパーサーを使用して、形式の正しくないハイブリッドPDFを読み取ろうとすると、パーサーは「Corrupt XRef table」または「Invalid Object Number」の例外で失敗します。

PDFiumを使用したハイブリッドフォールバックの処理

PDFiumエンジン(元々はFoxitによって開発され、Googleによってオープンソース化されました)は、形式の正しくないPDFに対して非常に寛容です。破損したXRefテーブルを検出すると、自動的にファイルをEOFから逆方向にスキャンして、代替のXRefStmを見つけます。

Delphiでは、PDFiumを使用する場合、トレーラー辞書を手動で解析する必要はありません。ただし、構造上の警告を確認して、ユーザーに警告したり、問題をログに記録したりできるようにする必要があります。

uses
  System.SysUtils, pdfium_lib;

procedure LoadAndCheckHybridPDF(const FileName: string);
var
  Doc: FPDF_DOCUMENT;
  LastError: ULONG;
begin
  FPDF_InitLibrary();
  try
    Doc := FPDF_LoadDocument(PAnsiChar(AnsiString(FileName)), nil);
    if Doc = nil then
    begin
      LastError := FPDF_GetLastError();
      case LastError of
        FPDF_ERR_FILE: Writeln('File not found or could not be opened.');
        FPDF_ERR_FORMAT: Writeln('File not in PDF format or corrupted.');
        FPDF_ERR_PASSWORD: Writeln('Password required or incorrect password.');
        FPDF_ERR_SECURITY: Writeln('Unsupported security scheme.');
        FPDF_ERR_XFDF: Writeln('Invalid XRef or Hybrid Reference structure.');
      else
        Writeln('Unknown error occurred loading PDF.');
      end;
      Exit;
    end;
    
    Writeln('PDF loaded successfully despite hybrid or structural anomalies.');
    
    // Proceed with processing...
    
    FPDF_CloseDocument(Doc);
  finally
    FPDF_DestroyLibrary();
  end;
end;

PDFの修復と再構築

ワークフローでPDFをより厳格なダウンストリームシステム(古いハードウェアRIPなど)に渡す必要がある場合、ハイブリッド構造を「フラット化」する必要があります。Delphiで破損したハイブリッドPDFを修正する最も確実な方法は、寛容なエンジンにロードして名前を付けて保存操作を実行することです。これにより、パーサーはメモリ内のオブジェクトツリーからクリーンで統一されたXRefテーブルを強制的に再構築します。

// Conceptual example using a high-level wrapper
procedure RebuildPdfStructure(const InputFile, OutputFile: string);
var
  Doc: TlxPDFDocument;
begin
  Doc := TlxPDFDocument.Create;
  try
    // Tolerant engine ignores the broken hybrid XRef and walks the objects
    Doc.LoadFromFile(InputFile);
    
    // Saving rewrites the file with a clean PDF 1.7 XRef stream
    Doc.SaveToFile(OutputFile);
    Writeln('PDF structure successfully rebuilt.');
  finally
    Doc.Free;
  end;
end;

ハイブリッド参照の破損を理解し予測することで、数十年前のレガシーファイルに直面した場合でも、ドキュメント処理パイプラインの回復力を維持できます。

注: ハイブリッド参照の解決と自動構造修復は、PDFium Componentで完全にサポートされています。