Search Results for

    Show / Hide Table of Contents

    Exporting Excel files to PDF (Delphi)

    Note

    This demo is available in your FlexCel installation at <FlexCel Install Folder>\Demo\Delphi\Modules\25.Printing and Exporting\30.ExportPdf and also at https:​//​github.​com/​tmssoftware/​TMS-​FlexCel.​VCL-​demos/​tree/​master/​Delphi/​Modules/​25.​Printing and Exporting/​30.​ExportPdf

    Overview

    FlexCel can natively export an Excel file to PDF, without needing to have Excel or Adobe Pdf installed.

    Concepts

    • FlexCel PDF output is not 100% identical to Excel output, and it can't be that way. But it is very similar, and this includes fonts, colors, margins, headers/footers/images, etc. It can print cells with multiple fonts, it can replace the macros on headers and footers (like "&CPage &P of &N"), export headers and hyperlinks, correctly export conditional formats and the list goes on.

    • Among the things that are not exported you can find:

      • ActiveX objects

      • 3D Charts (They will be rendered as 2d)

      • Not common AutoShapes (most used Autoshapes, as rectangles, rounded rectangles, ellipses, etc are exported)

    Files

    UExportPdf.pas

    unit UExportPdf;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics,
      Controls, Forms, Dialogs, ImgList, ActnList, StdCtrls,
      Tabs, Grids,ExtCtrls, ComCtrls, ToolWin,
      {$if CompilerVersion >= 23.0} System.UITypes, {$IFEND}
      ShellAPI,
      FlexCel.VCLSupport, FlexCel.Core, FlexCel.XlsAdapter, FlexCel.Render, FlexCel.Pdf;
    
    type
      TFExportPdf = class(TForm)
        ToolBar1: TToolBar;
        ToolButton1: TToolButton;
        ToolButton2: TToolButton;
        ToolButton3: TToolButton;
        ToolButton6: TToolButton;
        Actions: TActionList;
        ActionOpen: TAction;
        ActionExportAsPdf: TAction;
        ActionClose: TAction;
        OpenDialog: TOpenDialog;
        ToolbarImages: TImageList;
        ToolButton5: TToolButton;
        Panel1: TPanel;
        Label1: TLabel;
        cbExportObject: TComboBox;
        cbSheet: TComboBox;
        Label2: TLabel;
        Panel2: TPanel;
        Label3: TLabel;
        chGridLines: TCheckBox;
        chPrintLeft: TCheckBox;
        Panel3: TPanel;
        Label4: TLabel;
        Panel6: TPanel;
        Label7: TLabel;
        Panel7: TPanel;
        Label9: TLabel;
        edTop: TEdit;
        Label10: TLabel;
        Label11: TLabel;
        edBottom: TEdit;
        Label12: TLabel;
        edLeft: TEdit;
        edRight: TEdit;
        Label13: TLabel;
        Label14: TLabel;
        Panel9: TPanel;
        Label16: TLabel;
        cbConfidential: TCheckBox;
        chFormulaText: TCheckBox;
        ExportDialog: TSaveDialog;
        edHeader: TLabeledEdit;
        edFooter: TLabeledEdit;
        chLandscape: TCheckBox;
        chFitIn: TCheckBox;
        edHPages: TLabeledEdit;
        edVPages: TLabeledEdit;
        edZoom: TLabeledEdit;
        edl: TLabeledEdit;
        edt: TLabeledEdit;
        edh: TLabeledEdit;
        edr: TLabeledEdit;
        edb: TLabeledEdit;
        edf: TLabeledEdit;
        Panel4: TPanel;
        Label5: TLabel;
        cbFontMapping: TComboBox;
        chEmbed: TCheckBox;
        chSubset: TCheckBox;
        cbKerning: TCheckBox;
        Panel5: TPanel;
        Label6: TLabel;
        edSubject: TLabeledEdit;
        edAuthor: TLabeledEdit;
        edTitle: TLabeledEdit;
        Panel8: TPanel;
        Label8: TLabel;
        cbPdfType: TComboBox;
        cbVersion: TComboBox;
        cbTagged: TComboBox;
        Label15: TLabel;
        Label17: TLabel;
        Label18: TLabel;
        edLang: TLabeledEdit;
        ToolbarImages_100Scale: TImageList;
        ToolbarImages_300Scale: TImageList;
        ScrollBox1: TScrollBox;
        procedure ActionCloseExecute(Sender: TObject);
        procedure ActionOpenExecute(Sender: TObject);
        procedure ActionExportAsPdfExecute(Sender: TObject);
        procedure chFitInClick(Sender: TObject);
        procedure cbSheetChange(Sender: TObject);
        procedure cbExportObjectChange(Sender: TObject);
        procedure FormCreate(Sender: TObject);
      private
        Pdf: TFlexCelPdfExport;
        procedure LoadSheetConfig;
        function HasFileOpen: Boolean;
        function LoadPreferences: Boolean;
        procedure PdfExport_AfterGeneratePage(const sender: TObject;
          const e: TPageEventArgs);
    
      public
        constructor Create(aOwner: TComponent); override;
        destructor Destroy; override;
        { Public declarations }
      end;
    
    var
      FExportPdf: TFExportPdf;
    
    implementation
    uses IOUtils, UFlexCelHDPI;
    
    {$R *.dfm}
    
    constructor TFExportPdf.Create(aOwner: TComponent);
    begin
      inherited;
      Pdf := TFlexCelPdfExport.Create;
      Pdf.AllowOverwritingFiles := true;
      Pdf.AfterGeneratePage := PdfExport_AfterGeneratePage;
    end;
    
    destructor TFExportPdf.Destroy;
    begin
      Pdf.Workbook.Free;
      FreeAndNil(Pdf);
      inherited;
    end;
    
    
    procedure TFExportPdf.FormCreate(Sender: TObject);
    begin
      RegisterForHDPI(Self, nil);
    end;
    
    procedure TFExportPdf.ActionCloseExecute(Sender: TObject);
    begin
      Close;
    end;
    
    procedure TFExportPdf.ActionExportAsPdfExecute(Sender: TObject);
    var
      PdfStream: TFileStream;
    begin
      if not HasFileOpen then exit;
    
      if not LoadPreferences then exit;
    
      if not ExportDialog.Execute then exit;
    
      PdfStream := TFileStream.Create(exportDialog.FileName, fmCreate);
      try
        Pdf.BeginExport(PdfStream);
        if cbExportObject.ItemIndex = 0 then
        begin
          Pdf.PageLayout := TPageLayout.Outlines;  //To how the bookmarks when opening the file.
          Pdf.ExportAllVisibleSheets(false, TPath.GetFileNameWithoutExtension(exportDialog.FileName));
        end else
        begin
          Pdf.PageLayout := TPageLayout.None;
          Pdf.ExportSheet;
        end;
    
        Pdf.EndExport;
    
        if MessageDlg('Do you want to open the generated file?', mtConfirmation, [mbYes, mbNo], 0) = mrYes then
        begin
          ShellExecute(0, 'open', PCHAR(ExportDialog.FileName), nil, nil, SW_SHOWNORMAL);
        end;
    
      finally
        FreeAndNil(PdfStream);
      end;
    end;
    
    procedure TFExportPdf.ActionOpenExecute(Sender: TObject);
    var
      Xls: TExcelFile;
      i: integer;
    begin
      if not OpenDialog.Execute then exit;
    
      if Pdf.Workbook = nil then Pdf.Workbook := TXlsFile.Create;
      Pdf.Workbook.Open(OpenDialog.FileName);
      Caption := 'Export: ' + OpenDialog.FileName;
      Xls := Pdf.Workbook;
      cbSheet.Items.Clear;
      for i := 1 to Xls.SheetCount do
      begin
        cbSheet.Items.Add(Xls.GetSheetName(i));
      end;
    
      cbSheet.ItemIndex := Xls.ActiveSheet - 1;
      LoadSheetConfig;
    end;
    
    procedure TFExportPdf.cbExportObjectChange(Sender: TObject);
    begin
      cbSheet.Enabled := cbExportObject.ItemIndex <> 0;
    end;
    
    procedure TFExportPdf.cbSheetChange(Sender: TObject);
    begin
      Pdf.Workbook.ActiveSheet := cbSheet.ItemIndex + 1;
      LoadSheetConfig;
    end;
    
    procedure TFExportPdf.chFitInClick(Sender: TObject);
    begin
      edVPages.Enabled :=  chFitIn.Checked;
      edHPages.Enabled :=  chFitIn.Checked;
      edZoom.Enabled := not chFitIn.Checked;
    end;
    
    procedure TFExportPdf.LoadSheetConfig;
    var
      Xls: TExcelFile;
      m: TXlsMargins;
    begin
      Xls := Pdf.Workbook;
      chGridLines.Checked := Xls.PrintGridLines;
      chFormulaText.Checked := Xls.ShowFormulaText;
      chPrintLeft.Checked := TPrintOptions.LeftToRight in Xls.PrintOptions;
      edHeader.Text := Xls.PageHeader;
      edFooter.Text := Xls.PageFooter;
      chFitIn.Checked := Xls.PrintToFit;
      edHPages.Text := IntToStr(Xls.PrintNumberOfHorizontalPages);
      edVPages.Text := IntToStr(Xls.PrintNumberOfVerticalPages);
      edVPages.Enabled := chFitIn.Checked;
      edHPages.Enabled := chFitIn.Checked;
      edZoom.Enabled := not chFitIn.Checked;
      edZoom.Text := IntToStr(Xls.PrintScale);
      m := Xls.GetPrintMargins;
      edl.Text := FloatToStr(m.Left);
      edt.Text := FloatToStr(m.Top);
      edr.Text := FloatToStr(m.Right);
      edb.Text := FloatToStr(m.Bottom);
      edf.Text := FloatToStr(m.Footer);
      edh.Text := FloatToStr(m.Header);
      chLandscape.Checked :=  Xls.PrintLandscape;
    
      edAuthor.Text := Xls.DocumentProperties.GetStandardProperty(TPropertyId.Author);
      edTitle.Text := Xls.DocumentProperties.GetStandardProperty(TPropertyId.Title);
      edSubject.Text := Xls.DocumentProperties.GetStandardProperty(TPropertyId.Subject);
    
    end;
    
    function TFExportPdf.HasFileOpen: Boolean;
    begin
      if Pdf.Workbook = nil then
      begin
        ShowMessage('You need to open a file first.');
        exit(false);
      end;
    
      Result := true;
    end;
    
    function TFExportPdf.LoadPreferences: Boolean;
    var
      Xls: TExcelFile;
      m: TXlsMargins;
    begin
      try  //NOTE: THERE SHOULD BE *A LOT* MORE VALIDATION OF VALUES ON THIS METHOD. (For example, validate that margins are between bounds)
      // As this is a simple demo, they are not included.
        Xls := Pdf.Workbook;
        Xls.PrintGridLines := chGridLines.Checked;
        Xls.PageHeader := edHeader.Text;
        Xls.PageFooter := edFooter.Text;
        Xls.ShowFormulaText := chFormulaText.Checked;
        if chFitIn.Checked then
        begin
          Xls.PrintToFit := true;
          Xls.PrintNumberOfHorizontalPages := StrToInt(edHPages.Text);
          Xls.PrintNumberOfVerticalPages := StrToInt(edVPages.Text);
        end else
          Xls.PrintToFit := false;
    
        if chPrintLeft.Checked then
          Xls.PrintOptions:= Xls.PrintOptions + [TPrintOptions.LeftToRight] else
          Xls.PrintOptions:= Xls.PrintOptions - [TPrintOptions.LeftToRight];
    
        try
          Xls.PrintScale := StrToInt(edZoom.Text);
        except
            begin
              ShowMessage('Invalid Zoom');
              exit(false);
            end;
        end;
        m := TXlsMargins.Create;
        m.Left := StrToFloat(edl.Text);
        m.Top := StrToFloat(edt.Text);
        m.Right := StrToFloat(edr.Text);
        m.Bottom := StrToFloat(edb.Text);
        m.Footer := StrToFloat(edf.Text);
        m.Header := StrToFloat(edh.Text);
        Xls.SetPrintMargins(m);
        Pdf.PrintRangeLeft := StrToInt(edLeft.Text);
        Pdf.PrintRangeTop := StrToInt(edTop.Text);
        Pdf.PrintRangeRight := StrToInt(edRight.Text);
        Pdf.PrintRangeBottom := StrToInt(edBottom.Text);
        if chEmbed.Checked then
          Pdf.FontEmbed := TFontEmbed.Embed else
          Pdf.FontEmbed := TFontEmbed.None;
    
        if chSubset.Checked then
          Pdf.FontSubset := TFontSubset.Subset else
          Pdf.FontSubset := TFontSubset.DontSubset;
    
        Pdf.Kerning := cbKerning.Checked;
        case cbFontMapping.ItemIndex of
          0:
          begin
            Pdf.FontMapping := TFontMapping.ReplaceAllFonts;
          end;
          1:
          begin
            Pdf.FontMapping := TFontMapping.ReplaceStandardFonts;
          end;
          2:
          begin
            Pdf.FontMapping := TFontMapping.DontReplaceFonts;
          end;
        end;
    
        case cbPdfType.ItemIndex of
          0: Pdf.PdfType := TPdfType.Standard;
          1: Pdf.PdfType := TPdfType.PDFA1;
          2: Pdf.PdfType := TPdfType.PDFA2;
          3: Pdf.PdfType := TPdfType.PDFA3;
        end;
    
        case cbTagged.ItemIndex of
          0: Pdf.TagMode := TTagMode.Full;
          1: Pdf.TagMode := TTagMode.None;
        end;
    
        case cbVersion.ItemIndex of
          0: Pdf.PdfVersion := TPdfVersion.v14;
          1: Pdf.PdfVersion := TPdfVersion.v16;
        end;
    
    
        Pdf.Properties := TPdfProperties.Create(
                              edTitle.Text,
                              edAuthor.Text,
                              edSubject.Text,
                              '',
                              '',
                              edLang.Text);
    
        Xls.PrintLandscape := chLandscape.Checked;
      except
        on e: Exception do
          begin
            ShowMessage('Error: ' + e.Message);
            exit(false);
          end;
      end;
      Result := true;
    end;
    
    
    procedure TFExportPdf.PdfExport_AfterGeneratePage(const sender: TObject; const e: TPageEventArgs);
    var
      ABrush: TUIBrush;
      AFont: TUIFont;
      x0: RealNumber;
      y0: RealNumber;
      sf: TUISize;
    const
      s = 'Confidential';
    begin
      if not cbConfidential.Checked then
        exit;
    
      ABrush := TUISolidBrush.CreateNew(TUIColor.FromArgb($1E, $19, $19, $19));  //Red=Green=Blue is a shade of gray. Alpha=30 means it is transparent (255 is pure opaque, 0 is pure transparent).
      try
        AFont := TUIFont.CreateNew('Arial', $48);
        try
          x0 := ((e.DataFile.PageSize.Width * 72) / 100) / 2;  //PageSize is in inches/100, our coordinate system is in Points, that is inches/72
          y0 := ((e.DataFile.PageSize.Height * 72) / 100) / 2;
          sf := e.DataFile.MeasureString(s, AFont);
          e.DataFile.Rotate(x0, y0, $2D);
          e.DataFile.DrawString(s, AFont, ABrush, x0 - (sf.Width / 2), y0 + (sf.Height / 2));  //the y coord means the bottom of the text, and as the y axis grows down, we have to add sf.height/2 instead of substracting it.
        finally
          FreeAndNil(AFont);
        end;
      finally
        FreeAndNil(ABrush);
      end;
    end;
    
    
    end.
    
    In This Article
    Back to top FlexCel Studio for VCL and FireMonkey v7.24
    © 2002 - 2025 tmssoftware.com