Technical Article

Obravnavanje PDF datotek s hibridnimi referencami iz Office aplikacij v Delphiju

Pri razvoju dokumentnih rešitev za podjetja boste neizogibno naleteli na PDF datoteke, ki jih ustvari ogromno različnih orodij, od vrhunske programske opreme Adobe do hroščate odprtokodne knjižnice ali virtualnih gonilnikov tiskalnikov. Ena izmed najbolj zloglasnih strukturnih težav, s katerimi se boste soočili, je "hibridna referenca" (hybrid-reference) PDF datoteke.

V tem članku bomo pojasnili, kaj so hibridne reference, zakaj jih določene Office aplikacije ustvarjajo ter kako programsko razčleniti in popraviti te strukture z uporabo Delphija in robustnih PDF knjižnic.

Evolucija tabele navzkrižnih referenc PDF

Za hitro iskanje objektov (pisav, slik, strani) brez razčlenjevanja celotne datoteke PDF uporablja tabelo navzkrižnih referenc (Cross-Reference Table - XRef). V starejših specifikacijah PDF (PDF 1.4 in starejše) je bila to dobesedna tabela z besedilom ASCII na koncu datoteke.

Začenši s PDF 1.5 je Adobe predstavil tokove navzkrižnih referenc (Cross-Reference Streams - XRefStm), ki so stisnili podatke navzkrižnih referenc v binarni tok in s tem znatno zmanjšali velikost datotek. Kljub temu so za združljivost za nazaj s starejšimi bralniki PDF nekateri generatorji začeli ustvarjati PDF datoteke s hibridnimi referencami. Te datoteke vsebujejo tako staro tabelo XRef v formatu ASCII kot nov tok XRef.

Težava s hibridnimi referencami

Hibridne datoteke so teoretično veljavne, vendar jih mnogi generatorji PDF (zlasti starejši vtičniki "Shrani kot PDF" v starejših pisarniških paketih) zapišejo nepravilno. Pogost hrošč je pisanje napačnega bajtnega odmika za kazalec `startxref` ali ustvarjanje nepovezanih tokov objektov, kjer tabela XRef kaže na napačno številko generacije.

Če vaša Delphi aplikacija poskuša prebrati slabo oblikovano hibridno datoteko PDF s strogim razčlenjevalnikom, bo razčlenjevalnik odpovedal z izjemo "Corrupt XRef table" (Poškodovana tabela XRef) ali "Invalid Object Number" (Neveljavna številka objekta).

Obravnavanje hibridnih napak s PDFium

Mehanizem PDFium (ki ga je prvotno razvil Foxit in je zdaj odprtokoden pod okriljem Googla) je zelo toleranten do slabo oblikovanih PDF datotek. Ko zazna poškodovano tabelo XRef, samodejno preišče datoteko nazaj od konca (EOF), da najde alternativni XRefStm.

V Delphiju vam pri delu s PDFium ni treba ročno razčlenjevati slovarjev trailerja. Vendar pa bi morali preveriti strukturna opozorila, da lahko opozorite uporabnika ali zabeležite težavo.

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;

Popravljanje in obnova PDF dokumenta

Če vaš delovni proces zahteva posredovanje PDF datoteke v strožji sistem v nadaljevanju (kot je starejši strojni RIP), morate "sploščiti" (flatten) hibridno strukturo. Najbolj zanesljiv način za popravilo poškodovanega hibridnega PDF dokumenta v Delphiju je nalaganje v toleranten mehanizem in izvedba operacije "Shrani kot" (Save-As). To prisili razčlenjevalnik, da iz drevesa objektov v pomnilniku zgradi čisto, enotno tabelo 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;

Razumevanje in predvidevanje poškodb hibridnih referenc zagotavlja, da vaši cevovodi za obdelavo dokumentov ostanejo odporni, tudi ko se soočijo z desetletja starimi datotekami.

Opomba: Razreševanje hibridnih referenc in samodejna strukturna popravila so v celoti podprta v komponenti PDFium Component.