Search Results for

    Show / Hide Table of Contents

    Exporting Excel files to HTML (Delphi)

    Note

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

    Overview

    FlexCel can natively export an Excel file to HTML, in many formats like XHTML 1.1, HTML 3.2, HTML 4.1 strict or HTML 5.

    Concepts

    • HTML is a format that makes emphasis in semantics over presentation, and because of this reason the HTML file will not be as faithful to the original file as a PDF. PDF are targeted especially for handling presentation. Anyway, the output is very similar and in many ways better (and more cross-browser) than the HTML generated by Excel itself when saving to HTML.

    • 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

    UExportHTML.pas

    unit UExportHTML;
    
    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, UMailDialog,
      FlexCel.VCLSupport, FlexCel.Core, FlexCel.XlsAdapter, FlexCel.Render;
    
    type
      TFExportHTML = class(TForm)
        ToolBar1: TToolBar;
        ToolButton1: TToolButton;
        ToolButton2: TToolButton;
        ToolButton3: TToolButton;
        ToolButton4: TToolButton;
        ToolButton6: TToolButton;
        Actions: TActionList;
        ActionOpen: TAction;
        ActionExportAsHTML: TAction;
        ActionExportAsMHTML: 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;
        chPrintHeadings: TCheckBox;
        Panel3: TPanel;
        Label4: TLabel;
        cbImages: TCheckBox;
        cbComments: TCheckBox;
        cbHyperlinks: TCheckBox;
        cbHeadersFooters: TCheckBox;
        Panel4: TPanel;
        Label5: TLabel;
        cbOutlook2007: TCheckBox;
        cbIe6Png: TCheckBox;
        Panel5: TPanel;
        Label6: TLabel;
        cbLeft: TCheckBox;
        cbTop: TCheckBox;
        cbRight: TCheckBox;
        cbBottom: TCheckBox;
        Panel6: TPanel;
        Label7: TLabel;
        Label8: TLabel;
        cbHtmlVersion: TComboBox;
        cbFileFormat: TComboBox;
        Panel7: TPanel;
        Label9: TLabel;
        edTop: TEdit;
        Label10: TLabel;
        Label11: TLabel;
        edBottom: TEdit;
        Label12: TLabel;
        edLeft: TEdit;
        edRight: TEdit;
        Label13: TLabel;
        Label14: TLabel;
        Panel8: TPanel;
        Label15: TLabel;
        edSheetSeparator: TEdit;
        Panel9: TPanel;
        Label16: TLabel;
        edBodyStart: TEdit;
        Panel10: TPanel;
        Label17: TLabel;
        edImages: TEdit;
        Panel11: TPanel;
        edCss: TEdit;
        cbCss: TCheckBox;
        cbReplaceFonts: TCheckBox;
        chFormulaText: TCheckBox;
        ExportDialog: TSaveDialog;
        sbSVG: TCheckBox;
        Label18: TLabel;
        cbEmbedImages: TCheckBox;
        ToolbarImages_100Scale: TImageList;
        ToolbarImages_300Scale: TImageList;
        procedure ActionCloseExecute(Sender: TObject);
        procedure ActionOpenExecute(Sender: TObject);
        procedure cbSheetChange(Sender: TObject);
        procedure ActionExportAsHTMLExecute(Sender: TObject);
        procedure cbExportObjectChange(Sender: TObject);
        procedure cbCssClick(Sender: TObject);
        procedure ActionExportAsMHTMLExecute(Sender: TObject);
        procedure FormCreate(Sender: TObject);
      private
        Html: TFlexCelHtmlExport;
        procedure LoadSheetConfig;
        function HasFileOpen: Boolean;
        function LoadPreferences: Boolean;
        procedure HtmlFont(const sender: TObject; const e: THtmlFontEventArgs);
        function GenerateMHTML: string;
    
      public
        constructor Create(aOwner: TComponent); override;
        destructor Destroy; override;
        { Public declarations }
      end;
    
    var
      FExportHTML: TFExportHTML;
    
    implementation
    uses IOUtils, UFlexCelHDPI;
    
    {$R *.dfm}
    
    constructor TFExportHTML.Create(aOwner: TComponent);
    begin
      inherited;
      Html := TFlexCelHtmlExport.Create;
      Html.AllowOverwritingFiles := true;
      Html.HtmlFont := HtmlFont;
    end;
    
    destructor TFExportHTML.Destroy;
    begin
      Html.Workbook.Free;
      FreeAndNil(Html);
      inherited;
    end;
    
    procedure TFExportHTML.FormCreate(Sender: TObject);
    begin
      RegisterForHDPI(Self, nil);
    end;
    
    procedure TFExportHTML.HtmlFont(const sender: TObject; const e: THtmlFontEventArgs);
    begin
      if cbReplaceFonts.Checked then
      begin
        e.FontFamily := 'arial, sans-serif';
      end;
    end;
    
    
    procedure TFExportHTML.ActionCloseExecute(Sender: TObject);
    begin
      Close;
    end;
    
    procedure TFExportHTML.ActionExportAsHTMLExecute(Sender: TObject);
    var
      CssFileName: String;
      FileNameToOpen: String;
      SelectorPosition: TSheetSelectorPositionSet;
      GeneratedFiles: TArray<String>;
    begin
      if not HasFileOpen then
        exit;
    
      if not LoadPreferences then
        exit;
    
      if cbFileFormat.ItemIndex = 1 then
      begin
        Html.HtmlFileFormat := THtmlFileFormat.MHtml;
        ExportDialog.FilterIndex := 2;
      end else
      begin
        Html.HtmlFileFormat := THtmlFileFormat.Html;
        ExportDialog.FilterIndex := 1;
      end;
    
      if not ExportDialog.Execute then exit;
    
      Html.AllowOverwritingFiles := true;
      Html.SavedImagesFormat := THtmlImageFormat.Png;
      CssFileName := '';
      if cbCss.Checked then
        CssFileName := edCss.Text;
    
      FileNameToOpen := ExportDialog.FileName;
    
      case cbHtmlVersion.ItemIndex of
        0: Html.HtmlVersion := THtmlVersion.Html_32;
        2: Html.HtmlVersion := THtmlVersion.XHTML_10;
        3: Html.HtmlVersion := THtmlVersion.Html_5;
        else Html.HtmlVersion := THtmlVersion.Html_401;
      end;
    
      if edBodyStart.Text <> '' then
        Html.ExtraInfo.BodyStart := TArray<String>.Create(edBodyStart.Text);
    
      case cbExportObject.ItemIndex of
        0:
        begin
          SelectorPosition := [];
          if cbTop.Checked then
            SelectorPosition:= SelectorPosition + [TSheetSelectorPosition.Top];
    
          if cbLeft.Checked then
            SelectorPosition:= SelectorPosition + [TSheetSelectorPosition.Left];
    
          if cbBottom.Checked then
            SelectorPosition:= SelectorPosition + [TSheetSelectorPosition.Bottom];
    
          if cbRight.Checked then
            SelectorPosition:= SelectorPosition + [TSheetSelectorPosition.Right];
    
          Html.ExportAllVisibleSheetsAsTabs(TPath.GetDirectoryName(ExportDialog.FileName),
            TPath.GetFileNameWithoutExtension(ExportDialog.FileName),
            TPath.GetExtension(ExportDialog.FileName),
            edImages.Text, CssFileName, TStandardSheetSelector.Create(SelectorPosition), true);
    
          FileNameToOpen := TPath.Combine(TPath.GetDirectoryName(ExportDialog.FileName), TPath.GetFileNameWithoutExtension(ExportDialog.FileName));
          FileNameToOpen := TPath.Combine(FileNameToOpen, Html.Workbook.SheetName);
          FileNameToOpen := TPath.Combine(FileNameToOpen, TPath.GetExtension(ExportDialog.FileName));
        end;
        1:
        begin
          Html.ExportAllVisibleSheetsAsOneHtmlFile(ExportDialog.FileName, edImages.Text, CssFileName, edSheetSeparator.Text);
        end;
        2:
        begin
          begin
            Html.Export(ExportDialog.FileName, edImages.Text, CssFileName);
          end;
        end;
      end;
      GeneratedFiles := Html.GeneratedFiles.GetHtmlFiles;
      if Length(GeneratedFiles) = 0 then
      begin
        ShowMessage('Error: No file has been generated');
      end else
      begin
        if MessageDlg('Do you want to open the generated file?', mtConfirmation, [mbYes, mbNo], 0) = mrYes then
        begin
          ShellExecute(0, 'open', PCHAR(GeneratedFiles[0]), nil, nil, SW_SHOWNORMAL);
        end;
    
      end;
    
    end;
    
    procedure TFExportHTML.ActionExportAsMHTMLExecute(Sender: TObject);
    var
      dr: TModalResult;
    begin
      if not HasFileOpen then
        exit;
    
      if not Html.FixOutlook2007CssSupport then
      begin
        dr := MessageDlg('You have not checked "Outlook 2007 support". If any of your clients has Outlook express, you should turn this on.'#$000A#$000A'Use Outlook 2007 fix?',
             TMsgDlgType.mtWarning, [mbYes, mbNo, mbCancel], 0);
        if dr = mrCancel then
          exit;
    
        if dr = mrYes then
        begin
          cbOutlook2007.Checked := true;
          Html.FixOutlook2007CssSupport := true;
        end;
    
      end;
    
      MailDialog.GetMHTML := GenerateMHTML;
      MailDialog.ShowModal;
    end;
    
    procedure TFExportHTML.ActionOpenExecute(Sender: TObject);
    var
      Xls: TExcelFile;
      i: Int32;
    begin
      if not OpenDialog.Execute then exit;
    
      if Html.Workbook = nil then Html.Workbook := TXlsFile.Create;
      Html.Workbook.Open(OpenDialog.FileName);
      Caption := 'Export: ' + OpenDialog.FileName;
      Xls := Html.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 TFExportHTML.cbCssClick(Sender: TObject);
    begin
      edCss.Enabled := cbCss.Checked;
    end;
    
    procedure TFExportHTML.cbExportObjectChange(Sender: TObject);
    begin
      edSheetSeparator.Enabled := cbExportObject.ItemIndex = 1;
      cbTop.Enabled := cbExportObject.ItemIndex = 0;
      cbLeft.Enabled := cbExportObject.ItemIndex = 0;
      cbRight.Enabled := cbExportObject.ItemIndex = 0;
      cbBottom.Enabled := cbExportObject.ItemIndex = 0;
      cbSheet.Enabled := cbExportObject.ItemIndex = 2;
    end;
    
    procedure TFExportHTML.cbSheetChange(Sender: TObject);
    begin
      Html.Workbook.ActiveSheet := cbSheet.ItemIndex + 1;
      LoadSheetConfig;
    end;
    
    procedure TFExportHTML.LoadSheetConfig;
    var
      Xls: TExcelFile;
    begin
      Xls := Html.Workbook;
      chGridLines.Checked := Xls.PrintGridLines;
      chPrintHeadings.Checked := Xls.PrintHeadings;
      chFormulaText.Checked := Xls.ShowFormulaText;
    end;
    
    function TFExportHTML.HasFileOpen: Boolean;
    begin
      if Html.Workbook = nil then
      begin
        ShowMessage('You need to open a file first.');
        exit(false);
      end;
    
      Result := true;
    end;
    
    function TFExportHTML.LoadPreferences: Boolean;
    var
      Xls: TExcelFile;
    begin
      //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.
      try
        Xls := Html.Workbook;
    
         //Note: In this demo we will only apply this things to the active sheet.
         //If you want to apply the settings to all the sheets, you should loop in the sheets and change them here.
        Xls.PrintGridLines := chGridLines.Checked;
        Xls.PrintHeadings := chPrintHeadings.Checked;
        Xls.ShowFormulaText := chFormulaText.Checked;
        Html.PrintRangeLeft := StrToInt(edLeft.Text);
        Html.PrintRangeTop := StrToInt(edTop.Text);
        Html.PrintRangeRight := StrToInt(edRight.Text);
        Html.PrintRangeBottom := StrToInt(edBottom.Text);
    
        if (sbSVG.Checked) then Html.SavedImagesFormat := THtmlImageFormat.Svg else Html.SavedImagesFormat := THtmlImageFormat.Png;
        Html.EmbedImages := cbEmbedImages.Checked;
    
        Html.FixOutlook2007CssSupport := cbOutlook2007.Checked;
        Html.FixIE6TransparentPngSupport := cbIe6Png.Checked;
        Html.HidePrintObjects := [];
        if not cbImages.Checked then
          Html.HidePrintObjects:= Html.HidePrintObjects + [THidePrintObjects.Images];
    
        if not cbHyperlinks.Checked then
          Html.HidePrintObjects:= Html.HidePrintObjects + [THidePrintObjects.Hyperlynks];
    
        if not cbComments.Checked then
          Html.HidePrintObjects:= Html.HidePrintObjects + [THidePrintObjects.Comments];
    
        if not cbHeadersFooters.Checked then
          Html.HidePrintObjects:= Html.HidePrintObjects + [THidePrintObjects.Headers, THidePrintObjects.Footers];
    
      except
        on e: Exception do
          begin
            ShowMessage('Error: ' + e.Message);
            exit(false);
          end;
      end;
      Result := true;
    end;
    
    function TFExportHTML.GenerateMHTML: string;
    var
      ms: TBytesStream;
      writer: TStreamWriter;
      preambleLen: integer;
    begin
      LoadPreferences;
      Html.HtmlFileFormat := THtmlFileFormat.MHtml;
      Html.AllowOverwritingFiles := true;
      Html.SavedImagesFormat := THtmlImageFormat.Png;
      Html.HtmlVersion := THtmlVersion.Html_401;
      if edBodyStart.Text <> '' then
        Html.ExtraInfo.BodyStart := TArray<String>.Create(edBodyStart.Text);
    
      ms := TBytesStream.Create;
      try
        writer := TStreamWriter.Create(ms, TEncoding.UTF8);
        try
          Html.Export(writer, Html.Workbook.ActiveFileName, nil);
        finally
          FreeAndNil(writer);
        end;
        PreambleLen := Length(TEncoding.UTF8.GetPreamble);
        exit(TEncoding.UTF8.GetString(ms.Bytes, preambleLen, ms.Size - preambleLen));
      finally
        FreeAndNil(ms);
      end;
    end;
    
    
    end.
    

    UMailDialog.pas

    unit UMailDialog;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics,
      Controls, Forms, Dialogs, StdCtrls, ExtCtrls,
      IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,
      IdExplicitTLSClientServerBase, IdMessageClient, IdSMTPBase, IdSMTP, IdMessage,
      {$if CompilerVersion >= 23.0} System.UITypes, {$IFEND}
      IdIOHandler, IdIOHandlerSocket, IdIOHandlerStack, IdSSL, IdSSLOpenSSL, StrUtils;
    
    type
      TMailDialog = class(TForm)
        edFrom: TLabeledEdit;
        edTo: TLabeledEdit;
        edSubject: TLabeledEdit;
        edOutServer: TLabeledEdit;
        btnSend: TButton;
        btnCancel: TButton;
        Mailer: TIdSMTP;
        Msg: TIdMessage;
        edPort: TLabeledEdit;
        edUserName: TLabeledEdit;
        edPassword: TLabeledEdit;
        cbUseTLS: TCheckBox;
        SSLHandler: TIdSSLIOHandlerSocketOpenSSL;
        procedure btnSendClick(Sender: TObject);
        procedure FormCreate(Sender: TObject);
        procedure edFromExit(Sender: TObject);
        procedure cbUseTLSClick(Sender: TObject);
      private
        OriginalTo, OriginalFrom, OriginalServer: string;
        function ValidateFields: Boolean;
        procedure FillServer;
        procedure FillMsgBody;
        { Private declarations }
      public
        GetMHTML: TFunc<string>;
        { Public declarations }
      end;
    
    var
      MailDialog: TMailDialog;
    
    implementation
    
    {$R *.dfm}
    
    procedure TMailDialog.cbUseTLSClick(Sender: TObject);
    begin
      edPort.Visible := cbUseTLS.Checked;
      edUserName.Visible := cbUseTLS.Checked;
      edPassword.Visible := cbUseTLS.Checked;
    end;
    
    procedure TMailDialog.edFromExit(Sender: TObject);
    begin
     if (OriginalTo = edTo.Text) and (OriginalFrom <> edFrom.Text) then
      begin
        edTo.Text := edFrom.Text;
      end;
    
      FillServer;
      if edUserName.Text = '' then edUserName.Text := edFrom.Text;
    
    end;
    
    procedure TMailDialog.FillServer;
    var
      AtPos: Int32;
      Server: String;
    begin
      if (OriginalServer = edOutServer.Text) and (OriginalFrom <> edFrom.Text) then
      begin
        AtPos := Pos('@', edFrom.Text);
        if AtPos > 1 then
        begin
          Server := copy(edFrom.Text, AtPos + 1, Length(edFrom.Text));
          edOutServer.Text := 'smtp.' + Server;
        end;
    
      end;
    
    end;
    
    procedure TMailDialog.FormCreate(Sender: TObject);
    begin
      OriginalTo := edTo.Text;
      OriginalFrom := edFrom.Text;
      OriginalServer := edOutServer.Text;
    end;
    
    function TMailDialog.ValidateFields: Boolean;
    begin
      if OriginalFrom = edFrom.Text then
      begin
        ShowMessage('Please change the ''From'' field to the user you are using to send the email');
        edFrom.SetFocus;
        exit(false);
      end;
    
      if OriginalTo = edTo.Text then
      begin
        ShowMessage('Please change the ''TO'' field to the user you want to send the email');
        edTo.SetFocus;
        exit(false);
      end;
    
      if OriginalServer = edOutServer.Text then
      begin
        ShowMessage('Please change the ''Outgoing Mail Server'' field to the pop3 server you will use to send the email.');
        edOutServer.SetFocus;
        exit(false);
      end;
    
      Result := true;
    end;
    
    procedure TMailDialog.FillMsgBody;
    var
      p, p0: integer;
      s: string;
    begin
      //FlexCel returns both headers and body, as this is the MHTML standard. We need to separate
      //them to add headers to headers and body to body. Maybe other smtp component different from
      //indy could allow to just write the raw block.
    
      s := GetMHTML;
      p0 := 1;
    
      while true do
      begin
        p := PosEx(#13#10, s, p0);
        if (p < 1) or(p >= Length(s) - 3) then exit;
        Msg.Headers.Add(Copy(s, p0, p - p0));
        p0 := p + 2;
        if s[p0] = #13 then break; //double enter.
      end;
    
      Msg.Body.Text := copy(s, p0 + 2, Length(s));
    
    end;
    
    procedure TMailDialog.btnSendClick(Sender: TObject);
    begin
     if not ValidateFields then
        exit;
    
      if MessageDlg('Now we will try to send the email using the server ''' + edOutServer.Text +
         ''''#$000A + 'Note that this is a very simple implementation, and it might not work if the SMTP server needs to login. GMail accounts should work.',
         mtInformation,
         [mbOk, mbCancel], 0) <> mrOK then exit;
    
      Msg.Clear;
      Msg.NoEncode := true;
      Msg.Headers.Add('From: ' +  Trim(edFrom.Text));
      Msg.Recipients.Add.Text := Trim(edTo.Text);
      Msg.Headers.Add('Subject: ' + Trim(edSubject.Text));
    
      FillMsgBody;
      Mailer.Host := Trim(edOutServer.Text);
      if cbUseTLS.Checked then
      begin
        Mailer.Port := StrToInt(Trim(edPort.Text));
        Mailer.Username := Trim(edUserName.Text);
        Mailer.Password := Trim(edPassword.Text);
        Mailer.UseTLS := TIdUseTLS.utUseExplicitTLS;
      end
      else
      begin
        Mailer.Port := 25;
        Mailer.Username := '';
        Mailer.Password := '';
        Mailer.UseTLS := TIdUseTLS.utNoTLSSupport;
      end;
    
    
      try
        Mailer.Connect;
        try
          Mailer.Send(Msg);
        finally
          Mailer.Disconnect;
        end;
      except
        on ex: Exception do
          begin
            ShowMessage('Error trying to send the message: ' + ex.Message);
            exit;
          end;
      end;
      ShowMessage('Message has been sent. Please verify your JUNK folder or any filters, since it might be filtered as spam');
      ModalResult := mrOk;
    end;
    
    end.
    
    In This Article
    Back to top FlexCel Studio for VCL and FireMonkey v7.24
    © 2002 - 2025 tmssoftware.com