Home Delphi installation FPC Lazarus installation Components and controls Design Global defines Render contexts Text layouts Supported SVG features Programming examples SVG Viewer applications Contact and bug reporting Licensing

SVG control package v2.3

SVG (Scalable Vector Graphics) is an XML-based vector image format for two dimensional graphics developed by the World Wide Web Consortium (W3C).

The "SVG control package" enables the use of Scalable Vector Graphics (SVG) in Delphi and FPC Lazarus applications. The current version of the package covers most of the SVG 1.1 specification, with the exception of SMIL animation and scripting.

The architecture of the software allows for use on multiple platforms. The software can be used in Delphi VCL, FMX and Lazarus applications for Windows, OsX and Linux targets. Mobile platforms iOS and Android are to some extend possible but with limitations. Other targets might also be possible but these are not tried or tested.

The requirements for the package are the following:

You can just use the controls provided in the package or you can go a bit deeper and try the programming examples. The programming examples show how to interact with the SVG content, or how to animate the graphic, not with SMIL but with Pascal code.

In this help file you will find the following:

Please read the installation instructions carefully!


Delphi installation

Installation packages in Delphi

Remove old versions

If older versions of the SVG control version packages are already installed, these have to be removed first.

Choose "Install Packages..." in the IDE.


Then deselect and remove the packages named DclSVG2PackageFmx.bpl, DclSVG2PackageVcl.bpl and DclSVG2PackageCommon.bpl. Remove the Fmx and Vcl package first because these are dependent on the Common package.


It might be necessary to check if really all old files are deleted and no old package files or object files remain on the file path. Otherwise you might experience strange behaviour in Delphi, for example exception errors on closing Delphi.

Next, before you reinstall the new packages RESTART DELPHI!

Install the new versions.

For each Delphi version there are in total 6 packages, 3 run-time packages and 3 design-time packages.

Depending on your Delphi version, you can find find the package files in the sub folder indicated by the following table.

Folder Delphi name ID Compiler version
XE2 Delphi XE2 XE2 23
XE3 Delphi XE3 XE3 24
XE4 Delphi XE4 XE4 25
XE5 Delphi XE5 XE5 26
XE6 Delphi XE6 XE6 27
XE7 Delphi XE7 XE7 28
XE8 Delphi XE8 XE8 29
DX Delphi 10 Seattle DX 30
DX1 Delphi 10.1 Berlin DX1 31
DX2 Delphi 10.2 Tokyo DX2 32
DX3 Delphi 10.3 Rio DX3 33

So, the package that ends with ..XE5.dproj should be installed in Delphi XE5 and ..DX1.dproj should be installed in Delphi DX1 Berlin.

The run-time packages contain the actual SVG source code units, there is a common package, a package for Vcl and one for FMX. The run-time packages must at least be build to target Win32 and if you want to use the SVG package in 64 bit applications, you have to build the run time packages to target Win64 also.

  1. SVG2PackageCommon<ID>
  2. SVG2PackageFmx<ID>
  3. SVG2PackageVcl<ID>

The design-time packages start with "Dcl..." and contain the units to register the package in the Delphi IDE and the property editors. These packages can only be build to target Win32, because the Delphi IDE is a 32bit application.

  1. DclSVG2PackageCommon<ID>
  2. DclSVG2PackageFmx<ID>
  3. DclSVG2PackageVcl<ID>

Here is an example how to build the packages and in case of the design-time packages how to install them. In this example I use Delphi DX1 Berlin and only build the packages to the default Win32 target.

The run-time common package SVG2PackageCommonDX1 has to be build first because the other packages are dependent.

1. In the IDE choose "File - Open Project..." and open the project file SVG2PackageCommonDX1.dproj in de Package folder of relevant Delphi version.


2. Build SVG2PackageCommonDX1, you can save the changes if asked for

3. Open project file DclSVG2PackageCommonDX1.dproj.

4. Build and then Install package DclSVG2PackageCommon.DX1.

After installation there will be a notification that one component has been registered: TSVG2Doc.


5. Next open the project file SVG2PackageFmxDX1.dproj in the sub folder Fmx of the package folder.


6. Build package SVG2PackageFmxDX1.

7. Open the project file DclSVG2PackageFmxDX1.dproj.

8. Build an then Install package DclSVG2PackageFmxDX1.

After installation there will be a notification that four new components have been registered: TSVG2Control, TSVG2Image, TSVG2ImageList and TSVG2LinkedImage.


9. Next open the project file SVG2PackageVclDX1.dproj in the sub folder Vcl of the package folder.


10. Build package SVG2PackageVclDX1.

11. Open the project file DclSVG2PackageVclDX1.dproj.

12. Build and then Install package DclSVG2PackageVclDX1.

After installation there will be a notification that four new components have been registered: TSVG2Control, TSVG2Image, TSVG2ImageList and TSVG2LinkedImage.


After installing these packages, there should be a group called SVG2 in the Tool palette containing 5 components in FMX and 6 components in VCL: TSVG2Doc, TSVG2Control, TSVG2Image, TSVG2ImageList, TSVG2LinkedImageList (VCL only), TSVG2LinkedImage.




Setting up the Delphi project environment

To be able to compile your Delphi projects with the SVG package, Delphi needs to know where the source code of the package is located. There are three ways to set this up:

  1. Add folders to your library path once.
  2. Add a search path to your new projects in the project options
  3. Add the SVG package units to your new projects explicitly

Add folders to your library path once

This might be the most convenient because you have to do it only once.



Add a search path to your new projects in the project options

This you have to do for each new project.


Add the SVG package units to your new projects explicitly

This you might want to do if you want full control over which units you want to compile into your project, you have to do this also for each new project.

First add all the .pas files from the SVG package in folder Common.

Choose from the Delphi menu "Project ->Add to project". Navigate to the Common folder of the SVG package and select the files.



VCL application

In case you are creating a VCL application, choose "Project ->Add to project" again and go to the folder Common\Vcl and select all the files from there.

Next go to folder Common\Platform. The files you select here depend on the render context you want to use in your application.

The default render context for VCL is Direct2D with a fall back to GDI+.

For this, you have to select all the Direct2D header files (starting with BVE.DX...), next add BVE.SVG2ContextD2D.pas and add BVE.SVG2ContextGP.pas

For rendering text using system fonts, you need to include thetext layoutsalso, so add BVE.SVG2FontDirectWrite.pas and add BVE.SVG2FontGDI.pas.

The render context to use for VCL are defined asglobal definesin the include file Common\Vcl\ContextSettingsVCL.inc. If you want to use another render context than the default, you have to modify this file and include the appropriate files from Common\Platform into your project.


FMX application

In case you are creating a Firemonkey (FMX) application, choose "Project ->Add to project" again and go to the folder Common\Fmx and select all the files from there.

Next go to folder Common\Platform. Again the files you select here depend on the render context you want to use in your application.

The default render context for FMX is "FMX canvas".

For this, you have to select BVE.SVG2ContextFMX.pas.

The render context to use for FMX are defined in the include file Common\Fmx\ContextSettingsFMX.inc. If you want to use another render context than the default, you have to modify this file and include the appropriate files from Common\Platform into your project. See paragraph "Global defines" for details.


A more flexible approach would be to add all the units to your project as described above,exceptthe ones from Common\Platform. And add a search path to this folder in the project options or in the library path. This way you simply set the render context you want to use in ContextSettingsVCL.inc or ContextSettingsFMX.inc and let the system decide which units need to be included.


Test compilation Delphi

Next you can test if your project compiles.

  1. Create a new project.
  2. Select the TSVG2Image from the tool palette and put in on the form.
  3. Select the SVG2Image1 and put a path to an SVG file into the "FileName" property.
  4. Run the application.



FPC Lazarus installation


FPC and Lazarus requirements for the SVG library

The SVG library is developed with FPC version 3.0.4 and Lazarus version 1.8.4, so it is recommended to use these versions or later.

Also because the SVG library uses generics for lists, stacks and so on, the "rtl-generics" package is needed. This package is provided as standard in FPC 3.1.1.+ but must be downloaded separately for version 3.0.4.


Installation packages in FPC Lazarus

Load the package FPC\Package\svg2package.lpk into Lazarus IDE:

The package has the following search paths defined:

Common, shared units for all platforms
Common\Fpc, the FPC Lazarus specific units
Common\Platform, the render context interface implementations

If your FPC version doesn't include the rtl-generics version by default (version FPC 3.1.1.+ and above) you need to download the package and add a search path to it, or use the version included in the package.

Common\Fpc\generics, the "rtl-generics" package. Only include this path if your FPC Lazarus version doesn't include the package by default!

To include the SVG components into the Lazarus IDE, follow these steps:

  1. Compile the package
  2. Select Use->Install

Lazarus has to be rebuild to complete the installation.

After installation you will find the SVG controls on tab "SVG2"

Lazarus IDE, tab SVG2

Test compilation FPC Lazarus

Test the installation:

  1. Create a new application project.
  2. Select the TSVG2Image from the tool palette and put in on the form.
  3. Select the SVG2Image1 and put a path to an SVG file into the "FileName" property.
  4. Run the application
Test project FPC

SVG components and controls

The SVG package contains the following components and controls.

Components

  1. TSVG2Doc
  2. TSVG2ImageList
  3. TSVG2LinkedImageList
  4. TSVGGraphic (not available in FMX)

Controls

  1. TSVG2Control
  2. TSVG2Image
  3. TSVG2LinkedImage

TSVG2Doc



Source Unit Parent
Vcl BVE.SVG2Doc.pas BVE.SVG2Doc Xml.XMLDoc.TXMLDocument
Fpc Not available
Fmx BVE.SVG2Doc.pas BVE.SVG2Doc Xml.XMLDoc.TXMLDocument

Description

The TSVGDoc is basically a TXMLDocument. It allows for loading SVG content in an XML document without causing error messages.

This might be useful if you want to work with SVG in a IXMLDocument and be able to render it to a bitmap.

The TSVG2Control has a property "SVGDoc" to which you can connect a TSVG2Doc. TSVGDoc is more or less deprecated now, because it is more efficient to parse the SVG from file or from strings than using a TSVGDoc.


TSVG2ImageList and TSVG2LinkedImageList


TSVG2ImageList is derived from TImageList and therefore contains a list of bitmap images. However, it also contains a list of SVG's and has the capability to automatically create the bitmap images out of the SVG.

The rendering of the bitmap images out of the SVG content occurs when the SVG data is modified or if the TSVGImageList properties are changed, otherwise it just behaves as a static TImageList.

Controls that have a "ImageList" property can also link to a TSVG2ImageList, the control will display the static image from the TSVG2ImageList. If SVG data or some other property of TSVG2ImageList is modified, than the associated static image will be updated and all linked controls will update there image as well.

The image bitmap data along with all the SVG content and settings are stored in the Delphi or FPC/Lazarus form file.

The software for parsing and rendering SVG is complex and adds to the complexity and size of the application you are developing, so it only makes sense to use TSVG2ImageList if you actually need to parse and render images in run-time. An alternative use case could be, to just use a normal TImageList in your main application and develop a small utility application with TSVG2ImageList, from which you export the images that you need in your main application.

Differences between the VCL, FMX and FPC image list

The standard TImageList for VCL, FMX an FPC each differ in design. The main differences are in how scaling is implemented:

These differences are also present in TSVG2ImageList, because it is derived from TImageList for VCL, FMX and FPC/Lazarus:


SVG Image lists functionality and settings

The TSVG2ImageList for VCL/FPC Lazarus has the following main functionalities on top of those supplied by the normal TImageList:

  1. Synthesizing images from SVG definitions
  2. Creating variations on images using "Styles"
  3. Creating multiple sizes of images using "Resolutions"
  4. Exporting images to stream or file

In stead of a list, the TSVG2ImageList can be seen as an image grid, where the rows represent SVG's and the columns represent "Styles" and the "Resolutions" represent different layers of the grid.

The total number of mages you can create with a TSVGImagelist:

SVG count * Style count * Resolution count

The TSVG2LinkedImageList can be used as an intermediate between the controls on the form and a centralized TSVG2ImageList.

The TSVG2LinkedImageList uses all SVG's and all, or one of the "Styles" from a linked parent "TSVG2ImageList" but for the rest has the same properties as a TSVG2ImageList.

Both TSVG2ImageList and TSVG2LinkedImageList are derived from TSVG2BaseImageList.

Component editor

The component editor is activated by double clicking on the TSVG2ImageList component on the form you are designing, or by the pop-up menu that is shown when you right click TSVG2ImageList and then select "Edit...".

VCL TSVG2ImageList component editor

FPC/Lazarus TSVG2ImageList component editor

FMX TSVG2ImageList component editor

TSVG2LinkedImageList component editor

There is also a component editor for the TSVG2LinkedImageList. It has the same "Bitmap" and "Export" tab as the TSVG2ImageList, but it lacks the "SVG" and "Styles". In stead it has a "Parent list" tab, where you can set the link to the parent TSVG2ImageList.

With the "Parent style index" you can select one of the styles that are defined in the parent TSVG2ImageList. If you set this to -1, all styles of the parent image list are used.

Example creating styles

An example for this is using a "Saturation" filter to create a "Disabled" version of an image. The outer SVG would look like this:

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <defs>
    <filter id="fltr_saturate">
      <feColorMatrix in="SourceGraphic" type="saturate" values="0.20"/>
    </filter>
  </defs>
    <g filter="url(#fltr_saturate)">&cur_svg;</g>
</svg>

Here &cur_svg; is a special entity that the parser will replace with the SVG from the SVG list.

There are a couple of default outer SVG's defined that you can select and modify if you wish, or you can create your own outer SVG, as long as it contains the &cur_svg; entity and it is a valid SVG after substitution.

Entities added to the SVG

Another means of altering the SVG in order to create a different style is by using Entities in the SVG itself. Entities are often used to replace special characters in XML, for example the symbol "<" is replaced in XML by the entity "&lt;". See for details on Entities over here.

When the parser encounters an Entity in the SVG, it will add it to the Entity list of all the Styles that are defined in the TSVG2ImageList. For each style a different value for the Entity can be entered.

For example, we have the following SVG (start.svg):

<svg version="1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" enable-background="new 0 0 48 48">
  <path fill="#F44336" d="M38,42H10c-2.2,0-4-1.8-4-4V10c0-2.2,1.8-4,4-4h28c2.2,0,4,1.8,4,4v28C42,40.2,40.2,42,38,42z"/>
  <polygon fill="#fff" points="31,24 20,16 20,32"/>
</svg>

We want to create different styles by changing the colour, so we add a DTD and within that an Entity for the fill attribute:

<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Basic//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-basic.dtd" [
  <!ENTITY fill_color "#F44336">
]>
<svg version="1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" enable-background="new 0 0 48 48">
  <path fill="&fill_color;" d="M38,42H10c-2.2,0-4-1.8-4-4V10c0-2.2,1.8-4,4-4h28c2.2,0,4,1.8,4,4v28C42,40.2,40.2,42,38,42z"/>
  <polygon fill="#fff" points="31,24 20,16 20,32"/>
</svg>

On parsing the entity "fill-color" will be added to the Entity list of all styles. On each style you can now set a different value.

The image below shows some other things that can be done, for example replacing a transformation value or a complete element with an entity.

The SVG used for the rotation example:

<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Basic//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-basic.dtd" [
  <!ENTITY rotation "0">
]>
<svg version="1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" enable-background="new 0 0 48 48">
  <path fill="#F44336" d="M38,42H10c-2.2,0-4-1.8-4-4V10c0-2.2,1.8-4,4-4h28c2.2,0,4,1.8,4,4v28C42,40.2,40.2,42,38,42z"/>
  <polygon transform="rotate(&rotation;, 24, 24)" fill="#fff" points="31,24 20,16 20,32"/>
</svg>

The SVG used for the replaced element example:

<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Basic//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-basic.dtd" [
  <!ENTITY shape "<polygon fill='#fff' points='31,24 20,16 20,32'/>">
]>
<svg version="1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" enable-background="new 0 0 48 48">
  <path fill="#F44336" d="M38,42H10c-2.2,0-4-1.8-4-4V10c0-2.2,1.8-4,4-4h28c2.2,0,4,1.8,4,4v28C42,40.2,40.2,42,38,42z"/>
  &shape;
</svg>


Example transparency on VCL and work-around in case of non-themed user interface

In VCL, the "Color depth" controls if the bitmaps in the list will support transparency. To enable transparency this must be set to "cd32bit" and the "Clear color" must be set to "clNone". However:

Windows only supports transparency on controls if runtime themes are enabled.

For example, in the following project the "Color depth" is set to "cd32bit" and the "Clear color" is set to "clNone".

If runtime themes are enabled, this will result in transparent images on the toolbar.

If runtime themes are disabled, in the application manifest or in the Windows OS settings, the background of the controls will become black.

A work around for this problem is to detect if runtime themes are enabled when the application starts and if not, to set the "Color depth" of the image list to "cd24" bit and the "ClearColor" equal to the controls background color, for example:

uses
  Vcl.Themes;

procedure TForm1.FormCreate(Sender: TObject);
begin
  if not StyleServices.Enabled then
  begin
    SVG2ImageList1.BeginUpdate;
    try
      SVG2ImageList1.ClearColor := clBtnFace;
      SVG2ImageList1.ColorDepth := cd24Bit;
    finally
      SVG2ImageList1.EndUpdate;
    end;
  end else begin
    SVG2ImageList1.BeginUpdate;
    try
      SVG2ImageList1.ClearColor := clNone;
      SVG2ImageList1.ColorDepth := cd32Bit;
    finally
      SVG2ImageList1.EndUpdate;
    end;
  end;
end;

After this, the images will have the following appearance in a non-themed application.



Example scaling

An example how to set up the image list for scaling can be found in the VCL demo viewer for Delphi 10.3.

There is one SVGImageList1 component, that has two styles, style 0 with plain images and style 1 with disabled images using a saturation filter. There are two linked image lists, "ilNormal" is linked two style 0 of the SVGImageList1 and "ilDisabled" is linked to style 1 of SVGImageList1.

The "DisabledImages" property of the ActionManager1 component is set to "ilDisabled" and the "Images" property is set to "ilNormal".


The properties of the image lists are set up as folows:

SVG2ImageList1 ilNormal ilDisabled
ParentImageList SVG2ImageList1 SVG2ImageList1
ParentStyleIndex 0 1
Scaled False True True
ScalingKind skReRender skReRender

Monitor scale is set to 100%


Monitor scale is set to 125%


The scaling kind is set to "skReRender", so when scaling occurs, all images in the image lists that have the "Scaled" property set to "True" will be re-rendered. It is also possible to create the images beforehand. It that case the image list properties must be set up as follows:

SVG2ImageList1 ilNormal ilDisabled
ParentImageList SVG2ImageList1 SVG2ImageList1
ParentStyleIndex 0 1
Scaled False True True
ScalingKind skBestFitFromResolution skBestFitFromResolution
Resolutions 24
30
36
48
skBestFitFromResolution skBestFitFromResolution

In the VCL version the resolutions are kept within the main SVG2ImageList1 and are defined by the width in pixels of the images. In this example they are chosen as to be 100% 125% 150% and 200% of the base image width. Maybe you can do with less resolutions, this is something you have to try out.

The FPC/Lazarus viewer has a SVG2ImageList1 component on which three styles are defined. Linked image list "ilNormal" links to style 0, linked image list "liDisabled" is linked to style 1 using a saturation filter, and linked image list "ilHot" links to style 2 using a drop shadow filter.

The "Images" property of the toolbar is set to "ilNormal", the "DisabledImages" is set to "ilDisabled" and "HotImages" is set to "ilHot".


The properties for scaling on the image lists are set up as follows:

SVG2ImageList1 ilNormal ilDisabled ilHot
ParentImageList SVG2ImageList1 SVG2ImageList1 SVG2ImageList1
ParentStyleIndex 0 1 2
Scaled False True True True
Resolutions 24
30
36
48
24
30
36
48
24
30
36
48

There is no "ScalingKind" property for the FMX/Lazarus SVG image list, an image will be selected from the resolutions that best fit the image width needed for the linked control. If not an exact match can be found, than the system will try to find a larger resolution and than make it smaller by resampling it to the right size.

For the FMX version there is also no "ScalingKind" property, there is also no "Scaled" property because Delphi FMX has scaling build into the core of all controls by default. In the FMX TImageList is a multi resolution bitmap. Again all resolutions you are likely to need in your application, must be defined beforehand. The SVG image list will render the images on all layers of the multi resolution bitmap.

The FMX viewer demo application has a SVG2ImageList1 component for the application icons. Delphi FMX has no separate "DisabledImages" property on toolbars or menu's, so the styling functionality of the TSVG2Imagelist is not used and also no linked image lists are needed.


The scaling for the SVG2ImageList1 component is set up as follows:

SVG2ImageList1
Resolutions 32
48

TSVG2BaseImageList


Source Unit Parent
Vcl BVE.SVG2ImageList.VCL.pas BVE.SVG2ImageList.VCL Vcl.Controls.TImageList
Fpc BVE.SVG2ImageList.FPC.pas BVE.SVG2ImageList.FPC TCustomImageList
Fmx BVE.SVG2ImageList.FMX.pas BVE.SVG2ImageList.FMX TCustomImageList

Description

TSVG2BaseImageList is the parent class for TSVG2ImageList and TSVG2LinkedImageList.

Properties

Methods

Events


TSVGListItem


Vcl BVE.SVG2ImageList.VCL.pas BVE.SVG2ImageList.VCL TCollectionItem TSVGBaseListItem
Fpc BVE.SVG2ImageList.FPC.pas BVE.SVG2ImageList.FPC TCollectionItem TSVGBaseListItem
Fmx BVE.SVG2ImageList.FMX.pas BVE.SVG2ImageList.FMX TCollectionItem

Description

TSVGListItem represents one SVG in the collection of SVG's in TSVG2ImageList.

Properties

Methods


TSVGImageStyle


Vcl BVE.SVG2ImageList.VCL.pas BVE.SVG2ImageList.VCL TCollectionItem TSVGBaseListItem
Fpc BVE.SVG2ImageList.FPC.pas BVE.SVG2ImageList.FPC TCollectionItem TSVGBaseListItem
Fmx BVE.SVG2ImageList.FMX.pas BVE.SVG2ImageList.FMX TCollectionItem

Description

TSVGImageStyle represents one style item in the collection of style items in a TSVG2ImageList. The style item has properties to modify SVG's to create a extra set of images, for example to create a "Disabled" version of the images.

Different styles are created using the XML functionality of "Entities". XML entities are a way of representing an item of data within an XML document, instead of using the data itself.

An entity can be referred to in XML by the Entity name preceded with a "&" and followed by a ";".

Properties

Methods


TSVGImageListResolution


Vcl BVE.SVG2ImageList.VCL.pas BVE.SVG2ImageList.VCL System.Classes.TPersistent
Fpc For FPC/Lazarus version 1.9 and up TCustomImageListResolution is used.
Fmx Delphi XE8 and higher uses a multi resolution bitmap.

Description

In VCL the TSVGImageListResolution is basically an extra image list within an image list but with larger images. The size of the images is defined by the "Width", the height of the images is calculated so that it is scaled proportionally.

Each resolution is one big data block of image count * image width * image height * 4 bytes. The extra resolutions can be used for DPI scaling, another use is for creating multi-layered images, for example icons.

In the VCL SVG image list, the type of scaling is controlled by the "ScalingKind" property, if it is set to "Re-render", than all images are re-rendered if scaling occurs and the extra resolutions are not needed, if the SVG's are very complex and it rendering takes a long time, you can set "ScalingKind" to "From resolutions". The system will then select a resolution that has images of the correct size or slightly larger and if so, resample the image.

The FPC/Lazarus image list supports scaling from version 1.9 onwards. It is basically a collection of image lists where each TCustomImageListResolution represents an image list with a different size of images. It's implementation does not allow for re-rendering of images, so if you need scaling, the extra resolutions must be defined always.

Properties

Methods


TSVG2ImageList


VCL, FMX, FPC/Lazarus


Source Unit Parent
Vcl BVE.SVG2ImageList.VCL.pas BVE.SVG2ImageList.VCL Vcl.Controls.TImageList TSVG2BaseImageList TSVG2CustomImageList
Fpc BVE.SVG2ImageList.FPC.pas BVE.SVG2ImageList.FPC TCustomImageList TSVG2BaseImageList TSVG2CustomImageList
Fmx BVE.SVG2ImageList.FMX.pas BVE.SVG2ImageList.FMX FMX.ImgList.TCustomImageList TSVG2BaseImageList TSVG2CustomImageList

Description

The TSVG2ImageList keeps the collection of SVG's and Styles.

Properties

Methods


TSVG2LinkedImageList


VCL, FMX, FPC/Lazarus


Source Unit Parent
Vcl BVE.SVG2ImageList.VCL.pas BVE.SVG2ImageList.VCL Vcl.Controls.TImageList TSVG2BaseImageList TSVG2CustomLinkedImageList
Fpc BVE.SVG2ImageList.FPC.pas BVE.SVG2ImageList.FPC TCustomImageList TSVG2BaseImageList TSVG2CustomLinkedImageList
Fmx BVE.SVG2ImageList.FMX.pas BVE.SVG2ImageList.FMX FMX.ImgList.TCustomImageList TSVG2BaseImageList TSVG2CustomLinkedImageList

Description

The TSVG2LinkedImageList is almost the same as as a TSVG2ImageList. It has its own list of images and most of TSVG2ImageList properties are present in TSVG2LinkedImageList as well, the main difference is that it does not contain any SVG or Style data, but uses these from the TSVG2ImageList it is linked to.

This makes it possible to centralize the SVG and Style data in one place and use TSVG2LinkedImageList as "agents" on forms, that are set up for the needs of that particular form. Something like the new TVirtualImageList and TImageCollection in Delphi 10.3

Properties

The TSVG2LinkedImageList has two properties for linking with a TSVG2ImageList:


TSVG2Graphic


Source Unit Parent
Vcl BVE.SVG2Graphic.VCL.pas BVE.SVG2Graphic.VCL Vcl.Graphics.TGraphic
Fpc BVE.SVG2Graphic.FPC.pas BVE.SVG2Graphic.FPC TGraphic
Fmx Not available

Description

The TSVG2Graphic is a non-visible component. It is derived from TGraphic and so can be used as any other TGraphic derived classes (like TJPEGImage and TPngImage).

If you look at the initialization section of the BVE.SVG2Graphic.VCL.pas unit, you will see that the TSVG2Graphic is used to register the SVG file format.

initialization
  // Register the file format for load/save dialog
  TPicture.RegisterFileFormat('svg', 'Scalable Vector Graphics', TSVG2Graphic);

Because it is registered, the TOpenPictureDialog will recognize SVG files as a graphic format, and also you can load SVG files into the "Picture" property of Delphi's standard TImage control.

Properties

Methods

Events

Examples

See the "OpenPicture" project in the Examples folder.

For an example how to use TSVGGraphic see Assign an SVG to a TSVG2Graphic object and assign to a standard TImage.


SVG Controls

The SVG controls TSVG2Control, TSVG2Image and TSVG2LinkedImage can be used to display and interact with a single SVG. They are all derived from TSVGBaseControl. The main difference is where the SVG is stored and with what defaults the controls are initialized.


SVG source AutoViewbox Clipping
TSVG2Control From file
From strings
from a TSVG2Doc
False True
TSVG2Image From file
From strings
True False
TSVG2LinkedImage From an imagelist True False

The VCL version of the controls is derived from TGraphicControl. A TGraphicControl is rendered in the paint cycle of its parent TWinControl. As all VCL controls there will be some flicker if the control repaints itself, to avoid flicker you should set the "DoubleBuffered" property of the parent TWinControl to "True".

The FPC/Lazarus and FMX versions do not suffer from this flicker problem.


TSVG2BaseControl


Source Unit Parent
Vcl BVE.SVG2Control.VCL.pas BVE.SVG2Control.VCL Vcl.Controls.TGraphicControl
Fpc BVE.SVG2Control.FPC.pas BVE.SVG2Control.FPC TGraphicControl
Fmx BVE.SVG2Control.FMX.pas BVE.SVG2Control.FMX FMX.Controls.TControl

Description

TSVG2BaseControl is the base class for the SVG controls.

All measuring, rendering and interaction is defined in TSVG2BaseControl. The derived SVG controls only add the source for the SVG.

Properties

Methods

Events


TSVG2Control



Source Unit Parent
Vcl BVE.SVG2Control.VCL.pas BVE.SVG2Control.VCL TSVGBaseControl TSVG2CustomControl
Fpc BVE.SVG2Control.FPC.pas BVE.SVG2Control.FPC TSVGBaseControl TSVG2CustomControl
Fmx BVE.SVG2Control.FMX.pas BVE.SVG2Control.FMX TSVGBaseControl TSVG2CustomControl

Description

TSVG2Control is used for displaying and interacting with a single SVG. It inherits most of its properties, methods and events from TSVGBaseControl.

By default the control is clipped by the parent canvas and property "AutoViewBox" is False. The SVG can be read from file, stored in an internal TStringList object or read from a linked TSVG2Doc component.

Properties


TSVG2Image



Source Unit Parent
Vcl BVE.SVG2Image.VCL.pas BVE.SVG2Image.VCL TSVGBaseControl TSVG2CustomImage
Fpc BVE.SVG2Image.FPC.pas BVE.SVG2Image.FPC TSVGBaseControl TSVG2CustomImage
Fmx BVE.SVG2Image.FMX.pas BVE.SVG2Image.FMX TSVGBaseControl TSVG2CustomImage

Description

The TSVG2Image control is also used for displaying and interacting with a single SVG. It inherits most of its properties, methods and events from TSVGBaseControl.

By default the control is not clipped to the parent canvas and "AutoViewBox" is True. The SVG can be read from file or stored in an internal TStringList object.

Properties


TSVG2LinkedImage



Source Unit Parent
Vcl BVE.SVG2ImageList.VCL.pas BVE.SVG2ImageList.VCL TSVGBaseControl TSVG2CustomLinkedImage
Fpc BVE.SVG2ImageList.FPC.pas BVE.SVG2ImageList.FPC TSVGBaseControl TSVG2CustomLinkedImage
Fmx BVE.SVG2ImageList.FMX.pas BVE.SVG2ImageList.FMX TSVGBaseControl TSVG2CustomLinkedImage

Description

The is the same as an TSVGImage only it reads its SVG from a TSVG2ImageList.

Properties


Common methods of the SVG components


Common properties of the SVG components


Common events of the SVG components


Technical design

The following section explains the design and architecture of the package.

Process flow

The purpose of the package is to transform raw SVG data into a something that can be used in an application. This could be a raster image, for example a bitmap in one or more different sizes and/or provide a structure for changing, animating or interacting with the SVG data.

Basically there are two processing stages:

  1. Parsing the input SVG data and producing a document object model (DOM) which is represented in the package by the ISVGRoot interface.
  2. Rendering the DOM to the output.

The input SVG data is basically text structured as XML in which the elements and attributes provide the instructions of how the graphic should be rendered.

The output will almost always be a raster image in the form of a in memory 32bit bitmap with alpha (transparency channel). The alpha can be premultiplied or not depending on the platform. The bitmap can be converted to PNG or JPG of something else and written to file.

Optionally the render stage can also output an "object state tree" represented by an ISVGObjectState interface. For every visible element of the DOM a corresponding object state is created. Because the object state contains the bounding boxes of all visible elements, we can determine de elements behind every pixel in the raster image. This in turn is used to process mouse pointer events.

The renderer can also output EMS files. EMS files consist of GDI+ instructions and can only be produces by the GDI+ render context.

SVG v230 architecture diagram

Zooming in on the rendering process, this can be divided into two sub processes:

  1. Issuing drawing instructions to the render context
  2. Rasterization

Drawing instructions to the render context are similar to the drawing instructions you would give to the canvas: DrawRect, FillRect, DrawEllipse etc.

The ISVGRoot implementation has the capability to render itself to the render context, by issuing the render instructions in the correct order and if necessary apply transformations, rendering to intermediate buffers or loading external resources like referenced svg graphics or bitmaps. This is the core functionality provided by the package.

The rasterization is delegated to the render context implementation. An important part of this is drawing polygons often filled by a scan line algorithm, for which different render context implementations provide different solutions. The decision to delegate the rasterization to an external software package was made as to benefit from existing solutions and not to reinvent the wheel. These external software solutions are either already provided by the operating system (Direct2D, GDI+ for windows, Quartz for Mac) or are graphic packages developed by the Delphi FPC Lazarus community (Graphics32, Aggpas, BGRABitmap). Also this makes it easier to provide a multi platform SVG solution.

See section "Render Contexts" for a complete overview of available render contexts.

A similar approach is taken for fonts and the rendering of text. Rendering text for different languages can be very very complex, so the package provides interfaces to existing solutions from which you can choose: DirectWrite or GDI + Uniscribe for Windows, CoreText for Mac or Freetype if these are not available. An exception is SVG fonts. Officially SVG fonts are no longer supported by the SVG standard, but because they provide a platform independent solution for rendering text, the functionality is kept in the package.

The following diagram shows how text is rendered. The implementation of the ISVGTextLayout interface handles the conversion of text with style information to path data. The style information includes font family, font weight, font style and so on.

With this information a best fitting font is selected from the font source. This is a database of fonts implemented by the ISVGFontSource interface.

You can select the ISVGTextLayout implementation that you want to use with a "global define". For windows you can select DirectWrite or GDI fonts, for Mac you can select CoreText or you can select Freetype which is available for almost every operating system.

If you don't select a specific text layout implementation in the global defines, than only SVG fonts will be rendered.


SVG v230 text rendering diagram

The RenderContext and TextLayout are independent of each other. So on Windows for example, you could use Graphics32 as the render context implementation and DirectWrite as the text layout implementation.

See section "Text layouts" for a complete overview of available options for rendering text.


Global defines

The package uses include files for setting global parameters using defines. These defines determine which render context is used, which text layout and a number of other settings.

There is one common include file, CompilerSettings.inc on folder Common and there is one include file for each platform: ContextSettingsVCL.inc for VCL in folder Common\Vcl, ContextSettingsFMX.inc for Firemonkey in folder Common\Fmx and ContextSettingsFPC.inc" for FPC Lazarus in folder Common\Fpc.


CompilerSettings.inc

Most defines in this file are switches for handling platform and Delphi version differences and you should not change these. There are a couple of defines that can be changed, these are listed in following table:

Define Meaning Default setting
SVGInlining This will cause some code to be inlined, which can speed up the software at the exspense of a larger executable. On
SVGDEBUG This will draw boxes around elements, and is used to debug the code. Off
SVGD2Debug This will set Direct2D in debug mode so Direct2D errors and messages are visible in the Delphi message panel. Off
SVGProfiler This will enable a build in profiler, sometimes used for development of the package. Off
SVGInternetAccess This will allow resources to be loaded from internet. For this Indy components will be compiled in the software and you might have to install libeay32.dll and ssleay32.dll for support for https. Off

ContextSettingsVCL.inc

The defines in this include file determine which render context implementation and which text layout implementation is used in Delphi VCL applications.

Define Meaning Default setting
SVGDirect2d3D11 This will include the Direct2D render context implementation, which renders to a DirectX device context. Off
SVGDirect2dDWIC This will include the Direct2D render context implementation, which renders to a WIC bitmap. On
SVGGDIP This will include the GDI+ render context implementation, which uses GDI+ for rendering. Off
SVGAGGRenderer This will include a render context based on the "Modernised Anti Grain" graphics library. You need to download this library to be able to compile with this setting. Off
SVGGraphics32 This will include a render context based on the "Graphics32" library. You need to download this library to be able to compile with this setting. Off
SVGFontDirectWrite This will include a text layout implementation based on DirectWrite, for using system fonts and text formatting. On
SVGFontGDI This will include a text layout implementation based on GDI and Uniscribe, for accessing system fonts and formatting text. Off
SVGFreetype This Includes the Freetype text layout implementation for accessing system fonts. Text formatting is handled by the SVG control package. The freetype.dll is has to be available on the system. See "Freetype.org" for more info. Off

You are allowed to enable SVGDirect2d3D11, SVGDirect2dDWIC, SVGGDIP and SVGFontDirectWrite and SVGFontGDI all at the same time. In that case the system will select the render context and text layout at run time, out of the options available op target system.

For example you want to use Direct2D using WIC and if Direct2D is not available on the target system you want to use GDI+, you would enable both SVGDirect2dDWIC and SVGGDIP.

The system will try SVGDirect2d3D11 first if enabled, then SVGDirect2dDWIC and last SVGGDIP. The same for text layouts, it will first try SVGFontDirectWrite if enabled then SVGFontGDI.


ContextSettingsFMX.inc

The defines in this include file determine which render context implementation and which text layout implementation is used in Delphi Firemonkey (FMX) applications. Because Firemonkey can build to different operating system targets, there is a set of defines for each possible operating system.

Define Meaning Default setting
Microsoft Windows
SVGDirect2dDWIC This will include the Direct2D render context implementation, which renders to a WIC bitmap. Off
SVGGDIP This will include the GDI+ render context implementation, which uses GDI+ for rendering. Off
SVGAGGRenderer This will include a render context based on the "Modernised Anti Grain" graphics library. You need to download this library to be able to compile with this setting. Off
SVGFMXCanvas This will include a render context based on the default Firemonkey canvas. System fonts will also be accessed via the Firemonkey canvas. On
SVGFontDirectWrite This will include a text layout implementation based on DirectWrite, for using system fonts and text formatting. Off
SVGFontGDI This will include a text layout implementation based on GDI and Uniscribe, for accessing system fonts and formatting text. Off
SVGFreetype This Includes the Freetype text layout implementation for accessing system fonts. Text formatting is handeled by the SVG control package. The freetype.dll is has to be available on the system. Off
Apple OsX or iOS
SVGQUARTZ This will include a context implementation based on Quartz. Off
SVGAGGRenderer This will include a render context based on the "Modernised Anti Grain" graphics library. You need to download this library to be able to compile with this setting. This is not tested on iOS. Off
SVGFMXCanvas This will include a render context based on the default Firemonkey canvas. System fonts will also be accessed via the Firemonkey canvas. On
SVGFontCoreText This will include a text layout implementation based on CoreText, for using system fonts and text formatting. Off
SVGFreetype This Includes the Freetype text layout implementation for accessing system fonts. Text formatting is handeled by the SVG control package. The freetype.dll is has to be available on the system. Off
All other operating systems
SVGFMXCanvas This will include a render context based on the default Firemonkey canvas. System fonts will also be accessed via the Firemonkey canvas. On
SVGFreetype This Includes the Freetype text layout implementation for accessing system fonts. Text formatting is handeled by the SVG control package. The freetype.dll is has to be available on the system. Off

ContextSettingsFPC.inc

The defines in this include file determine which render context implementation and which text layout implementation is used in FPC Lazarus applications. Again because FPC Lazarus can build to different operating system targets, there is a set of defines for each possible operating system.

Define Meaning Default setting
Microsoft Windows
SVGDirect2d3D11 This will include the Direct2D render context implementation, which renders to a DirectX device context. Off
SVGDirect2dDWIC This will include the Direct2D render context implementation, which renders to a WIC bitmap. On
SVGBGRABitmap This will include a render context based on the "BGRABitmap" graphics library. You need to download this library to be able to compile with this setting. Off
SVGGraphics32 This will include a render context based on the "Graphics32" library. You need to download this library to be able to compile with this setting. Off
SVGAGGRenderer This will include a render context based on the "Modernised Anti Grain" graphics library. You need to download this library to be able to compile with this setting. Off
SVGFontDirectWrite This will include a text layout implementation based on DirectWrite, for using system fonts and text formatting. On
SVGFreetype This Includes the "Freetype" text layout implementation for accessing system fonts. Text formatting is handled by the SVG control package. The freetype.dll is has to be available on the system. Off
Darwin
SVGQuartz This will include a context implementation based on Quartz. On
SVGBGRABitmap This will include a render context based on the "BGRABitmap" graphics library. You need to download this library to be able to compile with this setting. Off
SVGGraphics32 This will include a render context based on the "Graphics32" library. You need to download this library to be able to compile with this setting. Off
SVGAGGRenderer This will include a render context based on the "Modernised Anti Grain" graphics library. You need to download this library to be able to compile with this setting. Off
SVGFontCoreText This will include a text layout implementation based on CoreText, for using system fonts and text formatting. On
SVGFreetype This Includes the "Freetype" text layout implementation for accessing system fonts. Text formatting is handeled by the SVG control package. The freetype.dll is has to be available on the system. Off
Linux
SVGBGRABitmap This will include a render context based on the "BGRABitmap" graphics library. You need to download this library to be able to compile with this setting. On
SVGGraphics32 This will include a render context based on the "Graphics32" library. You need to download this library to be able to compile with this setting. Off
SVGAGGRenderer This will include a render context based on the "Modernised Anti Grain" graphics library. You need to download this library to be able to compile with this setting. Off
SVGFreetype This Includes the "Freetype" text layout implementation for accessing system fonts. Text formatting is handeled by the SVG control package. The freetype.dll is has to be available on the system. On
Other operating systems have not been tested...

Render contexts

There are a number of different render context implementations available in the package. Sometimes there is more than one render context available for an operating system, you can select the render context you want to use as explained in the previous section. The quality of the rendered image depends for a large part on the underlying graphics library of the selected render context.


Render contexts for Delphi

Render context Supported OS* Graphics library Platform Quality Rendering speed
SVG2ContextD2D Windows 7 and higher Direct2D VCL, FMX Very good, some minor issues withe the stroke-cap. Very good
SVG2ContextGP Windows XP and higher GDI+ VCL, FMX Good, except the radial gradients Very good
SVG2ContextQuartz OsX, iOS Quartz FMX Good, radial gradient spread method not supported Very good
SVG2ContextFMX All OS supported by Firemonkey: Windows, OsX, Android, iOS,.. Implemented by Firemonkey FMX This is a rendercontext based on Delphi's FMX canvas implementations:
  • Windows good, gradients and stroking not fully supported
  • OSX good, gradients and stroking not fully supported
  • Android not very good
  • iOS also not good
  • Windows reasonable
  • OsX good
  • Android and iOS slow
SVG2ContextAgg Windows, OsX Aggpas VCL, FMX Good Good
SVG2ContextGR32 Windows, OsX Graphics32 VCL Good Good

Render contexts for FPC Lazarus

Render context Supported OS* Graphics library Quality Rendering speed
SVG2ContextD2D Windows 7 and higher Direct2D Very good, some minor issues with the stroke-cap in combination with stroke-width. Very good
SVG2ContextQuartz OsX Quartz Good, radial gradient spread method not supported Very good
SVG2ContextGR32 Windows, Osx,Linux Graphics32 Good Good
SVG2ContextAgg Windows, OsX, Linux Aggpas Good Good
SVG2BGRABitmap Windows, Osx, Linux BGRABitmap Reasonable: some SVG features are not fully supported. Good

*Only the operating system on which the package is tested is shown.


Direct2D render context

Supprted operating systems:

Windows Vista, Win7, Win8, Win10

Supported platforms:

Delphi VCL, Delphi FMX (Wic only), FPC Lazarus

Library:

The required header files are included in the package, in folder Common\Platform.

Limitations:

Small issue with stroking in case of zero length path segments.

Unit:

Common\Platform\BVE.SVG2ContextD2D.pas

Remarks:

The Direct2D render context is the main render context for Windows. Quality and speed is very good. It has a great amount of functionality.

There are two types of Direct2D render contexts available, one is based on the "Windows Imaging Component" (WIC), this is available from Direct10 and upwards, the other is based in de "Direct11 Device context".

Some of the rendering with the Direct11 version will be hardware accelerated (if avaiable). This will be especially be noticable if you use filters, but on the other hand, copying buffers between GPU and CPU will be slow.


GDI+ render context

Supprted operating systems:

Windows XP, Vista, Win7, Win8, Win10

Supported platforms:

Delphi VCL, Delphi FMX

Library:

The required header files are included with Delphi

Limitations:

Unit:

Common\Platform\BVE.SVG2ContextGP.pas

Remarks:

The  "Graphic Device Interface +"  is mainly used as a fall back in cases DirectX is not available, for example on older XP versions.

Speed is good, quality is reasonable, the main problem is that svg-style radial gradients are not supported.

The GDI+ render context has the capability to render to EMS files.


Quartz render context

Supprted operating systems:

OsX and iOS

Supported platforms:

Delphi FMX, FPC Lazarus

Library:

The required header files are included with Delphi and FPC Lazarus

Limitations:

The radial gradient does not support the spread-method.

Unit:

Common\Platform\BVE.SVG2ContextQuartz.pas

Remarks:

Quarz is a graphics library for Apple's OsX and iOS.

Speed is good, Quality is overall good but the radial gradient does not support the spread-method.

The IOS support is tested with the IOS simulator only.


FMX canvas render context

Supprted operating systems:

All operating systems that Delphi Firemonkey supports for your particular Delphi version.

Supported platforms:

Delphi FMX

Library:

The required files are included with Delphi

Limitations:

The radial gradient does not support the spread-method.

Unit:

Common\Platform\BVE.SVG2ContextFMX.pas

Remarks:

The FMX render context is just a wrapper around Delphi's FMX canvas, On the positive side, this canvas supports a lot of operating systems, including Android (XE5 and higher). On the negative side, quality is not consistent. On Windows, FMX wil use Direct2D and quality will be reasonable but not as good as the dedicated Direct2D render context, because FMX doesn't use all available functionality of Direct2D. On Android for example overall quality of the rendered output is not very good. Also rendering text will not be as precise as with the dedicated render contexts.


Aggpas render context

Supprted operating systems:

Windows, OsX, Linux

Supported platforms:

Delphi VCL, Delphi FMX, FPC/Lazarus

Library

https://github.com/BVerhue/AggPasMod

Limitations:

Small issue with stroking in case of zero length path segments.

Unit:

Common\Platform\BVE.SVG2ContextAgg.pas

Remarks:

Aggpas is a port of the "Anti grain graphics library". Quality is good, speed is good.


Graphics32 render context

Supprted operating systems:

Windows (VCL, FPC) and Osx (FPC)

Supported platforms:

Delphi VCL, FPC/Lazarus

Library

https://github.com/graphics32/graphics32

Limitations:

Because SVG style gradients are not supported in this library, some code is borrowed from Aggpas to implement these using a custom polygon filler.

Unit:

Common\Platform\BVE.SVG2ContextGR32.pas

Remarks:

Graphics32 is a graphics library for Delphi and Lazarus. It is in principle a library for raster image processing, but it also has vector graphics capabilities implemented by the VPR vector graphics engine, the status of this extension is not really clear. Quality is good, speed is good.


BGRABitmap render context

Supprted operating systems:

Windows, Osx, Linux

Supported platforms:

FPC Lazarus

Library

https://github.com/bgrabitmap/bgrabitmap

Limitations:

Unit:

Common\Platform\BVE.SVG2ContextBGRA.pas

Remarks:

BGRABitmap is a graphics library for FPC Lazarus. Quality is good, speed is good but it has some limitations for rendering SVG graphics.


Text layouts

For rendering of the <text> element, the library needs a font. At the moment the library supports two sources of fonts: "SVG fonts" or system fonts that are present on the local system.

SVG fonts

Officially "SVG fonts" are no longer supported by the SVG standard 2.0, but the SVG library still supports SVG fonts, because the advantage is that fonts can be used independent of the operating system. You can embed an SVG font directly into an SVG graphic or let your SVG graphic reference an external SVG font located in a seperate file. Examples of how to do this can be found in the "SVG 1.1 test suite".

There are multiple tools on the web to convert a TTF font to an SVG font.

The official way to go for fonts in SVG is with WOFF font files, but the library doesn't support this format at the moment. Of course using web fonts requires the device to be on-line when rendering the SVG containing the font.

System fonts

To access system fonts, the tools provided by the operating system can be used, for Windows this is GDI or DirectWrite and for OsX and iOS this is CoreText. In all other cases Freetype is used. If a particular font cannot be found, the system will use a fall back font, so It cannot be guaranteed that text will be rendered exactly the same on every device.

If you want your text to render exactly the same on each device the best way is to converting text elements to path elements. You can do this for example with "Inkscape".

The SVG control package uses a "ISVGFontSource" implementation as a library of fonts and a "ISVGTextLayout" implementation to format text.

The formatting of text consist of selecting fonts, applying fonts styles, bidi ordering of text, substitution of ligatures selecting glyphs, language specific processing and so on. This is done by the ISVGTextLayout implementation. After all that follows the SVG text processing for aligning, placing of individual glyphs or setting glyphs on a path.


Direct write

Supprted operating systems:

Windows Vista, Win7, Win8, Win10

Supported platforms:

Delphi FMX, FPC Lazarus

Library:

The required header files are included in the package, in folder Common\Platform

Limitations:

Have not found any.

Units

Common\Platform\BVE.SVG2FontDirectWrite.pas


GDI fonts and Uniscribe

Supprted operating systems:

Windows XP, Vista, Win7, Win8, Win10

Supported platforms:

Delphi VCL, Delphi FMX

Library:

The required header files are included with Delphi, the header for Uniscribe is included in the package, in folder Common\Platform

Limitations:

Has sometimes trouble finding the correct font.

Units

Common\Platform\BVE.SVG2FontGDI.pas


Core text

Supprted operating systems:

OsX and iOS

Supported platforms:

Delphi FMX, FPC Lazarus

Library:

The required header files are included with Delphi and FPC Lazarus

Limitations:

Have not found any.

Units

Common\Platform\BVE.SVG2FontCoreText.pas


Freetype

Supprted operating systems:

See website

Supported platforms:

Delphi VCL, FMX, FPC Lazarus

Library:

The required header files are included in the package, in folder Common\Platform

Limitations:

Units

Common\Platform\BVE.SVG2FontFreetype.pas


FMX canvas text layout

Supprted operating systems:

All operating systems that Delphi Firemonkey supports for your particular Delphi version.

Supported platforms:

Delphi FMX

Library:

The required files are included with Delphi

Limitations:

Units

Common\Platform\BVE.SVG2ContextFMX.pas


SVG types, interfaces and classes

Internally the library uses many different types, classes and interfaces. these mirror for a large part the definitions in the "SVG 1.1 specification".

For most applications, you do not need to know all the types, classes or interfaces, but just use text in SVG language, as described in the SVG 1.1 spec. to define the SVG graphic or create elements or set attribute values. The internal parser will convert the text into the appropriate type in the SVG hierarchy (DOM).

If you do need to find certain types, classes or interfaces, these can be found in the following units:

Unit Description
BVE.SVG2Types.pas Basic types and constants
BVE.SVG2Intf.pas Interface defininitions for SVG elements and render context objects
BVE.SVG2Attributes.pas SVG Attribute interface and implementation
BVE.SVG2Elements.pas Implementations for the SVG element interfaces
BVE.SVG2Context.pas implementations for the base render context and text layout objects
BVE.SVG2PathData.pas Pathdata class
BVE.SVG2Bidi.pas Contains an implementation of "UAX #9: Unicode Bidirectional Algorithm", used in case not provided by the text layout implementation
BVE.BVE.SVG2CSSUtility.pas CSS parsing and evaluation
BVE.SVG2FilterUtility.pas Implementation of filter effects, used in case not provided by the render context implementation
BVE.SVG2GeomUtility.pas Geometrical functions
BVE.SVG2ParseUtility.pas Base parser class and XML and SVG parser implementation
BVE.SVG2SaxParser.pas Builds the DOM tree using the XML reader
BVE.SVG2XMLReader.pas Parses XML files
BVE.SVG2Doc.pas TSVGDoc component

Some interfaces and classes that are often needed when rendering SVG programmatically (see "Programming examples"):

Class/interface Unit Description
TSVGSaxParser Common\BVE.SVG2SaxParser.pas Class for parsing SVG text and converting it to a tree structure with SVG elements as nodes (DOM) represented by ISVGRoot
ISVGRoot Common\ISVGIntf.pas Interface to the root of the DOM, this holds the SVG elements after parsing in a tree structure.
TSVGRootVCL Common\Vcl\BVE.SVG2Elements.VCL.pas Implementation of the root for VCL.
TSVGRootFMX Common\Fmxl\BVE.SVG2Elements.FMX.pas Implementation of the root for FMX.
TSVGRootFPC Common\Fpc\BVE.SVG2Elements.FPC.pas Implementation of the root for FPC.
IXMLNode XML.XMLIntf(Delphi)
Common\BVE.SVG2Types.pas (FPC)
Interface for an XML node object, all SVG elements interfaces are derived from IXMLNode
ISVGElement Common\ISVGIntf.pas Derived from IXMLNode, an interface to a SVG element.

Some usefull procedures and functions

Procedure/function Unit Description
SVGCreateElement BVE.SVG2Elements Creates am SVG element
SVGCreateTextNode BVE.SVG2Elements Creates a text node
SVGRenderToRenderContext BVE.SVG2Elements Render a parsed SVG graphic represented by ISVGRoot to a ISVGRenderContext
SVGObjectAt BVE.SVG2Elements Returns the element under the mousepointer of a parsed SVG graphic represented by ISVGRoot. [sroEvents] must be present in the RenderOptions property of ISVGRoot.
SVGMouseDown BVE.SVG2Elements Passes an OnMouseDown event to ISVGRoot to process. If processed, this will trigger an OnSVGEvent on ISVGRoot. [sroEvents] must be present in the RenderOptions property of ISVGRoot.
SVGMouseMove BVE.SVG2Elements Same for OnMouseMove
SVGMouseUp BVE.SVG2Elements Same for OnMouseUp
SVGRenderToBitmap BVE.SVG2Elements.VCL Render a parsed SVG graphic represented by ISVGRoot to a VCL bitmap. The render context used depends on the settings in Common\Vcl\ContextSettingsVCL.inc
SaveBitmapAsPng BVE.SVG2Elements.VCL Save a VCL bitmap as Png
SaveBitmapAsJpg BVE.SVG2Elements.VCL Save a VCL bitmap as Jpg
SVGRenderToBitmap BVE.SVG2Elements.FPC Render a parsed SVG graphic represented by ISVGRoot to an FPC Lazarus bitmap. The render context used depends on the settings in Common\Vcl\ContextSettingsFPC.inc
SaveBitmapAsPng BVE.SVG2Elements.FPC Save a VCL bitmap as Png
SaveBitmapAsJpg BVE.SVG2Elements.FPC Save a VCL bitmap as Jpg
SVGRenderToBitmap BVE.SVG2Elements.FMX Render a parsed SVG graphic represented by ISVGRoot to an FMX bitmap. The render context used depends on the settings in Common\Vcl\ContextSettingsFMX.inc

Supported SVG features

The following table lists the supported SVG functionality for version 2.3 of the SVG package. The functionality marked with "Yes" is supported in basis but that doesn't always mean for 100%. If there is a known significant part of functionality missing, it is mentioned in the remark.


Limitations


Elements

The following list indicates the implementation status of "svg elements" in the SVG library.


SVG Element Implemented Type Remarks
<a> No The a element is converted to a group element
<altGlyph> No
<altGlyphDef> No

<altGlyphItem> No

<animate> No

<animateColor> No

<animateMotion> No

<animateTransform> No
<circle> Yes ISVGCircle
<color-profile> No

<cursor> No

<clipPath> Yes ISVGClipPath
<defs> Yes ISVGDefs
<desc> Yes ISVGDesc
<ellipse> Yes ISVGEllipse
<feBlend> Yes ISVGFilterBlend
<feColorMatrix> Yes ISVGFilterColorMatrix
<feComponentTransfer> Yes ISVGFilterComponentTransfer
<feComposite> Yes ISVGFilterComposite
<feConvolveMatrix> Yes ISVGFilterConvolveMatrix
<feDiffuseLighting> Yes ISVGFilterDiffuseLighting
<feDisplacementMap> Yes ISVGFilterDisplacementMap
<feDistantLight> Yes ISVGFilterDistantLight
<feFlood> Yes ISVGFilterFlood
<feFuncA> Yes ISVGFilterFunc
<feFuncB> Yes ISVGFilterFunc
<feFuncG> Yes ISVGFilterFunc
<feFuncR> Yes ISVGFilterFunc
<feGaussianBlur> Yes ISVGFilterGuassianBlur
<feImage> Yes ISVGFilterImage
<feMerge> Yes ISVGFilterMerge
<feMergeNode> Yes ISVGFilterMergeNode
<feMorphology> Yes ISVGFilterMorphology
<feOffset> Yes ISVGFilterOffset
<fePointLight> Yes ISVGFilterPointLight
<feSpecularLighting> Yes ISVGFilterSpecularLighting
<feSpotLight> Yes ISVGFilterSpotlight
<feTile> Yes ISVGFilterTile
<feTurbulence> Yes ISVGFilterTurbulence
<filter> Yes ISVGFilter
<font> Yes ISVGFont
<font-face> Yes ISVGFontFace
<font-face-format> Yes ISVGFontFaceFormat
<font-face-name> Yes ISVGFontFaceName
<font-face-src> Yes ISVGFontFaceSrc
<font-face-uri> Yes ISVGFontFaceUri
<foreignObject> No
<g> Yes ISVGGroup
<glyph> Yes ISVGGlyph
<glyphRef> No

<hkern> Yes ISVGHKern
<image> Yes ISVGImage
<line> Yes ISVGLine
<linearGradient> Yes TSVGLinearGradient
<marker> Yes ISVGMarker
<mask> Yes ISVGMask
<metadata> No

<missing-glyph> No ISVGGlyph is used
<mpath> No
<path> Yes ISVGPath
<pattern> Yes ISVGPattern
<polygon> Yes ISVGPolygon
<polyline> Yes ISVGPolyline
<radialGradient> Yes ISVGRadialGradient Some render contexts do not fully support this, see "Render contexts".
<rect> Yes ISVGRect
<script> No

<set> No

<stop> Yes ISVGGradientPoint
<style> Yes
<svg> Yes ISVG
<switch> Yes ISVGSwitch
<symbol> Yes ISVGSymbol
<text> Yes ISVGText
<textPath> Yes ISVGTextPath
<title> Yes ISVGTitle
<tref> Yes ISVGTextRef
<tspan> Yes ISVGSpan
<use> Yes ISVGUse
<view> No
<vkern> Yes ISVGVKern

Presentation attributes

This is a list indicates the implementation status of the "presentation attributes" in the SVG control library.


Attribute Implemented Type Remarks
alignment-baseline No

baseline-shift Yes TSVGBaselineShift
clip-path Yes string
clip-rule Yes TSVGFillRule
clip Yes TSVGDimRect
color-interpolation-filters Yes TSVGColorSpace
color-interpolation Yes TSVGColorSpace
color-profile No

color-rendering No

color Yes TSVGColor
cursor No

direction Yes TSVGDirection
display Yes TSVGDisplay
dominant-baseline No

enable-background No
This attribute is to be removed from the SVG specs. and is replaced by the "isolation" attribute
fill-opacity Yes TSVGFloat
fill-rule Yes TSVGFillRule
fill Yes TSVGPaint
filter Yes string
flood-color Yes TSVGPaint
flood-opacity Yes TSVGFloat
font-family Yes TFontName
font-size-adjust No

font-size Yes TSVGFontSize
font-stretch Yes TSVGFontStretch
font-style Yes TSVGFontStyle
font-variant Yes TSVGFontVariant
font-weight
Yes TSVGFontWeight
glyph-orientation-horizontal
No


glyph-orientation-vertical
No


image-rendering
No


isolation Yes TSVGIsolationMode
Kerning
No


letter-spacing Yes TSVGSpacing
lighting-color Yes TSVGPaint
marker Yes string
marker-start Yes string
marker-mid Yes string
marker-end Yes string
mask Yes
string

opacity Yes TSVGFloat
overflow Yes TSVGOverflow
pointer-events Yes TSVGPointerEventsType
shape-rendering
No


stop-color Yes TSVGPaint

stop-opacity Yes TSVGFloat

stroke Yes TSVGPaint
stroke-opacity Yes TSVGFloat
stroke-width Yes TSVGDimension
stroke-linecap Yes TSVGStrokeCap
stroke-linejoin Yes TSVGStrokeJoin
stroke-miterlimit Yes TSVGFloat

stroke-dasharray Yes TSVGDimArray
stroke-dashoffset Yes TSVGDimension
text-anchor Yes TSVGTextAnchor
text-decoration Yes
TSVGTextDecoration

text-rendering No

unicode-bidi Yes TSVGUnicodeBidi

visibility Yes TSVGVisibility
word-spacing
No


writing-mode Yes TSVGWritingMode


CSS

CSS is implemented as case-sensitive at the moment. Anything that is not on the list is not supported.

Selector types Implemented
* (All) Yes
<element> Yes
Selectors
. (Class) Yes
# (ID) Yes
Attribute Yes
PseudoClass Yes
PseudoClassTypes
FirstChild Yes
LastChild (not possible with the sax-parser)
No
NthChild Yes
Language Yes
others... No
Attribute evaluators
Name only Yes
= (Equal) Yes
~= (Contains word) Yes
|= (Begins with word) Yes
^= (Begins with part of word) Yes
$= (Ends with word) Yes
*= (Contains part of word) Yes
others... No
Combinators
 (Descendant) Yes
> (Direct descendant) Yes
+ (Adjacent) Yes
~ (Preceding) Yes
others... No
Properties
See list of attributes

Programming examples

Here are some examples on how to use the package for rendering and modifying SVG graphics programmatically.

  1. Assign an SVG to a TSVG2Image
  2. Create a simple digital clock
  3. Create a filter graph
  4. Assign an SVG to a TSVG2Graphic object and assign to a standard TImage
  5. Render SVG programmatically
  6. Find and element the easy way
  7. Find and element the hard way: traverse the DOM tree
  8. Change an attribute
  9. Setting style attributes
  10. Add and remove elements
  11. Add an SVG fragment
  12. Find element under the mouse pointer
  13. Using mouse events
  14. Loading files from internet

The source code for these examples can be found in Examples\ExamplesFromDoc.


Assign an SVG to a TSVG2Image

Put a TSVG2Image on a form.

In the "OnCreate" event handler of the form put the following (replace.. with a valid path to the img folder)

Code

procedure TForm1.FormCreate(Sender: TObject);
begin
  SVG2Image1.Filename := '..\Img\Butterfly.svg';
end;

Create a simple digital clock

Put a TSVG2Image on a form and set property "Align" of the SVG2Image1 to "alClient".

For Delphi VCL set the "DoubleBuffered" property of the form to "True", to surpress flicker.

Put a TTimer on the form.

Add the following code to the unit:

Code

const
  svg_clock =
     '<svg xmlns="http://www.w3.org/2000/svg" version="1.1"'
    + ' viewBox="0 0 200 80">'
     + '<g font-family="courier new" font-size="24" text-anchor="middle">'
       + '<text x="100" y="30" fill="blue" >%s</text>'
       + '<text x="100" y="60" fill="blue" >%s</text>'
     + '</g>'
     + '<rect x="1" y="1" width="198" height="78" fill="none" stroke="blue" stroke-width="2" />'
   + '</svg>';

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  SVG2Image1.SVG.Text := Format(svg_clock, [DateToStr(Now), TimeToStr(Now)]);
  SVG2Image1.Repaint;
end;

Create a filter graph

Put a TSVG2Image on a form and set property "Align" of the SVG2Image1 to "alClient".

For Delphi VCL set the "DoubleBuffered" property of the form to "True", to surpress flicker.

Create an "OnCreate" handler on the form.

Add the following code to the unit.

Code

uses
  BVE.SVG2Types;

const
  // Filter borowed from here: http://luxor-xul.sourceforge.net/talk/jug-nov-2002/slides.html
  svg_filter = '<filter id="%s" width="%s" height="%s">%s</filter>';
  svg_filter_gaussian =
    '<feGaussianBlur in="%s" result="%s" stdDeviation="%d"  />';
  svg_filter_offset =
    '<feOffset in="%s" result="%s" dx="%d" dy="%d" />';
  svg_filter_composite =
    '<feComposite in="%s" in2="%s" result="%s" operator="%s" />';
  svg_filter_spec_light =
    '<feSpecularLighting in="%s" result="%s"'
    + ' surfaceScale="%d" specularConstant="%d" specularExponent="%d"'
    + ' kernelUnitLength="1" lighting-color = "%s">%s</feSpecularLighting>';
  svg_filter_light_distant =
    '<feDistantLight azimuth="%d" elevation="%d" />';

  svg_filter_text =
      '<svg>'
      + '%s'
      + '<g font-size="100" font-weight="bold">'
        + '<text x="20" y="320" fill="%s" filter="url(#myFilter)">%s</text>'
      + '</g>'
    + '</svg>';

procedure TForm1.FormCreate(Sender: TObject);
var
  Filter: string;
begin
  SVG2Image1.RenderOptions := [sroFilters, sroClippath];

  Filter :=
    Format(svg_filter, ['myFilter', '120%', '150%',
        Format(svg_filter_gaussian, ['SourceAlpha', 'gauss1', 6])
      + Format(svg_filter_offset, ['gauss1', 'offset', 5, 5])
      + Format(svg_filter_composite, ['SourceGraphic', 'offset', 'comp1', 'over'])
      + Format(svg_filter_gaussian, ['SourceAlpha', 'gauss2', 2])
      + Format(svg_filter_spec_light, ['gauss2', 'spec', -3, 1, 16, 'white',
            Format(svg_filter_light_distant, [45, 45])
            ])
      + Format(svg_filter_composite, ['spec', 'SourceGraphic', 'comp2', 'in'])
      + Format(svg_filter_composite, ['comp2', 'comp1', 'comp3', 'over'])
    ]);

  SVG2Image1.SVG.Text := Format(svg_filter_text, [filter, 'red', 'SVG rocks!']);
end;

Assign an SVG to a TSVG2Graphic object and assign to a standard TImage

The TSVG2Graphic class is derived from TGraphic, so you can use it in a standard (Delphi or FPC) TImage object.

Put a TImage object on a form.

Set the "Align" property of the Image1 object to "alClient".

Set the "Stretch" property of the Image1 object to "True"

Put the following code in the "OnCreate" handler of the form (replace .. with a valid path to the img folder):

Code

uses
{$IFnDEF FPC}
  BVE.SVG2Graphic.VCL;
{$ELSE}
  BVE.SVG2Graphic.FPC;
{$ENDIF}

procedure TForm1.FormCreate(Sender: TObject);
var
  Graphic: TSVG2Graphic;
begin
  Graphic := TSVG2Graphic.Create;
  try
    Graphic.LoadFromFile('..\Img\Butterfly.svg');
    Image1.Picture.Assign(Graphic);
  finally
    Graphic.Free;
  end;
end;

Render SVG programmatically

Here is an example how to load an SVG graphic from file, parse it and render it to a bitmap.

For FPC Lazarus, there is a small difference, we render to an interface to a bitmap in stead of to a bitmap directly. This has to do with differences in widget set implementations.

Put a TButton on a form and put a TOpenFIle dialog object on the form.

On the Button1 "OnClick" event handler put the following.

Add the following code to the unit.

Code

uses
{$IFnDEF FPC}
  BVE.SVG2Elements.VCL,
{$ELSE}
  BVE.SVG2Elements.FPC,
{$ENDIF}
  BVE.SVG2Intf,
  BVE.SVG2SaxParser;

procedure TfrmRenderProgrammatically.Button1Click(Sender: TObject);
{$IFnDEF FPC}
var
  FileName: string;
  SVGParser: TSVGSaxParser;
  SVGRoot: ISVGRoot;
  Bitmap: TBitmap;
begin
  // Code for Delphi VCL

  if OpenDialog1.Execute then
  begin
    FileName := OpenDialog1.FileName;

    // Create a root to store the SVG rendering tree

    SVGRoot := TSVGRootVcl.Create;

    // Create a SAX parser instance

    SVGParser := TSVGSaxParser.Create(nil);
    try

      // Parse SVG document and build the rendering tree

      SVGParser.Parse(FileName, SVGRoot);

      // Create a bitmap

      Bitmap := TBitmap.Create;
      try
        Bitmap.PixelFormat := TPixelFormat.pf32bit;   // 32bit bitmap
        Bitmap.AlphaFormat := TAlphaFormat.afDefined; // Enable alpha channel
        Bitmap.SetSize(480, 320);                     // Set desired size

        Bitmap.Canvas.Brush.Color := clNone; // Fill background with transparent
        Bitmap.Canvas.FillRect(Rect(0, 0, 480, 320));

        // Render the SVG onto the bitmap

        SVGRenderToBitmap(
          SVGRoot, // The root containing the rendering tree
          Bitmap   // The destination bitmap
          );

        // Do something with the bitmap...
        Canvas.Draw(30, 30, Bitmap);

      finally
        Bitmap.Free;
      end;

    finally
      SVGParser.Free;
    end;
  end;
end;

{$ELSE}

var
  FileName: string;
  SVGParser: TSVGSaxParser;
  SVGRoot: ISVGRoot;
  IntfBitmap: ISVGIntfBitmap;
  Bitmap: TBitmap;
begin
  // Code for FPC Lazarus

  if OpenDialog1.Execute then
  begin
    FileName := OpenDialog1.FileName;

    // Create a root to store the SVG rendering tree

    SVGRoot := TSVGRootFpc.Create;

    // Create a SAX parser instance

    SVGParser := TSVGSaxParser.Create(nil);
    try

      // Parse SVG document and build the rendering tree

      SVGParser.Parse(FileName, SVGRoot);

      // Create an interface bitmap.
      // Because of differences in widget set implementations we cannot
      // render to a bitmap directly, but must use an interface with the
      // appropriate implementation.

      IntfBitmap := SVGCreateIntfBitmap(480, 320);

      // Render the SVG onto the interface bitmap

      SVGRenderToBitmap(
        SVGRoot,    // The root containing the rendering tree
        IntfBitmap  // The destination bitmap
        );

      // Create a bitmap from the interface bitmap
      Bitmap := IntfBitmap.CreateBitmap;
      try

        // Do something with the bitmap...
        Canvas.Draw(30, 30, Bitmap);

      finally
        Bitmap.Free;
      end;

    finally
      SVGParser.Free;
    end;
  end;
end;
{$ENDIF}

Find and element the easy way

Put a TSVG2Image on a form and set property "Align" of the SVG2Image1 to "alClient".

For Delphi VCL set the "DoubleBuffered" property of the form to "True", to surpress flicker.

Create an "OnCreate" and an "OnKeyDown" handler on the form.

Add the following code to the unit.

Code

uses
  BVE.SVG2Intf;

const
  svg_text =
     '<svg viewBox="0 0 200 80">'
     + '<g font-family="courier new" text-anchor="middle">'
       + '<text id="text1" x="100" y="30" font-size="16" fill="blue" ></text>'
       + '<text id="text2" x="100" y="60" font-size="24" fill="red" ></text>'
     + '</g>'
     + '<rect x="1" y="1" width="198" height="78" fill="none" stroke="blue" stroke-width="2" />'
   + '</svg>';

procedure TForm1.FormCreate(Sender: TObject);
begin
  SVG2Image1.SVG.Text := svg_text;
end;

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
var
  Element: ISVGElement;
  ShiftValue: string;
begin
  // Find element with id = 'text1'
  Element := SVG2Image1.SVGRoot.Element['text1'];
  if assigned(Element) then
  begin
    ShiftValue := '';
    if ssShift in Shift then
      ShiftValue := ShiftValue + '[Shift]';
    if ssAlt in Shift then
      ShiftValue := ShiftValue + '[Alt]';
    if ssCtrl in Shift then
      ShiftValue := ShiftValue + '[Ctrl]';

    Element.Text := ShiftValue;
  end;

  // Find element with id = 'text2'
  Element := SVG2Image1.SVGRoot.Element['text2'];
  if assigned(Element) then
  begin
    Element.Text := IntToStr(Key);
  end;

  SVG2Image1.Repaint;
end;

Find and element the hard way: traverse the DOM tree

Sometimes you need to evaluate all nodes in an SVG graphic.

The following code traverses the DOM tree and outputs the structure to a memo.

Put a TSVG2Image on a form.

Put a TMemo on the form.

Add an "OnCreate" event handler to the form.

Add an "OnAfterParse" event handler to the SVG2Image1 object.

Add the following code to the unit:

Code

uses
  ...
{$IFnDEF FPC}
  XML.XMLIntf;
{$ELSE}
  BVE.SVG2Types;
{$ENDIF}

type
  TForm1 = class(TForm)
    SVG2Image1: TSVG2Image;
    Memo1: TMemo;
    procedure FormCreate(Sender: TObject);
    procedure SVG2Image1AfterParse(Sender: TObject);
  private
    procedure DoNode(aLevel: integer; aNode: IXMLNode);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses
  BVE.SVG2Intf;

const
  svg_text =
     '<svg viewBox="0 0 200 80">'
     + '<g font-family="courier new" text-anchor="middle">'
       + '<text id="text1" x="100" y="30" font-size="16" fill="blue" >Blue</text>'
       + '<text id="text2" x="100" y="60" font-size="24" fill="red" >Red</text>'
     + '</g>'
     + '<rect x="1" y="1" width="198" height="78" fill="none" stroke="blue" stroke-width="2" />'
   + '</svg>';

type
  TOnNodeEvent = procedure(aLevel: integer; aNode: IXMLNode) of object;

procedure Traverse(aNode: IXMLNode; aLevel: integer; aProcNode: TOnNodeEvent);
var
  i: integer;
begin
  aProcNode(aLevel, aNode);
  for i := 0 to aNode.ChildNodes.Count - 1 do
    Traverse(aNode.ChildNodes[i], aLevel + 1, aProcNode);
end;

procedure TForm1.DoNode(aLevel: integer; aNode: IXMLNode);
var
  Info: string;
begin
  Info := '<' +  aNode.LocalName + '>';
  if aNode.HasAttribute('id') then
    Info := Info + ' id: ' + aNode.Attributes['id'];

  Memo1.Lines.Add(StringOfChar(' ', aLevel*4) + Info);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  SVG2Image1.SVG.Text := svg_text;
end;

procedure TForm1.SVG2Image1AfterParse(Sender: TObject);
begin
  Memo1.Clear;
{$IFnDEF FPC}
  Traverse(SVG2Image1.SVGRoot.SVG, 0, DoNode);
{$ELSE}
  Traverse(SVG2Image1.SVGRoot.SVG, 0, @DoNode);
{$ENDIF}
end;


Change an attribute

The following example changes the "transform" attribute of a group element.

For Delphi VCL set the "DoubleBuffered" property of the form to "True", to surpress flicker.

Put a TSVG2Image on a form and set property "Align" of the SVG2Image1 to "alClient".

Put a TTimer on the form.

Add an "OnCreate" event handler to the form.

Add an "OnAfterParse" event handler to the SVG2Image1 object.

Add an "OnTimer" event handler on the Timer1 object.

Set the folowing properties of Timer1:

"Enabled = False"

"Interval = 25"

Add the following code to the unit:

Code

type
  TForm1 = class(TForm)
    SVG2Image1: TSVG2Image;
    Timer1: TTimer;
    procedure FormCreate(Sender: TObject);
    procedure SVG2Image1AfterParse(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
  private
    t: integer;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses
  BVE.SVG2Intf;

const
  svg_transform =
    'translate(%3.2f,%3.2f) rotate(%3.2f)';

  svg_orbit =
     '<svg width="200" height="200" viewBox="0 0 200 200">'
     + '<ellipse cx="100" cy="100" rx="100" ry="100" fill="none" stroke="blue" stroke-width="2" />'
     + '<g id="g1">'
       + '<circle cx="0" cy="0" r="20" fill="none" stroke="blue" stroke-width="2" />'
       + '<text x="0" y="12" text-anchor="middle" font-size="36" fill="blue" >A</text>'
     + '</g>'
   + '</svg>';

procedure TForm1.FormCreate(Sender: TObject);
begin
  SVG2Image1.SVG.Text := svg_orbit;
end;

procedure TForm1.SVG2Image1AfterParse(Sender: TObject);
begin
  t := 0;
  Timer1.Enabled := True;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var
  Element: ISVGElement;
  A1, A2, Ar: Double;
begin
  Element := SVG2Image1.SVGRoot.Element['g1'];
  if assigned(Element) then
  begin
    A1 := 360*(t mod 100)/100;
    Ar := A1*PI/180;

    A2 := -A1*100/20;

    Element.Attributes['transform'] :=
      Format(svg_transform, [100+80*Cos(Ar), 100+80*Sin(Ar), A2]);
  end;

  Inc(t);

  SVG2Image1.Repaint;
end;

Setting style attributes

In SVG there are three ways to define style:

  1. With an element attribute, for example:
    <rect width="50" height="50" fill="red"/>
  2. With a css style sheet, for example:

    <style type="text/css">
      rect {fill: red; stroke: none;}
    </style>
    <rect  width="50" height="50" />
  3. With an inline css style attribute, for example:
    <rect width="50" height="50" style="fill: red; stroke: none;"/>

The priority in which style is evaluated is 3, then 2, then 1, so inline style overrules style sheet style which in turn overrules the attribute style.

The following example demonstrates setting style.

Put a TSVG2Image on a form and set property "Align" of the SVG2Image1 to "alClient".

Add an "OnCreate" event handler to the form.

Add an "OnClick" event handler to the SVG2Image1 object.

Add the following code to the unit:

Code

uses
  BVE.SVG2Intf;

const
  svg_style1 =
      ' text {'
     + ' font-family: "courier new";'
     + ' font-size: 24;'
     + ' }';

  svg_style2 =
      ' text {'
     + ' font-family: "arial";'
     + ' font-size: 16;'
     + ' }';

  svg_text =
     '<svg viewBox="0 0 200 80">'
     + '<style id="stylesheet" type="text/css">'
     + svg_style1
     + '</style>'
     + '<g text-anchor="middle">'
       + '<text id="text1" x="100" y="30" fill="blue" >Blue</text>'
       + '<text id="text2" x="100" y="60" fill="red" >Red</text>'
     + '</g>'
     + '<rect x="1" y="1" width="198" height="78" fill="none" stroke="blue" stroke-width="2" />'
   + '</svg>';

procedure TForm1.FormCreate(Sender: TObject);
begin
  SVG2Image1.SVG.Text := svg_text;
end;

procedure TForm1.SVG2Image1Click(Sender: TObject);
var
  Element: ISVGElement;
begin
  // Change inline style (highes priority)

  Element := SVG2Image1.SVGRoot.Element['text2'];
  if assigned(Element) then
    Element.Attributes['style'] := 'font-family: "Times New Roman"; font-size: 24';

  // Change style sheet (medium priority)

  Element := SVG2Image1.SVGRoot.Element['stylesheet'];
  if assigned(Element) then
    Element.Text := svg_style2;

  // Change attribute (lowest priority, this will have no effect)

  Element := SVG2Image1.SVGRoot.Element['text1'];
  if assigned(Element) then
    Element.Attributes['font-family'] := 'Georgia';

  SVG2Image1.Repaint;
end;

Add and remove elements

The following example shows how to add or remove elements.

Put a TSVG2Image on a form and set property "Align" of the SVG2Image1 to "alClient".

Add an "OnCreate" event handler to the form.

Add an "OnClick" event handler to the SVG2Image1 object.

Add the following code to the unit:

Code

type
  TForm1 = class(TForm)
    SVG2Image1: TSVG2Image;
    procedure SVG2Image1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    FStep: integer;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses
{$IFnDEF FPC}
  XML.XMLIntf,
{$ENDIF}
  BVE.SVG2Types,
  BVE.SVG2Elements,
  BVE.SVG2Intf;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FStep := 0;
  SVG2Image1.SVG.Text := '';
end;

procedure TForm1.SVG2Image1Click(Sender: TObject);
var
  Node: IXMLNode;
begin
  case FSTep of
  0: begin
       Node := SVGCreateElement(TSVGIri.Empty, el_svg);
       SVG2Image1.SVGRoot.SVGList.Add(Node);

       Node.Attributes['width'] := '10cm';
       Node.Attributes['height'] := '8cm';
       Node.Attributes['viewBox'] := '0 0 100 80';

       Caption := 'SVG element created';
       Inc(FStep);
     end;

  1: begin
       Node := SVGCreateElement(TSVGIri.Empty, el_rect);
       SVG2Image1.SVGRoot.SVG.ChildNodes.Add(Node);

       Node.Attributes['id'] := 'rect';
       Node.Attributes['x'] := 0;
       Node.Attributes['y'] := 0;
       Node.Attributes['width'] := 100;
       Node.Attributes['height'] := 80;
       Node.Attributes['style'] := 'fill: yellow; stroke: blue;';

       Caption := 'Rect element created';
       Inc(FStep);
     end;

  2: begin
       Node := SVGCreateElement(TSVGIri.Empty, el_ellipse);
       SVG2Image1.SVGRoot.SVG.ChildNodes.Add(Node);

       Node.Attributes['cx'] := 50;
       Node.Attributes['cy'] := 40;
       Node.Attributes['rx'] := 50;
       Node.Attributes['ry'] := 40;
       Node.Attributes['style'] := 'fill: none; stroke: red;';

       Caption := 'Ellipse element created';
       Inc(FStep);
     end;

  3: begin
       Node := SVGCreateElement(TSVGIri.Empty, el_text);
       SVG2Image1.SVGRoot.SVG.ChildNodes.Add(Node);

       Node.Attributes['x'] := 50;
       Node.Attributes['y'] := 45;
       Node.Attributes['text-anchor'] := 'middle';
       Node.Attributes['style'] := 'font-family: "times"; font-size: 24; fill: red;';

       Node.Text := 'Ready...';

       Caption := 'Text element created';
       Inc(FStep);
     end;

  4: begin
       Node := SVG2Image1.SVGRoot.Element['rect'];
       if assigned(Node) then
         SVG2Image1.SVGRoot.SVG.ChildNodes.Remove(Node);

       Caption := 'Rect element removed';
       Inc(FStep);
     end;

  5: begin
       SVG2Image1.SVGRoot.SVG.ChildNodes.Clear;

       Caption := 'SVG child list cleared';
       FStep := 1;
     end;
  end;

  SVG2Image1.Repaint;
end;

Add an SVG fragment

Apart from adding elements one by one your can also add multiple elements at once to the ChildList of a node.

Method "AddFragment" of ISVGElement allows you to parse an xml fragment and add the result to the Childlist of the element.

Put a TSVG2Image on a form.

Add an "OnClick" event handler to the SVG2Image1 object.

Add the following code to the unit:

Code

uses
  BVE.SVG2Intf;

const
  svg_text =
     '<svg viewBox="0 0 200 80">'
     + '<g text-anchor="middle">'
       + '<rect x="20" y="20" width="160" height="40" fill="#101010" stroke="#CCCCCC" stroke-width="2" />'
       + '<text id="text"  x="100" y="45" fill="white" >Click me...</text>'
     + '</g>'
     + '<rect x="1" y="1" width="198" height="78" fill="none" stroke="blue" stroke-width="1" />'
   + '</svg>';

procedure TForm1.FormCreate(Sender: TObject);
begin
  SVG2Image1.SVG.Text := svg_text;
end;

procedure TForm1.SVG2Image1Click(Sender: TObject);
var
  Element: ISVGElement;
begin
  Element := SVG2Image1.SVGRoot.Element['text'];
  if assigned(Element) then
  begin
    Element.ChildNodes.Clear;
    Element.AddFragment('<tspan fill="yellow">Button <tspan fill="red" font-weight="bold" text-decoration="underline">clicked!</tspan></tspan>');
    SVG2Image1.Repaint;
  end;
end;


Find element under the mousepointer

The following example shows how to get an element that is under the mousepointer.
Only elements with physical dimensions can receive mousepointer events, these are elements that support the ISVGObject interface.

Put a TSVG2Image on a form.

Set property "Align" of the SVG2Image1 to "alClient".
Set the "Filename" property of SVG2Image1 to "animated-clock.svg" in the "Img" folder.
Set property "RenderOptions" to include "sroEvents" (for example [sroClippath,sroEvents]), this will enable catching mousepointer events.

Add an "OnMouseDown" event handler to the SVG2Image1 object.

Add the following code to the unit. The clicked element will be shown in the form's caption.


uses
  BVE.SVG2Types,
  BVE.SVG2Intf;

procedure TForm1.SVG2Image1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  SVGObject: ISVGObject;
begin
  SVGObject := SVG2Image1.SVGRoot.ObjectAtPt(SVGPoint(X, Y), FALSE);
  if assigned(SVGObject) then
    Caption := SVGObject.LocalName + ' id:' + SVGObject.ID
  else
    Caption := 'No object';
end;

Using mouse events

The following example shows how to use SVGpointer events.

The mouse event that you want to catch must be defined in the SVG graphic.

Put a TSVG2Image on a form.

Set property "Align" of the SVG2Image1 to "alClient".

Set property "RenderOoptions" to "[sroClippath,sroEvents]"

Add an "OnCreate" event handler to the form,.

Add an "OnSVGEvent" event handler to the SVG2Image1 object.

Add the following code to the unit.

All info linked to the event will be accessible through the ISVGEvent interface, which is passed to the event handler.

Code

uses
  ...
  BVE.SVG2Intf;

type
  TfrmMouseEvents = class(TForm)
    SVG2Image1: TSVG2Image;
    procedure SVG2Image1SVGEvent(Sender: TObject; aSVGRoot: ISVGRoot;
      aEvent: ISVGEvent; const aValue: string);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  frmMouseEvents: TfrmMouseEvents;

implementation

{$R *.dfm}

uses
  BVE.SVG2Types;

const
  svg_events =
      '<svg width="6cm" height="5cm" viewBox="0 0 600 500"'
     + ' xmlns="http://www.w3.org/2000/svg" version="1.1"'
     + ' xmlns:xlink="http://www.w3.org/1999/xlink">'
     + '<defs>'
       + '<ellipse id="ellipse_large" cx="300" cy="250" rx="300" ry="200" />'
     + '</defs>'
     + '<use id="use_back" onmouseover="MouseOver!" onmouseout="MouseOut!" onmousemove="MouseMove!" fill="red" stroke="black" stroke-width="1" xlink:href="#ellipse_large" />'
     + '<use id="use_left" onmouseover="MouseOver!" onmouseout="MouseOut!" onmousemove="MouseMove!" fill="green" stroke="black" stroke-width="4" transform="translate(-50,250) scale(0.25)" xlink:href="#ellipse_large" />'
     + '<use id="use_right" onmouseover="MouseOver!" onmouseout="MouseOut!" onmousemove="MouseMove!" fill="blue" stroke="black" stroke-width="4" transform="translate(500,250) scale(0.25)" xlink:href="#ellipse_large" />'
   + '</svg>';

procedure TfrmMouseEvents.FormCreate(Sender: TObject);
begin
  SVG2Image1.SVG.Text := svg_events;
end;

procedure TfrmMouseEvents.SVG2Image1SVGEvent(Sender: TObject;
  aSVGRoot: ISVGRoot; aEvent: ISVGEvent; const aValue: string);
var
  Info: string;
begin
  if aEvent.EventType <> etNone then
  begin

    // Only the eventtypes defined in the SVG will be catched!

    Info := aEvent.CurrentTarget.LocalName + ' id: ' + aEvent.CurrentTarget.ID + ' event: ';

    case aEvent.EventType of
      etClick:
        Info := Info + 'click';
      etMouseDown:
        Info := Info + 'mouseDown';
      etMouseUp:
        Info := Info + 'mouseUp';
      etMouseOut:
        Info := Info + 'mouseOut';
      etMouseMove:
        Info := Info + 'mouseMove';
      etMouseOver:
        Info := Info + 'mouseOver';
    end;
  end else
    Info := '';

  Caption := Info;
end;

Loading files from internet

The following example shows how to load files from internet.

Requirements for downloading files directly from the internet:

  1. Define InternetAccess must be enabled in CompilerSettings.inc.
  2. For SSL (https) libeay32.dll and ssleay32.dll must  be available on the system. Download from https://indy.fulgan.com/SSL/

The example loads SVG files from the SVG1.1 test suite and loads the corresponding Png file and then displays them side by side.

To enable loading files from internet  the define "SVGInternetAccess" must be enabled in include file "Common\CompilerSettings.inc".

Put a TSVG2Image on a form.

Next to it, put a TImage control on the form.

Set width = 480 and height = 360 on both controls.

Put a TButton on the form.

Add an "OnCreate" event handler to the form.

Add an "OnDestroy" event handler to the form.

Add an "OnClick" event handler to the Button1 object.

Add the following code to the unit:

Code

type
  TForm1 = class(TForm)
    SVG2Image1: TSVG2Image;
    Image1: TImage;
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    FStep: integer;
    Fsl: TStringList;
    FPath: string;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses
  BVE.SVG2SaxParser,
  BVE.SVG2Types,
  PngImage;

procedure TForm1.Button1Click(Sender: TObject);
var
  p: integer;
  Filename: string;
  MemStream: TMemoryStream;
  Png: TPngImage;
begin
  if FStep >= Fsl.Count then
    FStep := 0;

  if FStep < Fsl.Count then
  begin
    FileName := Fsl[FStep];
    Caption := FileName;

    try
      // Load the SVG file

      SVG2Image1.FileName := FPath + 'svg/' + FileName;

      // Load the corresponding Png file

      MemStream := TMemoryStream.Create;
      try
        p := Pos('.', FileName);
        Png := TPngImage.Create;
        try
          TSVGSaxParser.LoadFromInternet(FPath + 'png/' + copy(FileName, 1, p - 1) + '.png', MemStream);
          MemStream.Position := 0;
          Png.LoadFromStream(MemStream);
          Image1.Picture.Graphic := Png;
        finally
          Png.Free;
        end;

      finally
        MemStream.Free;
      end;

      except on E:Exception do
      begin
        Caption := Caption + ' Error: ' + E.Message;
      end;
    end;
  end;

  FStep := FStep + 1;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  MemStream: TMemoryStream;
  i: integer;
begin
  SVG2Image1.RenderOptions := [sroClippath, sroFilters];

  FPath := 'https://dev.w3.org/SVG/profiles/1.1F2/test/';

  Fsl := TStringList.Create;
  MemStream := TMemoryStream.Create;
  try
    // Load the list of files in the SVG1.1 test suite

    TSVGSaxParser.LoadFromInternet(FPath + '/svg/basic-files.txt', MemStream);
    TSVGSaxParser.LoadFromInternet(FPath + '/svg/tiny-files.txt', MemStream);
    TSVGSaxParser.LoadFromInternet(FPath + '/svg/full-files.txt', MemStream);

    MemStream.Position := 0;
    Fsl.LoadFromStream(MemStream);

    // Delete the testfiles that are not supprted
    i := 0;
    while i < Fsl.Count do
    begin
      // Note: not all test svg's will render correctly, filter out the
      // svg groups that are not supported in any case.

      if (Pos('animate-', Fsl[i])<>0)
      or (Pos('interact-', Fsl[i])<>0)
      or (Pos('script-', Fsl[i])<>0)
      or (Pos('struct-dom-', Fsl[i])<>0)
      or (Pos('text-dom-', Fsl[i])<>0)
      or (Pos('text-tselect-', Fsl[i])<>0)
      then
        Fsl.Delete(i)
      else
        Inc(i);
    end;


    Fsl.Sort;
  finally
    MemStream.Free;
  end;

  FStep := 0;
  Button1Click(Self);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  Fsl.Free;
end;

SVG Viewer applications

The purpose of these viewer applications is to demonstrate the functionality of the SVG package but also to provide some coding examples for working with the SVG in application development.


SVG viewer VCL


SVG Viewer for VCL screenshot

The demo viewer is a viewer for SVG graphics and build with the VCL framework, so Windows only.


SVG viewer FMX


Demo SVG viewer for FMX screenshot

The demo viewer is a viewer for SVG graphics and build with the FMX framework, it compiles on all platforms.

It has more or less the same functionality as the VCL viewer, but additionally it also supports global scalling, with the slider on the right.


Bug reporting

It is not unlikely that at some point you run into a bug. I spend a lot of time testing, but considering that the package supports 10 Delphi versions, the VCL, FMX and FPC Lazarus platform and possibly 4 operating systems, the number of test scenarios add up and some bugs may slip through.

If you find a bug you can send me an email at BVerhue@gmail.com and I will do my best to solve it.

In your bug report please name:

  1. the Delphi or FPC and Lazarus version you are using
  2. the platform you are using (VCL or FMX or FPC Lazarus)
  3. the operating system
  4. and if possible send the SVG graphic that triggers the bug.

It is not guaranteed that I can solve everything, some render contexts are limited or do not support all functionality needed for rendering the full SVG specification. See sections "Render contexts" and "Text layouts" for known limitations.


Future development

With this new version I hope I made another step to a more complete and more useful SVG implementation for Delphi and FPC Lazarus. Of course adding SVG functionality is something I will keep on doing.

If you have any suggestions for the control, you can send it to me. I can't guaranty I will be able to implemented it, but I'll have a go. I am developing this control in my free time so I don't have an unlimited time for development.

See the website for updates and more examples

https://www.bverhue.nl/delphisvg

Bruno Verhue, Delft 2019

BVerhue@gmail.com


License

See the order page on the Delphi SVG site or see the License.txt that is included in the package.