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.