Skip to content

PDF Library

To get started with the PDF library, add the FMX.TMSFNCPDFLib, VCL.TMSFNCPDFLib, LCLTMSFNCPDFLib or WEBLib.TMSFNCPDFLib depending on the chosen framework. The PDF library class is called TTMSFNCPDFLib, and the code is shareable between the four supported frameworks.

Starting a new document

Starting a new document can be file-based, or TMemoryStream-based. To start a new document, call the BeginDocument function. The BeginDocument always needs to be paired with EndDocument, which is responsible for writing the contents to a file or TMemoryStream. When the AFileName parameter in the BeginDocument call is empty, the contents will be written to a TMemoryStream, returned by the EndDocument call. The EndDocument call also has an additional parameter to allow opening the generated PDF file in the default PDF reader application. This only occurs when the file exists and the BeginDocument has received a valid AFileName parameter.

procedure TForm1.GeneratePDF(AFileName: string);
var
  p: TTMSFNCPDFLib;
begin
  p := TTMSFNCPDFLib.Create;
  try
    p.BeginDocument(AFileName);
    p.EndDocument;
  finally
    p.Free;
  end;
end;

Adding pages

Adding pages can be done by calling the NewPage function. The NewPage is responsible for starting a new page content stream on which the graphics / text can be written. Each NewPage call will clear the content buffer and allow you to start with new text and graphics. Please note though that all appearance settings such as fill, stroke and font will be preserved, so starting a new page will allow you to continue in the same appearance settings as the previous page. When the NewPage call is missing, the EndDocument call automatically throws an error indicating a new page needs to be added.

Pages can also be inserted at a specific position using InsertPage(APageIndex: Integer). The GetPageCount function returns the total number of pages in the document, and GetPageIndex returns the zero-based index of the current page.

procedure TForm1.GeneratePDF(AFileName: string);
var
  p: TTMSFNCPDFLib;
begin
  p := TTMSFNCPDFLib.Create;
  try
    p.BeginDocument(AFileName);
    p.NewPage;
    p.EndDocument;
  finally
    p.Free;
  end;
end;

Drawing content on a page

After adding a new page, the page can be filled with content such as HTML formatted text, plain text as well as some basic drawing primitives such as rectangles, circles and lines. The PDF graphics engine is a separate interface implementation that allows you to pass a reference to this interface. This has the advantage that it blocks access to the main pdf library, to avoid document / page corruption.

To start drawing content, the pdf library has a Graphics property that provides access to the drawing functionality. As a simple example, the following code exports a single-page PDF with a horizontal gray line.

Drawing content on a page

Please note that the Header and Footer text are added by default. The look and feel and text can be configured separately with a series of Header and Footer properties.

The appearance of the line in the above PDF export is controlled via the Stroke property. The stroke property supports setting the Color, Width and Kind. The Kind property is used to change between a solid, dashed or dotted line, or to completely turn off line drawing. The Stroke property is applied to each primitive that is drawn. The code below changes the appearance of the line to be thicker, have a different kind and color. (Note that most type values and constants can be found in the TTMSFNCGraphics class unit).

procedure TForm1.GeneratePDF(AFileName: string);
var
  p: TTMSFNCPDFLib;
begin
  p := TTMSFNCPDFLib.Create;
  try
    p.BeginDocument(AFileName);
    p.NewPage;
    p.Graphics.Stroke.Color := gcRed;
    p.Graphics.Stroke.Width := 3;
    p.Graphics.Stroke.Kind := gskDashDotDot;
    p.Graphics.DrawLine(PointF(10, 50), PointF(100, 50));
    p.EndDocument(True);
  finally
    p.Free;
  end;
end;
Drawing content on a page1

When keeping the above configuration for stroke and adding code to draw a rectangle instead, the stroke properties are also applied to the rectangle. The difference between a line is that a rectangle is a path shape, and a path can also be filled. The fill is controlled with the Fill property and supports horizontal and vertical gradients.

procedure TForm1.GeneratePDF(AFileName: string);
var
  p: TTMSFNCPDFLib;
begin
  p := TTMSFNCPDFLib.Create;
  try
    p.BeginDocument(AFileName);
    p.NewPage;
    p.Graphics.Stroke.Color := gcRed;
    p.Graphics.Stroke.Width := 3;
    p.Graphics.Stroke.Kind := gskDashDotDot;
    p.Graphics.DrawRectangle(RectF(10, 50, 100, 150));
    p.EndDocument(True);
  finally
    p.Free;
  end;
end;

Drawing content on a page2

Applying a gradient is done through the Fill property as demonstrated in the following sample.

procedure TForm1.GeneratePDF(AFileName: string);
var
  p: TTMSFNCPDFLib;
begin
  p := TTMSFNCPDFLib.Create;
  try
    p.BeginDocument(AFileName);
    p.NewPage;
    p.Graphics.Stroke.Color := gcRed;
    p.Graphics.Stroke.Width := 3;
    p.Graphics.Stroke.Kind := gskDashDotDot;
    p.Graphics.Fill.Kind := gfkGradient;
    p.Graphics.Fill.Color := gcBlue;
    p.Graphics.Fill.ColorTo := gcOrange;
    p.Graphics.DrawRectangle(RectF(10, 50, 100, 150));
    p.EndDocument(True);
  finally
    p.Free;
  end;
end;
Drawing content on a page3

As already mentioned, the rectangle, circle and line drawing functionality is based on paths. The pdf library also exposes a set of drawing calls to construct your own path. Below is a sample of drawing a star shape filled with a gradient fill and a dotted stroke.

procedure TForm1.GeneratePDF(AFileName: string);
var
  p: TTMSFNCPDFLib;
  st: TPointF;
  rad, angle, x, y: Single;
  I: Integer;
begin
  p := TTMSFNCPDFLib.Create;
  try
    p.BeginDocument(AFileName);
    p.NewPage;
    p.Graphics.Stroke.Color := gcBlue;
    p.Graphics.Stroke.Width := 1;
    p.Graphics.Stroke.Kind := gskDot;
    p.Graphics.Fill.Kind := gfkGradient;
    p.Graphics.Fill.Orientation := gfoHorizontal;
    p.Graphics.Fill.Color := gcLightcyan;
    p.Graphics.Fill.ColorTo := gcSteelblue;

    st := PointF(100, 100);
    rad := 75;
    angle := 0;
    x := rad * Sin(angle * Pi / 5) + st.X;
    y := rad * Cos(angle * PI / 5) + st.Y;
    p.Graphics.DrawPathBegin;
    p.Graphics.DrawPathMoveToPoint(PointF(x, y));

    for I := 1 to 5 do
    begin
      x := rad * sin((i * 4 * pi + angle) / 5) + st.X;
      y := rad * cos((i * 4 * pi + angle) / 5) + st.Y;
      p.Graphics.DrawPathAddLineToPoint(PointF(x, y));
    end;
    p.Graphics.DrawPathClose;
    p.Graphics.DrawPathEnd;
    p.Graphics.DrawRestoreState;

    p.EndDocument(True);
  finally
    p.Free;
  end;
end;

Drawing content on a page4

Path drawing modes

The DrawPathEnd call accepts a DrawingMode parameter of type TTMSFNCPDFGraphicsLibPathDrawingMode that controls how the path is rendered:

Value Description
dmPathFill Fill the path using the non-zero winding rule
dmPathEOFill Fill the path using the even-odd rule
dmPathStroke Stroke the path outline only
dmPathEOStroke Stroke using the even-odd rule
dmPathFillStroke Fill and stroke (default)
dmPathEOFillStroke Fill (even-odd) and stroke

Clipping paths

A path can be used as a clipping mask by calling DrawPathBeginClip instead of DrawPathBegin, then closing with DrawPathEndClip. All subsequent drawing is clipped to the defined path until the graphics state is restored with DrawRestoreState.

Linear gradient paths

To fill a path with a linear gradient instead of a solid fill, replace DrawPathEnd with DrawPathEndLinearGradient(StartPoint, EndPoint: TPointF). The gradient transitions from Fill.Color at StartPoint to Fill.ColorTo at EndPoint.

Transforms

The current transformation matrix can be changed with DrawSetTransform. Two overloads are available: one accepts individual matrix elements (m11, m12, m21, m22, dx, dy: Double), and one accepts a TTMSFNCGraphicsMatrix value directly. Call DrawSaveState before applying a transform and DrawRestoreState afterwards to scope the effect.

Clearing a region

DrawClear(Rect: TRectF) erases the content inside the given rectangle by painting it with the background color.

Drawing Text

Drawing text on a PDF page is done via the DrawText function. The DrawText has a set of parameters to allow drawing wordwrapped text in a rectangle, or simply as-is at a specific position.

The DrawText function has a set of overloads that also supports column drawing. Each call to DrawText returns a value that can either contain the calculated text rectangle or the amount of left-over characters after an overflow is detected when drawing text in a column.

The font that is used when drawing text can be controlled separately via the Font property. With this property, the font name, size, color and style can be set.

procedure TForm1.GeneratePDF(AFileName: string);
var
  p: TTMSFNCPDFLib;
begin
  p := TTMSFNCPDFLib.Create;
  try
    p.BeginDocument(AFileName);
    p.NewPage;
    p.Graphics.Font.Name := 'Segoe UI';
    p.Graphics.Font.Size := 16;
    p.Graphics.Font.Color := gcRed;
    p.Graphics.Font.Style := [TFontStyle.fsBold];
    p.Graphics.DrawText('Hello World !', PointF(10, 50));
    p.EndDocument(True);
  finally
    p.Free;
  end;
end;

Drawing Text

The above sample draws a 16 point single-line text in a red color with a bold style. The supported fonts in a PDF is based on the operating system font set on which the PDF is generated. If a specific font or a font name and style combination is not found, the font will fall back on one of the entries specified in the FontFallBackList property. The FontFallBackList is already initialized with a limited set of default operating system fonts, but you can easily add your own fonts, if they are installed and available on the operating system on which the PDF is generated.

The pdf engine recognizes the Delphi carriage return(#13) and line feed(#10) combination in order to break text in lines. To break the above "Hello World !" in 2 lines add the #13#10 combination.

procedure TForm1.GeneratePDF(AFileName: string);
var
  p: TTMSFNCPDFLib;
begin
  p := TTMSFNCPDFLib.Create;
  try
    p.BeginDocument(AFileName);
    p.NewPage;
    p.Graphics.Font.Name := 'Segoe UI';
    p.Graphics.Font.Size := 16;
    p.Graphics.Font.Color := gcRed;
    p.Graphics.Font.Style := [TFontStyle.fsBold];
    p.Graphics.DrawText('Hello'#13#10'World !', RectF(10, 50, 150, 100));
    p.EndDocument(True);
  finally
    p.Free;
  end;
end;

Drawing Text1

If you are not using #13#10 in your text, but want to automatically wordwrap text based on the width of a rectangle then you can change the drawing functionality to add a TRectF parameter instead of a TPointF. The following sample draws 3 different lines of text in the same rectangle. As the text length changes, the text is automatically wordwrapped before the width of the rectangle is reached.

procedure TForm1.GeneratePDF(AFileName: string);
var
  p: TTMSFNCPDFLib;
  r: TRectF;
begin
  p := TTMSFNCPDFLib.Create;
  try
    p.BeginDocument(AFileName);
    p.NewPage;
    p.Graphics.Font.Name := 'Arial';
    p.Graphics.Fill.Color := gcNull;
    r := RectF(10, 50, 100, 100);
    p.Graphics.DrawRectangle(r);
    p.Graphics.DrawText('A single line', r);
    r := RectF(10, 105, 100, 155);
    p.Graphics.DrawRectangle(r);
    p.Graphics.DrawText('This is a single line', r);
    r := RectF(10, 160, 100, 210);
    p.Graphics.DrawRectangle(r);
    p.Graphics.DrawText('This is a single line, with more text', r);
    p.EndDocument(True);
  finally
    p.Free;
  end;
end;

Drawing Text2

As already mentioned, the PDF library also supports drawing text in one or multiple columns. If the end of a column is reached, and the drawing call specifies multiple columns, the text is automatically drawn in the next available column. Below is a sample that demonstrates this based on a long text drawn in 3 columns. The first drawing sets a font of 8 points which draws the text completely in the first column. As the font size increases, more columns are used.

procedure TForm1.GeneratePDF(AFileName: string);
var
  p: TTMSFNCPDFLib;
  s: string;
begin
  p := TTMSFNCPDFLib.Create;
  try
    s := 'Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry''s standard dummy'+
      'text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. '+
      'It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It'+
      ' was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with des'+
      'ktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.';
    p.BeginDocument(AFileName);
    p.NewPage;
    p.Graphics.Font.Name := 'Arial';
    p.Graphics.Font.Size := 8;
    p.Graphics.Fill.Color := gcNull;
    p.Graphics.DrawText(s, RectF(10, 50, 500, 400), 3);
    p.EndDocument(True);
  finally
    p.Free;
  end;
end;

Drawing Text3

When modifying the same sample and choosing a different font size, the text is flowed into the next column.

procedure TForm1.GeneratePDF(AFileName: string);
var
  p: TTMSFNCPDFLib;
  s: string;
  r: TRectF;
begin
  p := TTMSFNCPDFLib.Create;
  try
    s := 'Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry''s standard dummy'+
      'text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. '+
      'It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It'+
      ' was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with des'+
      'ktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.';
    p.BeginDocument(AFileName);
    p.NewPage;
    p.Graphics.Font.Name := 'Arial';
    p.Graphics.Font.Size := 14;
    p.Graphics.Fill.Color := gcNull;
    r := RectF(10, 50, 500, 400);
    p.Graphics.DrawRectangle(r);
    p.Graphics.DrawText(s, r, 3);
    p.EndDocument(True);
  finally
    p.Free;
  end;
end;
Drawing Text4

When the rectangle is not large enough to contain all text, or the amount of columns specified does not suffice for displaying all of the text, the DrawText function returns a value of the amount of characters that are not drawn. Each DrawText call has an additional parameter to calculate the text. In this case, the method also returns a TRectF or Integer parameter but does not actually draw the text. In particular for the DrawText functionality that has the ability to draw text in multiple columns, you can increase the width/height or amount of columns in a while loop, until the character overflow count is 0. This is demonstrated in the next sample. Note that this sample shows the original requested rectangle, and the rectangle necessary for displaying all text after calculating the amount of overflow characters.

The sample indicates the original requested rectangle to draw the text in blue and the actual rectangle calculated with detection of character overflow in red.

Drawing Text5

The PDF library also supports HTML formatted text drawing. HTML formatted text is only available for drawing at a specific position or wordwrapped in a specific rectangle. Character overflow detection is not supported for HTML formatted text drawing. Below is a sample that draws the above text with HTML formatting applied.

procedure TForm1.GeneratePDF(AFileName: string);
var
  p: TTMSFNCPDFLib;
  s: string;
  r: TRectF;
begin
  p := TTMSFNCPDFLib.Create;
  try
    s := 'Lorem Ipsum is simply <b>dummy</b> text of the printing and typesetting industry. Lorem Ipsum has been the industry''s standard dummy'+
      'text ever since the 1500s, when an <i><font color="gcOrange">unknown printer took a galley</font></i> of type and scrambled it to make a type specimen book. '+
      'It has survived not only five <font size="16" color="gcRed">centuries</font>, but also the <sup>leap</sup> <sub>into</sub> <u>electronic</u> typeset'+
      'ting, <br><br>remaining essentially <font color"gcYellow" face="Comic Sans MS" bgcolor="gcBlue"><s>unchanged</s></font>. It'+
      ' was popularised in the 1960s with the <font size="12"><a href="http://www.tmssoftware.com">release</a></font> of Letraset sheets containing Lorem Ipsum passages, and more recently with des'+
      'ktop publishing software like <font bgcolor="gcSteelBlue" color="gcWhite">Aldus PageMaker</font> including versions of Lorem Ipsum.';
    p.BeginDocument(AFileName);
    p.NewPage;
    p.Graphics.Font.Name := 'Arial';
    p.Graphics.Font.Size := 10;
    p.Graphics.Fill.Color := gcNull;
    r := RectF(10, 50, 300, 400);
    p.Graphics.DrawHTMLText(s, r);
    p.EndDocument(True);
  finally
    p.Free;
  end;
end;

Drawing Text6

The above code renders the HTML formatted text in a rectangle with wordwrapping, but can easily be rendered as-is starting from a specific position, and then only breaks the text on the <BR> tag. The HTML formatted text is based on the Mini HTML rendering engine.

Each DrawText or DrawHTMLText call returns a TRectF containing the text width/height or character count overflow. These calculations can also be retrieved with the CalculateText and CalculateHTMLText calls. To calculate overflow without drawing, use CalculateTextOverflow(Text, Rect, Columns).

Text alignment

The Graphics.Alignment property controls the horizontal alignment of text drawn with DrawText. It accepts a TTMSFNCGraphicsTextAlign value: gtaLeading (left, default), gtaCenter, or gtaTrailing (right).

Multiline alignment with HTML

If drawing multiline text using DrawHTMLText or passing an HTML text to DrawText with the ASupportsHTML parameter enabled, use a <p> tag instead of relying on Graphics.Alignment.

Line break mode

The Graphics.LineBreakMode property controls how text is handled when it overflows its bounds:

Value Description
bmLineBreakModeWordWrap Wrap at word boundaries (default)
bmLineBreakModeCharacterWrap Wrap at any character
bmLineBreakModeClip Clip text at the boundary
bmLineBreakModeHeadTruncation Truncate at the start
bmLineBreakModeMiddleTruncation Truncate in the middle
bmLineBreakModeTailTruncation Truncate at the end

Currently these options are fully supported on macOS and iOS. It has limited support (bmLineBreakModeWordWrap and bmLineBreakModeCharacterWrap) in the rest of the platforms.

Line height

The Graphics.LineHeightFactor property scales the vertical spacing between lines. Call Graphics.LineHeightFactorResetToDefault to restore the default platform specific spacing.

URL font

The Graphics.URLFont property controls the appearance of hyperlinks rendered inside HTML text (anchor <a href> tags). Its properties mirror those of Graphics.Font.

Font Embedding

By default, each font that is used in the PDF library is embedded to make sure the PDF is readable on other operating systems. This means that for the rendered characters, a font subset is created and included to make sure the size of the PDF file is as small as possible. If the PDF file is created for printing purposes on the operating system on which it is generated, you could consider turning off font embedding, to have even smaller PDF files and speed up the creation process. Font embedding can be controlled with the EmbedFonts property.

The EmbedFontType property controls which font embedding strategy is used:

Value Description
eftNative Use the platform's native font embedding (default)
eftCustom Use the custom TMS cross-platform font embedding

On Android, a font file can be loaded explicitly by setting Graphics.Font.FileName to the full path of an external TTF file. This is useful when the desired font is not registered in the system font directory.

Images

The PDF library supports drawing images at a specific position or with optional stretching and aspect ratio in a rectangle. To draw images, you can use the DrawImage, DrawImageFromFile or DrawImageWithName functions. The first method takes an existing image object, the second method takes an existing image file and the last method requires assigning a BitmapContainer and then uses the ABitmapName parameter to find & draw the image on the PDF page canvas. Below is a sample that demonstrates these three ways of adding images.

procedure TForm1.GeneratePDF(AFileName: string);
var
  p: TTMSFNCPDFLib;
  MyImage: TBitmap;
begin
  p := TTMSFNCPDFLib.Create;
  MyImage := TBitmap.Create;
  try
    p.BitmapContainer := TMSFNCBitmapContainer1;
    p.BeginDocument(AFileName);
    p.NewPage;
    p.Graphics.Font.Name := 'Arial';
    p.Graphics.Font.Size := 8;
    p.Graphics.Fill.Color := gcNull;
    p.Graphics.DrawImageWithName('MyImage', PointF(10, 50));
    p.Graphics.DrawImageFromFile('MyImage.jpg', PointF(160, 50));
    MyImage.LoadFromFile('MyImage.jpg');
    p.Graphics.DrawImage(MyImage, PointF(310, 50));
    p.Graphics.DrawText('Rendering from image container', PointF(10, 100));
    p.Graphics.DrawText('Rendering from memory image', PointF(160, 100));
    p.Graphics.DrawText('Rendering from file', PointF(310, 100));
    p.EndDocument(True);
  finally
    MyImage.Free;
    p.Free;
  end;
end;

Images

Assigning an image container can also be used to render images that are added through the IMG tag. This is demonstrated below, based on the HTML formatted text sample.

procedure TForm1.GeneratePDF(AFileName: string);
var
  p: TTMSFNCPDFLib;
  s: string;
  r: TRectF;
begin
  p := TTMSFNCPDFLib.Create;
  try
    s := 'Lorem Ipsum is simply <b>dummy</b> text of the printing and typesetting industry. Lorem Ipsum has been the industry''s standard dummy'+
      'text ever since the 1500s, when an <i><font color="gcOrange">unknown printer took a galley</font></i> of type and scrambled it to make a type specimen book. '+
      'It has survived not only five <font size="16" color="gcRed">centuries</font>, but also the <sup>leap</sup> <sub>into</sub> <u>electronic</u> typeset'+
      'ting, <br><img src="TMSLogo.ico"/>remaining essentially <font color"gcYellow" face="Comic Sans MS" bgcolor="gcBlue"><s>unchanged</s></font>. It'+
      ' was popularised in the 1960s with the <font size="12"><a href="http://www.tmssoftware.com">release</a></font> of Letraset sheets containing Lorem Ipsum passages, and more recently with des'+
      'ktop publishing software like <font bgcolor="gcSteelBlue" color="gcWhite">Aldus PageMaker</font> including versions of Lorem Ipsum.';
    p.BitmapContainer := TMSFNCBitmapContainer1;
    p.BeginDocument(AFileName);
    p.NewPage;
    p.Graphics.Font.Name := 'Arial';
    p.Graphics.Font.Size := 10;
    p.Graphics.Fill.Color := gcNull;
    r := RectF(10, 50, 300, 400);
    p.Graphics.DrawHTMLText(s, r);
    p.EndDocument(True);
  finally
    p.Free;
  end;
end;
Images1

Graphics engine

The PDF library is capable of rendering primitives such as rectangles, ellipses or more complex paths built up of points. This can be done by combining the correct DrawPath* calls. To simplify this, the TTMSFNCGraphicsPDFEngine is available, that has the same methods as if you would draw on a canvas within WEB, FMX or VCL. So as an alternative to drawing, constructing paths via direct PDF draw calls, you can create an instance of TTMSFNCGraphicsPDFEngine which eliminates these complex path draw calls. Add FMX.TMSFNCGraphicsPDFEngine to the uses clause to access this class. Below is a sample that renders a diamond shape with rotated text.

uses
  FMX.TMSFNCPDFLib, FMX.TMSFNCGraphicsTypes, FMX.TMSFNCGraphicsPDFEngine;
procedure TForm1.GeneratePDF;
var
  p: TTMSFNCPDFLib;
  g: TTMSFNCGraphicsPDFEngine;
  pth: TTMSFNCGraphicsPath;
  r: TRectF;
begin
  p := TTMSFNCPDFLib.Create;
  g := TTMSFNCGraphicsPDFEngine.Create(p);
  pth := TTMSFNCGraphicsPath.Create;
  try
    p.BeginDocument('rotation.pdf');
    p.NewPage;
    pth.MoveTo(PointF(200, 200));
    pth.AddLine(PointF(200, 200), PointF(300, 300));
    pth.AddLine(PointF(300, 300), PointF(200, 400));
    pth.AddLine(PointF(200, 400), PointF(100, 300));
    pth.ClosePath;
    g.DrawPath(pth);
    r := RectF(100, 200, 300, 400);
    g.DrawText(r, 'Hello World!', False, gtaCenter, gtaCenter, gttNone, -45);
    p.EndDocument(True);
  finally
    pth.Free;
    g.Free;
    p.Free;
  end;
end;
Graphics engine

Form fields

The PDF library has support for adding form fields in a PDF, allowing users to fill in custom data. This can be done via the FormFields property.

Note

Form fields are currently supported on Windows and Linux only.

The following field types are available:

Type Function
text edit AddEdit
multiline text edit (memo) AddMemo
password edit AddPasswordEdit
check box AddCheckBox
radio group AddRadioGroup
radio button AddRadioButton
combo box AddComboBox
list box AddListBox

Each form field must define a field name. With the exception of radio groups, fields must also define a TRectF rectangle for the positioning on the page.

Example usage

procedure TForm1.Button1Click(Sender: TObject);
var
  p: TTMSFNCPDFLib;
  e: ITMSFNCCustomPDFFormFieldEdit;
begin
  p := TTMSFNCPDFLib.Create;
  try
    p.BeginDocument('test_pdf.pdf');
    p.NewPage;

    //Edit with trailing position and blue font color
    e := p.FormFields.AddEdit('Textfield1', RectF(10, 10, 210, 32),
      'The quick brown fox', gtaTrailing);
    e.Font.Color := gcBlue;
    e.Font.Size := 10;

    //Check box, unchecked
    p.FormFields.AddCheckBox('Checkbox1', RectF(10, 50, 30, 70), False);

    //Combo box, item index '1' selected
    p.FormFields.AddComboBox('Combobox1', RectF(10, 90, 70, 110),
      ['item1', 'item2', 'item3'], 1);

    //List box, item index '2' selected
    p.FormFields.AddListBox('Listbox1', RectF(10, 130, 110, 230),
      ['item1', 'item2', 'item3', 'item4', 'item5'], 2);

    //Memo, center aligned text
    p.FormFields.AddMemo('Memo1', RectF(10, 240, 110, 340),
      'abc def ghi jkl mno pqr stu vwx yz', gtaCenter);

    //Radio group, with 'Group1' group ID
    p.FormFields.AddRadioGroup('RadioGroup1', 'Group1');

    //Radio buttons added to the radio group with 'Group1' ID
    //First radio button is checked
    p.FormFields.AddRadioButton('RadioButton1', RectF(10, 380, 30, 400),
      'Group1', True);
    p.FormFields.AddRadioButton('RadioButton2', RectF(40, 380, 60, 400), 'Group1');
    p.FormFields.AddRadioButton('RadioButton3', RectF(70, 380, 90, 400), 'Group1');

    p.EndDocument(False);
  finally
    p.Free;
  end;
end;

Form field font and appearance

The FormFields object exposes a shared Font property (TTMSFNCPDFGraphicsLibFont) that sets the default font for all form fields. Individual fields that expose their own Font property override this default. The FontAutoSize boolean property enables automatic font size scaling to fit the field bounds. Set IgnoreFonts to True to suppress font embedding for form fields entirely.

Document & Page Settings

A new document can be configured to add meta-data. Below is an overview which meta-data is supported by the PDF library.

Author, Creator, Title, Subject and Keywords. The first four meta-data entries are strings and the Keywords entry is a list of strings. These values can be added directly on PDF document level.

Page size and orientation

Each new page starts with a specific page size. By default, the page size is set to Letter portrait, but can easily be changed by setting the PageSize and PageOrientation properties. Optionally a custom page size can be configured by setting the PageSize property to psCustom. The PageWidth and PageHeight properties can be used to set the custom page size. These properties can also be used to retrieve the current applied PageWidth and PageHeight independent of the PageSize property setting.

The PageSize property supports a large range of standard sizes including ISO A0–A8, B0–B10, C2–C6, SRA and RA series, US Letter, Legal, Ledger, Tabloid, Executive, ANSI C–E, and various traditional British paper sizes.

Each new page starts with a header and footer. The header and footer can be customized with the Header* and Footer* properties:

Property Description
Header / Footer Text content (supports HTML formatting)
HeaderSize / FooterSize Height of the header/footer area
HeaderMargins / FooterMargins Margins around the header/footer area
HeaderAlignment / FooterAlignment Horizontal text alignment
HeaderFont / FooterFont Font used for header/footer text

Use GetHeaderRect and GetFooterRect to retrieve the bounding rectangle of the header and footer areas respectively.

Page numbering

Page numbers can be added automatically using the PageNumber property:

Value Description
pnNone No automatic page number (default)
pnHeader Display page number in the header area
pnFooter Display page number in the footer area

Additional page number properties:

Property Description
PageNumberFormat Format string for the page number text
PageNumberSize Height of the page number area
PageNumberMargins Margins around the page number
PageNumberAlignment Horizontal alignment of the page number
PageNumberFont Font for the page number text

Use GetPageNumberRect to retrieve the page number bounding rectangle.

PDF standard

The PDFStandard property sets the conformance level of the generated PDF:

Value Description
pdfNone Standard PDF (default)
pdfA1 PDF/A-1 archival format

Security and permissions

The PDF library supports password-based security. Set OwnerPassword and UserPassword to protect the document. The AllowsPrinting and AllowsCopying boolean properties (both True by default) control what operations a user is permitted to perform when the document is opened with the user password.

PDF page boxes

Advanced print-production workflows can configure the PDF page boxes that define different page boundary regions:

Property Description
MediaBox Physical size of the page (default page boundary)
CropBox Region displayed or printed
BleedBox Region to which the page content is clipped when bleed marks are applied
TrimBox Intended dimensions of the finished page after trimming
ArtBox Extent of the page's meaningful content

Events

The PDF library exposes several events for customizing the automatic drawing of header, footer and page number content:

Event Description
OnBeforeDrawHeader Fires before the header is drawn; set ADefaultDraw := False to suppress default rendering and draw custom content via AGraphics
OnAfterDrawHeader Fires after the header has been drawn; use AGraphics to add decorations
OnBeforeDrawFooter Fires before the footer is drawn
OnAfterDrawFooter Fires after the footer has been drawn
OnBeforeDrawPageNumber Fires before the page number is drawn
OnAfterDrawPageNumber Fires after the page number has been drawn
OnNewPageStarted Fires after each NewPage call; provides the zero-based APageIndex

All header/footer/page-number events receive APageIndex, the current text value, the drawing rectangle (ARect), and an AGraphics reference for custom drawing.

procedure TForm1.PDFBeforeDrawHeader(Sender: TObject; APageIndex: Integer;
  AHeader: UnicodeString; ARect: TRectF;
  AGraphics: ITMSFNCCustomPDFGraphicsLib; var ADefaultDraw: Boolean);
begin
  ADefaultDraw := False;
  AGraphics.Font.Size := 9;
  AGraphics.DrawText('Page ' + IntToStr(APageIndex + 1), ARect.TopLeft);
end;

Coordinate Conversion Utilities

The PDF library includes a set of helper functions for converting between PDF points (pixels at 72 DPI by default), inches and millimeters. All functions accept an optional ADPI parameter (default 72.0).

Function Description
InchToPixel(AInch, ADPI) Convert inches to PDF points
PixelToInch(APixel, ADPI) Convert PDF points to inches
MillimeterToPixel(AMillimeter, ADPI) Convert millimeters to PDF points
PixelToMillimeter(APixel, ADPI) Convert PDF points to millimeters
InchPoint(AX, AY, ADPI) Create a TPointF from inch coordinates
InchRect(AX, AY, AWidth, AHeight, ADPI) Create a TRectF from inch coordinates
MillimeterPoint(AX, AY, ADPI) Create a TPointF from millimeter coordinates
MillimeterRect(AX, AY, AWidth, AHeight, ADPI) Create a TRectF from millimeter coordinates
PointToInchPoint(APoint, ADPI) Convert a TPointF from PDF points to inches
PointToMillimeterPoint(APoint, ADPI) Convert a TPointF from PDF points to millimeters
RectToInchRect(ARect, ADPI) Convert a TRectF from PDF points to inches
RectToMillimeterRect(ARect, ADPI) Convert a TRectF from PDF points to millimeters

Example — drawing a rectangle sized in millimeters:

p.Graphics.DrawRectangle(MillimeterRect(10, 10, 100, 150));

Components that support PDF Export

Below is a list of components that support exporting to a PDF, all components inherit from a base TTMSFNCPDFIO component that supports configuration of meta-data and header and footer as well as custom drawing / customization through events.

  • TTMSFNCGrid
  • TTMSFNCChart
  • TTMSFNCRichEditor

To get started, drop one of the TTMSFNC*PDFIO components on the form. Call the Save function to save to a file or stream. Additionally, the TTMSFNCGraphicsPDFIO component is capable of rendering a PDF version of the components as if painted within a Canvas.

WEB Support

Font caching

In a TMS WEB Core application, it is required to pre-load fonts to make PDF export function properly. This can be done by using the AddFontToCache method and specify a TTF file representing the fonts that you are using inside the component, or when generating a custom PDF. The font that is used by default is Arial, and the font used inside components is Tahoma. Below is a sample code that demonstrates how to add fonts.

AddFontToCache('http://www.myserver.com/fonts/arial.ttf');
AddFontToCache('http://www.myserver.com/fonts/tahoma.ttf');

As the fonts are loaded asynchronously, there is an event that is triggered when all fonts added to the font cache are preloaded. The OnFontCacheReady event can be used to make sure that the fonts are ready to use when exporting to PDF.

Application.OnFontCacheReady := DoFontCacheReady;

AddFontToCache also accepts a TJSBlob parameter as an alternative to a URL, allowing fonts loaded from other sources to be passed directly.

Compression

When a pdf is generated, the content and fonts that are embedded are compressed. in FMX and VCL this is automatically done, but on WEB a third party library is needed, based on the zlib compression algorithm. Whenever a new WEB project is created you should, by default, add the pako.js library. To enabled this, click on the "Manage JavaScript Libraries" project right-click context menu item and choose the "Pako ZLib Compression (PDF)" menu item.

WEB Support