Creating pdf files with the PDF API (Delphi)
Note
This demo is available in your FlexCel installation at <FlexCel Install Folder>\Demo\Delphi\Modules\10.API\A0.Creating Pdf Files With PDF API and also at https://github.com/tmssoftware/TMS-FlexCel.VCL-demos/tree/master/Delphi/Modules/10.API/A0.Creating Pdf Files With PDF API
Overview
Even when FlexCel is not a full featured PDF package, it does have a basic PDF API that you can use to create PDF files from scratch.
Concepts
How to create a PDF file using FlexCel's internal PDF API. The API is very similar to GDI+, and allows you to use a PDF "Canvas" where you can draw things in. To use the API, you need to use the class TPdfWriter
The PDF API on FlexCel is designed to support exporting Excel documents to PDF using TFlexCelPdfExport. But you can use the same API TFlexCelPdfExport uses to create your own PDF files with code.
Files
UPDFAPI.pas
unit UPDFAPI;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, UPaths,
Dialogs, StdCtrls, FlexCel.VCLSupport, FlexCel.Core, FlexCel.Pdf,
{$if CompilerVersion >= 23.0} System.UITypes, {$IFEND}
ShellAPI;
type
TFPDFAPI = class(TForm)
Memo1: TMemo;
btnCreateFile: TButton;
SaveDialog: TSaveDialog;
procedure btnCreateFileClick(Sender: TObject);
private
procedure CreateFile;
procedure OpenFile;
end;
var
FPDFAPI: TFPDFAPI;
implementation
uses Generics.Collections;
{$R *.dfm}
type
TUIBrushes = class //a small class to cache the brushes and free them all.
private
Brushes: TObjectDictionary<TUIColor, TUIBrush>;
Pens: TObjectDictionary<TUIColor, TUIPen>;
public
constructor Create;
destructor Destroy; override;
function GetBrush(const Color: TUIColor): TUIBrush;
function GetPen(const Color: TUIColor): TUIPen;
end;
procedure TFPDFAPI.btnCreateFileClick(Sender: TObject);
begin
CreateFile;
OpenFile;
end;
procedure TFPDFAPI.CreateFile;
var
pdf: TPdfWriter;
fStream: TFileStream;
f: TUIFont;
f2: TUIFont;
points: TArray<TUIPointF>;
Coords: TUIRectangle;
Gradient: TUIBrush;
Img: TUIImage;
Brushes: TUIBrushes;
Underline: TUITextDecoration;
begin
if not SaveDialog.Execute then exit;
Underline := TUITextDecoration.Create(TUIUnderline.Single);
pdf := TPdfWriter.Create;
try
fStream := TFileStream.Create(SaveDialog.FileName, fmCreate);
try
Brushes := TUIBrushes.Create;
try
pdf.Compress := true;
pdf.BeginDoc(fStream);
pdf.YAxisGrowsDown := true; //To keep it compatible with GDI+
f := TUIFont.CreateNew('times new roman', 22.5, [TUIFontStyle.fsItalic]);
try
f2 := TUIFont.CreateNew('Arial', 12, [TUIFontStyle.fsItalic]);
try
pdf.SaveState;
pdf.ClipPolygon(
TArray<TUIPointF>.Create(
TUIPointF.Create(50, 50),
TUIPointF.Create(180, 50),
TUIPointF.Create(50, 250),
TUIPointF.Create(50, 50)), true);
pdf.DrawAndFillPolygon(Brushes.GetPen(Colors.Aqua), Brushes.GetBrush(Colors.BlueViolet),
TArray<TUIPointF>.Create(
TUIPointF.Create(10, 10),
TUIPointF.Create(300, 10),
TUIPointF.Create(50, 300),
TUIPointF.Create(10, 10)
));
pdf.RestoreState;
pdf.DrawString('This is the first line on a test of many lines.', f, Underline, Brushes.GetBrush(Colors.Navy), 100, 100);
pdf.DrawString('Some unicode: '#$0E2A#$0E27#$0E31#$0E2A#$0E14#$0E35, f, Underline, Brushes.GetBrush(Colors.ForestGreen), 100, 200);
pdf.DrawString('More lines here!', f, Underline, Brushes.GetBrush(Colors.ForestGreen), 200, 300);
pdf.DrawString('And this is the last line.', f, Underline, Brushes.GetBrush(Colors.Black), 200, 400);
pdf.Properties.Author := 'Adri'#$00E1'n';
pdf.Properties.Title := 'This is a test of FlexCel Api';
pdf.Properties.Keywords := 'test'#$000A'flexcel'#$000A'api';
pdf.NewPage;
pdf.SaveState;
pdf.Rotate(200, 100, 45);
pdf.DrawString('Some rotated test', f, Underline, Brushes.GetBrush(Colors.Black), 200, 200);
pdf.RestoreState;
pdf.DrawString('Some NOT rotated text', f, Underline, Brushes.GetBrush(Colors.Black), 200, 200);
pdf.DrawString('Hello from FlexCel!', f2, Brushes.GetBrush(Colors.Black), 200, 50);
points := TArray<TUIPointF>.Create(TUIPointF.Create(200, 100), TUIPointF.Create(200, 50), TUIPointF.Create(500, 50), TUIPointF.Create(700, 100));
pdf.DrawLines(Brushes.GetPen(Colors.DarkOrchid), points);
Coords := TUIRectangle.Create(100, 300, 100, 100);
Gradient := TUILinearGradientBrush.CreateNew(Coords, Colors.Red, Colors.Blue, 0, false);
try
pdf.DrawAndFillRectangle(Brushes.GetPen(Colors.Red), Gradient, 100, 300, 100, 100);
finally
FreeAndNil(Gradient);
end;
pdf.DrawRectangle(Brushes.GetPen(Colors.DarkSlateBlue), 100, 300, 50, 50);
pdf.DrawLine(Brushes.GetPen(Colors.Black), 100, 300, 200, 400);
Img := TUIImage.FromFile(DataFolder + 'test.jpg');
try
pdf.DrawImage(Img, TUIRectangle.Create(200, 300, 200, 150), nil);
finally
FreeAndNil(Img);
end;
pdf.IntersectClipRegion(TUIRectangle.Create(100, 100, 50, 50));
pdf.FillRectangle(Brushes.GetBrush(Colors.DarkTurquoise), 100, 100, 100, 100);
pdf.EndDoc;
finally
FreeAndNil(f2);
end;
finally
FreeAndNil(f);
end;
finally
FreeAndNil(Brushes);
end;
finally
FreeAndNil(fStream);
end;
finally
FreeAndNil(pdf);
end;
end;
procedure TFPDFAPI.OpenFile;
begin
if MessageDlg('Do you want to open the generated file?', mtConfirmation, [mbYes, mbNo], 0) = mrYes then
begin
ShellExecute(0, 'open', PCHAR(SaveDialog.FileName), nil, nil, SW_SHOWNORMAL);
end;
end;
{ TUIBrushes }
function TUIBrushes.GetBrush(const Color: TUIColor): TUIBrush;
begin
if Brushes.TryGetValue(Color, Result) then exit;
Result := TUISolidBrush.CreateNew(Color);
Brushes.Add(Color, Result);
end;
function TUIBrushes.GetPen(const Color: TUIColor): TUIPen;
begin
if Pens.TryGetValue(Color, Result) then exit;
Result := TUIPen.CreateNew(Color);
Pens.Add(Color, Result);
end;
constructor TUIBrushes.Create;
begin
Brushes := TObjectDictionary<TUIColor, TUIBrush>.Create([doOwnsValues]);
Pens := TObjectDictionary<TUIColor, TUIPen>.Create([doOwnsValues]);
end;
destructor TUIBrushes.Destroy;
begin
Pens.Free;
Brushes.Free;
inherited;
end;
end.