Blog
All Blog Posts | Next Post | Previous PostPDF generation with complex graphics in Delphi
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
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.
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;
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;
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
This blog post has not received any comments yet.
All Blog Posts | Next Post | Previous Post