Articolo tecnico

Stampa di documenti PDF con PDFium VCL in Delphi

· Programmazione PDF

Stampare documenti PDF con rendering accurato e ridimensionamento corretto è un requisito comune. Stampa PDF La demo mostra come implementare una stampa PDF professionale con anteprima, selezione delle pagine e opzioni di qualità utilizzando il componente PDFium VCL.

Panoramica

Questa demo completa fornisce una soluzione di stampa completa, inclusa l'anteprima di stampa, la selezione dell'intervallo di pagine, le impostazioni di qualità, le opzioni di ridimensionamento e la cronologia dei file recenti. Dimostra le migliori pratiche per la stampa PDF nelle applicazioni Delphi.

Caratteristiche Principali

  • Anteprima di stampa – Anteprima visiva prima della stampa
  • Selezione delle pagine – Stampa tutte le pagine o intervalli specifici
  • Impostazioni di qualità. – Modalità bozza, normale e alta qualità.
  • Opzioni di ridimensionamento. – Adatta alla pagina, riduci per adattare o nessun ridimensionamento.
  • Copie multiple. – Stampa più copie con ordinamento.
  • Monitoraggio dei progressi. – Feedback visivo durante la stampa.
  • File recenti – Accesso rapido ai documenti stampati in precedenza

Requisiti delle librerie DLL di PDFium

Prima di eseguire qualsiasi applicazione VCL di PDFium, assicurarsi che i file DLL di PDFium siano installati:

  • pdfium32.dll / pdfium64.dll – Versioni standard (~5-6 MB)
  • pdfium32v8.dll / pdfium64v8.dll – Con il motore JavaScript V8 (~23-27 MB)

Installazione: Esegui PDFiumVCL\DLLs\CopyDlls.bat come amministratore per copiare automaticamente i file DLL nelle directory di sistema di Windows.

Stampa PDF di base

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
procedure PrintPdfSimple(const FileName: string);
var
  Pdf: TPdf;
  I: Integer;
  Bitmap: TBitmap;
begin
  Pdf := TPdf.Create(nil);
  try
    Pdf.FileName := FileName;
    Pdf.Active := True;
    
    Printer.Title := Pdf.Title;
    Printer.BeginDoc;
    try
      for I := 1 to Pdf.PageCount do
      begin
        if I > 1 then
          Printer.NewPage;
          
        Pdf.PageNumber := I;
        
        // Render page to printer
        Bitmap := Pdf.RenderPage(
          0, 0,
          Printer.PageWidth,
          Printer.PageHeight,
          ro0,
          [rePrinting]
        );
        try
          PrintBitmap(Printer, Bitmap);
        finally
          Bitmap.Free;
        end;
      end;
    finally
      Printer.EndDoc;
    end;
    
  finally
    Pdf.Active := False;
    Pdf.Free;
  end;
end;

Stampa di bitmap alla stampante

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
procedure PrintBitmap(Printer: TPrinter; Bitmap: TBitmap);
var
  InfoHeaderSize, ImageSize: DWORD;
  InfoHeader: PBitmapInfo;
  Image: Pointer;
begin
  GetDIBSizes(Bitmap.Handle, InfoHeaderSize, ImageSize);
  
  InfoHeader := AllocMem(InfoHeaderSize);
  try
    Image := AllocMem(ImageSize);
    try
      GetDIB(Bitmap.Handle, 0, InfoHeader^, Image^);
      
      StretchDIBits(
        Printer.Canvas.Handle,
        0, 0, Bitmap.Width, Bitmap.Height,
        0, 0, Bitmap.Width, Bitmap.Height,
        Image, InfoHeader^,
        DIB_RGB_COLORS, SRCCOPY
      );
    finally
      FreeMem(Image);
    end;
  finally
    FreeMem(InfoHeader);
  end;
end;

Stampa completa con opzioni

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
procedure TFormMain.PrintPDFPages;
var
  FromPage, ToPage, Page, Copy, CopyCount: Integer;
  FirstPage: Boolean;
  Bitmap: TBitmap;
  ScaleX, ScaleY, Scale: Double;
  DestWidth, DestHeight: Integer;
  Dpi: Integer;
begin
  // Get print quality DPI
  case cmbQuality.ItemIndex of
    0: Dpi := 150;  // Draft
    1: Dpi := 300;  // Normal
    2: Dpi := 600;  // High
  else
    Dpi := 300;
  end;
  
  // Determine page range
  if radAllPages.Checked then
  begin
    FromPage := 1;
    ToPage := Pdf.PageCount;
  end
  else
  begin
    FromPage := StrToIntDef(edtFromPage.Text, 1);
    ToPage := StrToIntDef(edtToPage.Text, Pdf.PageCount);
  end;
  
  // Handle copies and collation
  if chkCollate.Checked then
    CopyCount := 1  // Will repeat entire job
  else
    CopyCount := spnCopies.Value;
    
  FProcessing := True;
  FCancelled := False;
  
  Printer.Title := ExtractFileName(Pdf.FileName);
  Printer.BeginDoc;
  try
    FirstPage := True;
    progressPrint.Max := (ToPage - FromPage + 1) * spnCopies.Value;
    progressPrint.Position := 0;
    
    for Page := FromPage to ToPage do
    begin
      for Copy := 1 to CopyCount do
      begin
        if FCancelled then
          Break;
          
        if FirstPage then
          FirstPage := False
        else
          Printer.NewPage;
          
        Pdf.PageNumber := Page;
        
        // Calculate scaling based on settings
        case cmbScaling.ItemIndex of
          0: // No scaling
          begin
            DestWidth := Round(Pdf.PageWidth * Dpi / 72);
            DestHeight := Round(Pdf.PageHeight * Dpi / 72);
          end;
          
          1: // Fit to page
          begin
            ScaleX := Printer.PageWidth / (Pdf.PageWidth * Dpi / 72);
            ScaleY := Printer.PageHeight / (Pdf.PageHeight * Dpi / 72);
            Scale := Min(ScaleX, ScaleY);
            DestWidth := Round(Pdf.PageWidth * Dpi / 72 * Scale);
            DestHeight := Round(Pdf.PageHeight * Dpi / 72 * Scale);
          end;
          
          2: // Shrink to fit (only if needed)
          begin
            ScaleX := Printer.PageWidth / (Pdf.PageWidth * Dpi / 72);
            ScaleY := Printer.PageHeight / (Pdf.PageHeight * Dpi / 72);
            Scale := Min(ScaleX, ScaleY);
            if Scale > 1 then Scale := 1;
            DestWidth := Round(Pdf.PageWidth * Dpi / 72 * Scale);
            DestHeight := Round(Pdf.PageHeight * Dpi / 72 * Scale);
          end;
        end;
        
        // Render and print
        Bitmap := Pdf.RenderPage(0, 0, DestWidth, DestHeight,
          ro0, [rePrinting, reAnnotations]);
        try
          PrintBitmap(Printer, Bitmap);
        finally
          Bitmap.Free;
        end;
        
        progressPrint.Position := progressPrint.Position + 1;
        Application.ProcessMessages;
      end;
      
      if FCancelled then
        Break;
    end;
    
  finally
    Printer.EndDoc;
    FProcessing := False;
  end;
end;

Utilizzo della finestra di dialogo di stampa

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
procedure TFormMain.btnPrintClick(Sender: TObject);
begin
  if not FileExists(edtPdfFile.Text) then
  begin
    ShowError('Please select a valid PDF file first.');
    Exit;
  end;
  
  // Setup print dialog
  PrintDialog.MinPage := 1;
  PrintDialog.MaxPage := Pdf.PageCount;
  PrintDialog.FromPage := 1;
  PrintDialog.ToPage := Pdf.PageCount;
  PrintDialog.Options := [poPageNums, poSelection];
  
  if PrintDialog.Execute then
  begin
    PrintPDFPages;
  end;
end;

Anteprima di stampa

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
procedure TFormMain.UpdatePreview;
var
  PreviewWidth, PreviewHeight: Integer;
  Scale: Double;
begin
  if not Pdf.Active then
    Exit;
    
  Pdf.PageNumber := FCurrentPreviewPage;
  
  // Calculate preview size to fit panel
  Scale := Min(
    pnlPreview.Width / Pdf.PageWidth,
    pnlPreview.Height / Pdf.PageHeight
  ) * (FCurrentZoom / 100);
  
  PreviewWidth := Round(Pdf.PageWidth * Scale);
  PreviewHeight := Round(Pdf.PageHeight * Scale);
  
  // Render preview
  FPreviewBitmap.Free;
  FPreviewBitmap := Pdf.RenderPage(
    0, 0, PreviewWidth, PreviewHeight,
    ro0, [reAnnotations], clWhite
  );
  
  // Display in image control
  imgPreview.Picture.Assign(FPreviewBitmap);
  
  // Update page info
  lblPageInfo.Caption := Format('Page %d of %d',
    [FCurrentPreviewPage, Pdf.PageCount]);
end;

Navigazione nell'anteprima

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
procedure TFormMain.btnFirstPageClick(Sender: TObject);
begin
  if Pdf.Active then
  begin
    FCurrentPreviewPage := 1;
    edtPreviewPage.Text := '1';
    UpdatePreview;
  end;
end;
 
procedure TFormMain.btnPrevPageClick(Sender: TObject);
begin
  if Pdf.Active and (FCurrentPreviewPage > 1) then
  begin
    Dec(FCurrentPreviewPage);
    edtPreviewPage.Text := IntToStr(FCurrentPreviewPage);
    UpdatePreview;
  end;
end;
 
procedure TFormMain.btnNextPageClick(Sender: TObject);
begin
  if Pdf.Active and (FCurrentPreviewPage < Pdf.PageCount) then
  begin
    Inc(FCurrentPreviewPage);
    edtPreviewPage.Text := IntToStr(FCurrentPreviewPage);
    UpdatePreview;
  end;
end;
 
procedure TFormMain.btnLastPageClick(Sender: TObject);
begin
  if Pdf.Active then
  begin
    FCurrentPreviewPage := Pdf.PageCount;
    edtPreviewPage.Text := IntToStr(FCurrentPreviewPage);
    UpdatePreview;
  end;
end;

Controllo zoom.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
procedure TFormMain.cmbZoomChange(Sender: TObject);
begin
  case cmbZoom.ItemIndex of
    0: FCurrentZoom := 50;
    1: FCurrentZoom := 75;
    2: FCurrentZoom := 100;
    3: FCurrentZoom := 125;
    4: FCurrentZoom := 150;
    5: FCurrentZoom := 200;
  else
    FCurrentZoom := 100;
  end;
  
  UpdatePreview;
end;

Gestione della rotazione delle pagine.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function GetPrintRotation(Rotation: TRotation): TRotation;
begin
  // Adjust rotation for printing (printer coordinate system)
  case Rotation of
    ro90:  Result := ro270;
    ro270: Result := ro90;
  else
    Result := Rotation;
  end;
end;
 
// Use in printing
Bitmap := Pdf.RenderPage(0, 0, Width, Height,
  GetPrintRotation(Pdf.PageRotation), [rePrinting]);

Salva/Carica impostazioni.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
procedure TFormMain.SaveSettings;
var
  Ini: TIniFile;
begin
  Ini := TIniFile.Create(FSettingsFile);
  try
    Ini.WriteInteger('Print', 'Quality', cmbQuality.ItemIndex);
    Ini.WriteInteger('Print', 'Scaling', cmbScaling.ItemIndex);
    Ini.WriteInteger('Print', 'Copies', spnCopies.Value);
    Ini.WriteBool('Print', 'Collate', chkCollate.Checked);
    Ini.WriteInteger('Preview', 'Zoom', FCurrentZoom);
  finally
    Ini.Free;
  end;
end;
 
procedure TFormMain.LoadSettings;
var
  Ini: TIniFile;
begin
  if FileExists(FSettingsFile) then
  begin
    Ini := TIniFile.Create(FSettingsFile);
    try
      cmbQuality.ItemIndex := Ini.ReadInteger('Print', 'Quality', 1);
      cmbScaling.ItemIndex := Ini.ReadInteger('Print', 'Scaling', 1);
      spnCopies.Value := Ini.ReadInteger('Print', 'Copies', 1);
      chkCollate.Checked := Ini.ReadBool('Print', 'Collate', False);
      FCurrentZoom := Ini.ReadInteger('Preview', 'Zoom', 100);
    finally
      Ini.Free;
    end;
  end;
end;

Casi d'uso.

  • Stampa di documenti. – Stampa di alta qualità di documenti PDF.
  • Stampa in batch. – Stampa di più documenti in sequenza.
  • Distribuzione di report. – Stampa report per la distribuzione.
  • Stampa di prova. – Stampa le bozze prima della produzione finale.

Conclusione.

La demo di "Print PDF" mostra come implementare la stampa professionale di file PDF utilizzando PDFium VCL. Dal semplice processo di stampa di una singola pagina alle operazioni di stampa avanzate con più copie, anteprima e impostazioni di qualità, questo componente offre tutto ciò di cui hai bisogno.

Il RenderPage metodo con il rePrinting questa opzione garantisce una qualità di stampa ottimale, mentre la funzione di anteprima consente agli utenti di verificare le impostazioni prima di stampare.

Aggiungi la stampa professionale di file PDF. integralo nelle tue applicazioni con. Componente Delphi PDFium..