Technisch artikel

PDF-pagina's converteren naar JPEG-afbeeldingen in Delphi met PDFium

Delphi biedt geen eigen manieren om een vector-PDF te converteren naar een rasterafbeelding die kan worden opgeslagen of via een netwerk kan worden verzonden. U heeft een renderengine nodig. De PDFium Component omhult de PDFium-engine en verzorgt de GDI/GDI+-integratie, waardoor de conversie van PDF-pagina's naar JPEG slechts een kwestie wordt van wiskunde voor het schalen, een render-aanroep op VCL TBitmap, en codering via de standaard TJPEGImage

De PDF openen en pagina-afmetingen verkrijgen

Het proces start via TPdf, niet via de grafische component (TPdfView). Wijs de FileName toe en stel Active in op True. Onthoud dat Active := True geen uitzondering opwerpt bij een mislukte actie; u moet controleren of de toewijzing daadwerkelijk standhoudt. Daarna is the PageNumber (1-gebaseerd) gereed voor gebruik

var
  Pdf: TPdf;
begin
  Pdf := TPdf.Create(nil);
  try
    Pdf.FileName := 'document.pdf';
    Pdf.Active := True;
    if not Pdf.Active then
      Exit; // File not found or password protected
      
    Pdf.PageNumber := 1;
    // ...
  finally
    Pdf.Free;
  end;
end;

In PDF's worden pagina-afmetingen uitgedrukt in punten, waarbij 1 punt in theorie 1/72 inch is. Zodra PageNumber is toegewezen, geven Pdf.PageWidth en Pdf.PageHeight de afmetingen in punten terug, zoals gespecificeerd in de MediaBox of CropBox van het document

De afmetingen van de afbeeldingsuitvoer berekenen

Om te renderen, heeft u een resolutie in DPI (dots per inch) nodig, wat bepaalt hoe gedetailleerd en groot uw resulterende afbeelding wordt. Een DPI van 72 resulteert in één pixel voor elk PDF-punt (snelle export met lage resolutie), terwijl een DPI van 300 documenten produceert die geschikt zijn voor OCR of weergave met hoge resolutie

var
  DPI: Integer;
  BmpWidth, BmpHeight: Integer;
begin
  DPI := 300; // Standard print quality
  
  // PDF dimensions are in 1/72 inch points. 
  // Multiply by (DPI / 72.0) to get target pixel dimensions.
  BmpWidth  := Round(Pdf.PageWidth * (DPI / 72.0));
  BmpHeight := Round(Pdf.PageHeight * (DPI / 72.0));
  // ...
end;

Een standaard 8,5 x 11 inch pagina bij 300 DPI vereist een afbeelding van 2550 x 3300 pixels, wat behoorlijk wat geheugen vergt bij de toewijzing als 32-bits DIB (apparaat-onafhankelijke bitmap). Ga er niet vanuit dat het geheugen altijd toereikend is bij het verwerken van documenten met extra grote formaten (bijv. architectonische ontwerpen)

De render uitvoeren naar een TBitmap

Voorafgaand aan de conversie naar JPEG, moet de pixelinhoud worden gerenderd in een VCL TBitmap met behulp van de ingebouwde DrawPage-methode. Met deze methode kan de PDFium-bibliotheek direct in de device context (DC) van het canvas tekenen

var
  Bmp: TBitmap;
begin
  Bmp := TBitmap.Create;
  try
    // Use pf32bit to avoid complex palette issues when rendering via GDI/GDI+
    Bmp.PixelFormat := pf32bit;
    Bmp.Width  := BmpWidth;
    Bmp.Height := BmpHeight;
    
    // Fill background with white because PDF background is technically transparent
    Bmp.Canvas.Brush.Color := clWhite;
    Bmp.Canvas.Brush.Style := bsSolid;
    Bmp.Canvas.FillRect(Rect(0, 0, BmpWidth, BmpHeight));

    // Render the page contents scaled to the entire bitmap bounds
    Pdf.DrawPage(Bmp.Canvas.Handle, 0, 0, BmpWidth, BmpHeight);
    
    // ... encode to JPEG
  finally
    Bmp.Free;
  end;
end;

De belangrijkste opmerking hierbij is FillRect. Vrijwel alle PDF-documenten hebben een lege (transparante) achtergrond, in plaats van een witte. Zonder de achtergrond te vullen, zal de gerenderde bitmap een willekeurige opvulling voor GDI hebben - waarschijnlijk ondoorzichtig zwart - waardoor al uw tekst en lijntekeningen die op wit bedoeld waren, in plaats daarvan donkerder zijn na het rasteren

Coderen naar TJPEGImage en opslaan

Zodra de onbewerkte TBitmap de render opslaat, brengt u de afbeelding over naar een TJPEGImage uit de Vcl.Imaging.jpeg-unit voor compressie, en schrijft u naar een bestand of stream

uses
  Vcl.Imaging.jpeg;
  
// ...
var
  Jpg: TJPEGImage;
begin
  Jpg := TJPEGImage.Create;
  try
    // Transfer the DIB payload
    Jpg.Assign(Bmp);
    
    // Optionally balance quality versus output file size
    Jpg.CompressionQuality := 85; 
    
    Jpg.SaveToFile('page_1.jpg');
  finally
    Jpg.Free;
  end;
end;

Het Assign-commando verwerkt de kleurruimte-conversie (normaal BGR naar YCbCr in de codec). Omdat CompressionQuality de bestandsgrootte direct beïnvloedt, is the standaard 90 een goede balans; verlaag deze naar 75 of 80 voor bestandsarchivering indien visuele degradatie is toegestaan, maar let op: artefacten van de compressie verstoren scherpe vectorranden aanzienlijk sneller dan bij fotografie

De methoden en concepten die hier worden geschetst, maken deel uit van de PDFium Component, de primaire bibliotheek van losLab Software voor het programmeren en genereren van documenten