Technical Article

Verwerken van hybride-referentie PDF's van Office-applicaties in Delphi

Bij het ontwikkelen van enterprise documentoplossingen zult u onvermijdelijk PDF's tegenkomen die door een enorme verscheidenheid aan tools zijn gegenereerd (van high-end Adobe software tot foutgevoelige open-source bibliotheken of virtuele printerdrivers). Een van de meest beruchte structurele problemen waarmee u te maken krijgt, is de "hybride-referentie" PDF.

In dit artikel leggen we uit wat hybride referenties zijn, waarom bepaalde office-applicaties deze genereren en hoe u deze structuren programmatisch kunt parsen en repareren met behulp van Delphi en robuuste PDF-bibliotheken.

De evolutie van de PDF kruisverwijzingstabel

Om objecten (lettertypen, afbeeldingen, pagina's) snel te lokaliseren zonder het hele bestand te parsen, gebruikt PDF een kruisverwijzingstabel (XRef). In eerdere PDF-specificaties (PDF 1.4 en ouder) was dit een letterlijke ASCII-teksttabel aan het einde van het bestand.

Vanaf PDF 1.5 introduceerde Adobe Cross-Reference Streams (XRefStm), die de kruisverwijzingsgegevens in een binaire stream comprimeerden, wat de bestandsgrootte aanzienlijk verkleinde. Echter, voor achterwaartse compatibiliteit met oudere PDF-lezers, begonnen sommige generatoren met het produceren van hybride-referentie PDF's. Deze bestanden bevatten zowel een oude stijl ASCII XRef-tabel als een nieuwe stijl XRef-stream.

Het probleem met hybride referenties

Hybride bestanden zijn theoretisch geldig, maar veel PDF-generatoren (vooral oudere "Opslaan als PDF" plugins in oudere Office-pakketten) schrijven ze verkeerd. Een veelvoorkomende bug is het schrijven van de verkeerde byte-offset voor de pointer `startxref`, of het creëren van onsamenhangende objectstreams waarbij de XRef-tabel naar het verkeerde generatienummer wijst.

Als uw Delphi-applicatie een slecht gevormde hybride PDF probeert te lezen met behulp van een strikte parser, zal de parser falen met een uitzondering zoals "Corrupt XRef table" of "Invalid Object Number".

Omgaan met hybride fallbacks met PDFium

De PDFium engine (oorspronkelijk ontwikkeld door Foxit en open-source gemaakt door Google) is zeer tolerant voor misvormde PDF's. Wanneer het een kapotte XRef-tabel detecteert, scant het automatisch het bestand achterwaarts vanaf EOF om de alternatieve XRefStm te lokaliseren.

In Delphi hoeft u, wanneer u met PDFium werkt, de trailer dictionaries niet handmatig te parsen. U moet echter wel controleren op structurele waarschuwingen, zodat u de gebruiker kunt waarschuwen of het probleem kunt loggen.

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;

De PDF repareren en opnieuw opbouwen

Als uw workflow vereist dat de PDF wordt doorgegeven aan een strikter downstream systeem (zoals een oudere hardware RIP), moet u de hybride structuur "afvlakken". De meest betrouwbare manier om een kapotte hybride PDF in Delphi te repareren, is om deze in een tolerante engine te laden en een Opslaan-als bewerking uit te voeren. Dit dwingt de parser om een schone, verenigde XRef-tabel opnieuw op te bouwen vanuit de objectboom in het geheugen.

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

Het begrijpen van en anticiperen op corruptie van hybride referenties zorgt ervoor dat uw documentverwerkingspijplijnen veerkrachtig blijven, zelfs wanneer ze te maken krijgen met decennia oude legacy bestanden.

Opmerking: Het oplossen van hybride referenties en automatische structurele reparaties worden volledig ondersteund door de PDFium Component.