Technical Article

Hantera hybridreferens-PDF:er från Office-program i Delphi

När du utvecklar dokumentlösningar för företag kommer du oundvikligen att stöta på PDF-filer genererade av en mängd olika verktyg, från avancerad Adobe-programvara till buggiga bibliotek med öppen källkod eller virtuella skrivardrivrutiner. Ett av de mest ökända strukturella problemen du kommer att möta är PDF-filer med "hybridreferens" (hybrid-reference).

I den här artikeln förklarar vi vad hybridreferenser är, varför vissa kontorsprogram genererar dem, och hur man programmatiskt kan tolka och reparera dessa strukturer med hjälp av Delphi och robusta PDF-bibliotek.

Utvecklingen av PDF-korsreferenstabellen

För att snabbt hitta objekt (teckensnitt, bilder, sidor) utan att tolka hela filen använder PDF en korsreferenstabell (Cross-Reference Table, XRef). I tidigare PDF-specifikationer (PDF 1.4 och äldre) var detta bokstavligen en ASCII-texttabell i slutet av filen.

Från och med PDF 1.5 introducerade Adobe Cross-Reference Streams (XRefStm), vilket komprimerade korsreferensdata till en binär ström, vilket avsevärt minskade filstorlekarna. För bakåtkompatibilitet med äldre PDF-läsare började dock vissa generatorer producera hybridreferens-PDF:er. Dessa filer innehåller både en ASCII XRef-tabell i äldre stil och en XRef-ström i nyare stil.

Problemet med hybridreferenser

Hybridfiler är teoretiskt sett giltiga, men många PDF-generatorer (särskilt äldre "Spara som PDF"-plugins i äldre Office-paket) skriver dem felaktigt. En vanlig bugg är att skriva fel byteförskjutning (byte offset) för `startxref`-pekaren, eller att skapa osammanhängande objektströmmar där XRef-tabellen pekar på fel generationsnummer.

Om din Delphi-applikation försöker läsa en dåligt formaterad hybrid-PDF med en strikt tolkare, kommer tolkaren att misslyckas med ett undantag för "Corrupt XRef table" eller "Invalid Object Number".

Hantera reservlösningar för hybrider med PDFium

PDFium-motorn (ursprungligen utvecklad av Foxit och släppt som öppen källkod av Google) är mycket tolerant mot felaktiga PDF-filer. När den upptäcker en trasig XRef-tabell söker den automatiskt filen baklänges från EOF för att hitta den alternativa XRefStm.

När du arbetar med PDFium i Delphi behöver du inte manuellt tolka trailer-ordböckerna (trailer dictionaries). Du bör dock kontrollera efter strukturella varningar så att du kan varna användaren eller logga problemet.

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;

Korrigera och bygga om PDF:en

Om ditt arbetsflöde kräver att PDF:en skickas vidare till ett striktare nedströmssystem (som en äldre hårdvaru-RIP) måste du "platta till" hybridstrukturen. Det mest pålitliga sättet att fixa en trasig hybrid-PDF i Delphi är att ladda in den i en tolerant motor och utföra en Spara som-åtgärd. Detta tvingar tolkaren att bygga om en ren, enhetlig XRef-tabell från objektträdet i minnet.

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

Att förstå och förutse korruption av hybridreferenser säkerställer att dina dokumentbearbetningsflöden förblir motståndskraftiga, även när du står inför årtionden gamla äldre filer.

Obs: Upplösning av hybridreferenser och automatiska strukturella reparationer stöds fullt ut av PDFium Component.