Teknisk artikel

Skriva ut PDF-dokument med PDFium VCL i Delphi

· PDF-programmering

Att skriva ut PDF-dokument med korrekt rendering och korrekt skalning är ett vanligt krav. Den Skriv ut PDF demo visar hur man implementerar professionell PDF-utskrift med förhandsgranskning, sidval och kvalitetsalternativ med PDFium VCL Component.

Översikt

Denna omfattande demo ger en komplett utskriftslösning inklusive förhandsgranskning, val av sidintervall, kvalitetsinställningar, skalningsalternativ och aktuell filhistorik. Den visar bästa praxis för PDF-utskrift i Delphi-applikationer.

Nyckelfunktioner

  • Förhandsgranskning – Visuell förhandsgranskning före utskrift
  • Sidval – Skriv ut alla sidor eller specifika intervall
  • Kvalitetsinställningar – Utkast, normala och högkvalitativa lägen
  • Skalningsalternativ – Anpassa till sidan, krympa för att passa eller ingen skalning
  • Flera kopior – Skriv ut flera kopior med sortering
  • Framstegsspårning – Visuell återkoppling under utskrift
  • Senaste filer – Snabb åtkomst till tidigare utskrivna dokument

PDFium DLL-krav

Innan du kör ett PDFium VCL-program, se till att PDFium DLL-filerna är installerade:

  • pdfium32.dll / pdfium64.dll – Standardversioner (~5-6 MB)
  • pdfium32v8.dll / pdfium64v8.dll – Med V8 JavaScript-motor (~23-27 MB)

Installation: Kör PDFiumVCL\DLLs\CopyDlls.bat som administratör för att automatiskt kopiera DLL:erna till Windows systemkataloger.

Grundläggande PDF-utskrift

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;

Skriver ut bitmapp till skrivare

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;

Komplett utskrift med tillval

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;

Använda Print Dialog

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;

Förhandsgranskning

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;

Förhandsgranska navigering

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;

Zoomkontroll

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;

Hantera sidrotation

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]);

Spara/ladda in inställningar

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;

Användningsfall

  • Dokumentutskrift – Högkvalitativ utskrift av PDF-dokument
  • Batchutskrift – Skriv ut flera dokument i följd
  • Rapportfördelning – Skriv ut rapporter för distribution
  • Korrekturtryck – Skriv ut korrektur innan slutproduktion

Slutsats

Print PDF-demon visar hur man implementerar professionell PDF-utskrift med PDFium VCL. Från enkel enkelsidig utskrift till avancerade flerkopieringsjobb med förhandsgransknings- och kvalitetsinställningar, komponenten ger allt du behöver.

Den RenderPage metod med rePrinting alternativet säkerställer optimal utskrift för skrivare, medan förhandsgranskningsfunktionen låter användare verifiera sina inställningar före utskrift.

Lägg till professionell PDF-utskrift till dina applikationer med PDFium Delphi-komponent.