Blog

All Blog Posts  |  Next Post  |  Previous Post

PDF generation with complex graphics in Delphi

Bookmarks: 

Wednesday, February 2, 2022

Intro

TMS FNC Core is the core foundation of FNC. It offers a solid structure for the other FNC component sets such as TMS FNC UI Pack and TMS FNC Maps. In the past, we have demonstrated the capabilities of TMS FNC Core in various ways. Below are a couple of links to blog posts about functionality available in TMS FNC Core.

A browser, JSON persistence, printing, SVG support and many more. Today I want to focus on another "hidden gem": PDF generation and in particular focusing on drawing complex graphics.

Basic drawing 

Before going to complex drawing statements, we need to take a look at the basics. Generating a PDF starts by specifying a file name, adding the first page, and then the PDF context is ready to be accessed via the Graphics property. In the sample below, we draw a simple rectangle by setting the properties of the fill & stroke and by calling p.Graphics.DrawRectangle.

uses
  FMX.TMSFNCPDFLib, FMX.TMSFNCGraphicsTypes;

procedure TPDFGenerationForm.GeneratePDF;
var
  p: TTMSFNCPDFLib;
begin
  p := TTMSFNCPDFLib.Create;
  try
    p.BeginDocument('MyPDF.pdf');
    p.NewPage;

    p.Graphics.Fill.Color := gcYellowgreen;
    p.Graphics.Stroke.Color := gcGreen;
    p.Graphics.Stroke.Width := 4;
    p.Graphics.DrawRectangle(RectF(100, 100, 300, 300));

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

This generates the following PDF

TMS Software Delphi  Components


The basic ITMSFNCCustomPDFGraphicsLib interface (p.Graphics property) exposes a lot of basic drawing calls to draw shapes constructed out of simple primitives or more complex paths. On top of that, it's possible to export images as well. Using these calls gives you the flexibility to enhance your PDF with vector sharp graphics. The way this needs to be done is by calling each draw statement in a specific order. See this sample below to draw a bezier curve.

uses
  FMX.TMSFNCPDFLib, FMX.TMSFNCGraphicsTypes, FMX.TMSFNCPDFCoreLibBase;

procedure TPDFGenerationForm.GeneratePDF;
var
  p: TTMSFNCPDFLib;
begin
  p := TTMSFNCPDFLib.Create;
  try
    p.BeginDocument('MyPDF.pdf');
    p.NewPage;

    p.Graphics.Stroke.Color := gcDarkseagreen;
    p.Graphics.Stroke.Width := 3;
    p.Graphics.Stroke.Kind := gskSolid;
    p.Graphics.DrawPathBegin;
    p.Graphics.DrawPathMoveToPoint(PointF(350, 40));
    p.Graphics.DrawPathAddCurveToPoint(PointF(310, 130), PointF(445, 50), PointF(398, 115));
    p.Graphics.DrawPathEnd(dmPathStroke);

    p.Graphics.Stroke.Width := 0.5;
    p.Graphics.Stroke.Color := gcBlack;
    p.Graphics.Fill.Color := gcNull;
    p.Graphics.Fill.Kind := gfkSolid;
    p.Graphics.DrawLine(PointF(350, 40), PointF(310, 130));
    p.Graphics.DrawLine(PointF(445, 50), PointF(398, 115));

    p.Graphics.DrawRectangle(RectF(442.5, 47.5, 447.5, 52.5));
    p.Graphics.DrawRectangle(RectF(395.5, 50 + 62.5, 400.5, 50 + 67.5));
    p.Graphics.DrawRectangle(RectF(347.5, 50 - 12.5, 352.5, 50 - 7.5));
    p.Graphics.DrawRectangle(RectF(307.5, 127.5, 312.5, 132.5));

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

The result of the above code is a bezier curve with lines and handles mimicking interaction.


TMS Software Delphi  Components

Mapping FNC Core graphics onto PDF graphics

After the initial release, we had some requests on exporting FNC components to PDF. The PDF graphics layer was too limited to export components to PDF, therefore we have created the TTMSFNCGraphicsPDFEngine class, which decends from TTMSFNCGraphics, the core class for all FNC cross-platform drawing. On top of the default PDF graphics, the TTMSFNCGraphicsPDFEngine gives you complex paths, matrix transforms as well as various flexible image drawing options. Together with SVG support we can then load the SVG as a resource and draw the information as vector graphics inside the PDF. Internally, the SVG is parsed, elements are transformed to FNC graphics paths and with that information the PDF graphics engine draws renders the SVG onto the PDF canvas, via the earlier mentioned drawing calls. All in a couple of lines.

uses
  FMX.TMSFNCPDFLib, FMX.TMSFNCGraphicsTypes,
  FMX.TMSFNCGraphicsPDFEngine, FMX.TMSFNCTypes;

procedure TPDFGenerationForm.GeneratePDF;
var
  p: TTMSFNCPDFLib;
  g: TTMSFNCGraphicsPDFEngine;
  bmp: TTMSFNCBitmap;
begin
  p := TTMSFNCPDFLib.Create;
  g := TTMSFNCGraphicsPDFEngine.Create(p);
  bmp := TTMSFNCBitmap.CreateFromFile('tiger.svg');
  try
    p.BeginDocument('MyPDF.pdf');
    p.NewPage;

    g.DrawBitmap(RectF(50, 50, 400, 600), bmp);

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

TMS Software Delphi  Components


Export FNC Components

Adding complex vector graphics to your PDF through the TTMSFNCGraphicsPDFEngine class also brings a way to export FNC components. In the base TTMSFNCCustomControl class we have added the ITMSFNCGraphicsExport interface, which is capable of exporting the component to another graphics instance, in this case the PDF graphics engine. In this sample, we chose to export TTMSFNCChart, which is a component that is capable of displaying statistical & mathemical data in various representation types  such as a line chart, bar chart or an area chart. The code looks like this and is for this sample based on the TMS FNC Chart desktop demo, included in the distribution.

procedure TPDFGenerationForm.GeneratePDF;
var
  p: TTMSFNCPDFLib;
  g: TTMSFNCGraphicsPDFEngine;
  e: ITMSFNCGraphicsExport;
begin
  p := TTMSFNCPDFLib.Create;
  g := TTMSFNCGraphicsPDFEngine.Create(p);
  try
    p.BeginDocument('MyPDF.pdf');
    p.NewPage;

    if Supports(TMSFNCChart1, ITMSFNCGraphicsExport, e) then
      e.Export(g, RectF(50, 50, 500, 350));

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

TMS Software Delphi  Components


Explore

Download TMS FNC Core today and start exploring TTMSFNCPDFLib, TTMSFNCGraphicsPDFEngine and its capabilities! If you are an active registered user of any FNC product, TMS FNC Core is included in your subscription!



Pieter Scheldeman


Bookmarks: 

This blog post has not received any comments yet.



Add a new comment

You will receive a confirmation mail with a link to validate your comment, please use a valid email address.
All fields are required.



All Blog Posts  |  Next Post  |  Previous Post