Technical Article

Spracovanie PDF súborov s hybridnými odkazmi z aplikácií Office v Delphi

Pri vývoji podnikových riešení pre dokumenty nevyhnutne narazíte na PDF súbory vygenerované obrovským množstvom nástrojov, od špičkového softvéru Adobe po chybné open-source knižnice alebo ovládače virtuálnych tlačiarní. Jedným z najznámejších štrukturálnych problémov, ktorým budete čeliť, sú PDF s "hybridnými odkazmi" (hybrid-reference).

V tomto článku vysvetlíme, čo sú to hybridné odkazy, prečo ich niektoré kancelárske aplikácie generujú a ako tieto štruktúry programovo analyzovať a opravovať pomocou Delphi a robustných knižníc pre PDF.

Vývoj tabuľky krížových odkazov v PDF

Na rýchle vyhľadanie objektov (písma, obrázky, stránky) bez analýzy celého súboru používa PDF tabuľku krížových odkazov (Cross-Reference Table, XRef). V starších špecifikáciách PDF (PDF 1.4 a staršie) to bola doslovná textová ASCII tabuľka na konci súboru.

Počnúc verziou PDF 1.5 spoločnosť Adobe zaviedla Cross-Reference Streams (XRefStm), ktoré komprimovali údaje krížových odkazov do binárneho streamu, čím sa výrazne zmenšila veľkosť súborov. Avšak pre spätnú kompatibilitu so staršími čítačkami PDF začali niektoré generátory vytvárať PDF s hybridnými odkazmi. Tieto súbory obsahujú starú ASCII tabuľku XRef aj nový stream XRef.

Problém s hybridnými odkazmi

Hybridné súbory sú teoreticky platné, ale mnohé generátory PDF (najmä staršie doplnky "Uložiť ako PDF" v starších balíkoch Office) ich zapisujú nesprávne. Častou chybou je zápis nesprávneho bajtového offsetu pre ukazovateľ startxref alebo vytvorenie nesúvisiacich streamov objektov, kde tabuľka XRef ukazuje na nesprávne číslo generácie.

Ak sa vaša aplikácia v Delphi pokúsi prečítať nesprávne naformátované hybridné PDF pomocou striktného analyzátora, analyzátor zlyhá s výnimkou "Corrupt XRef table" alebo "Invalid Object Number".

Riešenie hybridných záložných riešení pomocou PDFium

Nástroj PDFium (pôvodne vyvinutý spoločnosťou Foxit a sprístupnený ako open-source spoločnosťou Google) je vysoko tolerantný voči poškodeným PDF súborom. Keď zistí poškodenú tabuľku XRef, automaticky prehľadá súbor spätne od konca súboru (EOF), aby našiel alternatívny XRefStm.

V Delphi, keď pracujete s PDFium, nemusíte manuálne analyzovať slovníky trailerov. Mali by ste však skontrolovať štrukturálne varovania, aby ste mohli upozorniť používateľa alebo zaznamenať problém do protokolu.

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;

Oprava a prestavba PDF

Ak váš pracovný postup vyžaduje odovzdanie PDF do prísnejšieho nadväzujúceho systému (napríklad starší hardvérový RIP), musíte hybridnú štruktúru "sploštiť". Najspoľahlivejším spôsobom, ako opraviť poškodené hybridné PDF v Delphi, je načítať ho do tolerantného enginu a vykonať operáciu Uložiť ako. To prinúti analyzátor prestavať čistú a zjednotenú tabuľku XRef zo stromu objektov v pamäti.

// 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;

Pochopenie a predvídanie poškodenia hybridných odkazov zabezpečuje, že vaše linky na spracovanie dokumentov zostanú odolné aj pri práci s desaťročia starými súbormi.

Poznámka: Rozlíšenie hybridných odkazov a automatické štrukturálne opravy sú plne podporované v komponente PDFium Component.