Drawing outlines around SVG elements

Drawing outlines around SVG elements

 

The SVG control package offers a number of controls to display SVG graphics. But if you want more control over how SVG graphics are rendered or if you want to post process graphics, you can also use the lower level classes, interfaces and functions of the package.

 

Two of these interfaces are

ISVGRenderContext

and

ISVGRoot

 

ISVGRenderContext is a high quality canvas, very much like the Delphi Firemonkey canvas, but it has the advantage that you can use it in Delphi VCL also. It always draws to a bitmap which you have to supply.

It has most of the drawing functions that the Firemonkey canvas has. Functions like DrawCircle, DrawRect, FillRect, FillPath, ApplyFill, ApplyStroke, MultiplyMatrix BeginScene, EndScene and so on.

You can use the render context (RC) for example to add drawings before or after you render an SVG graphic, or you could just use it for high quality drawings, also supporting transparency, something Delphi VCL does not excel in.

ISVGRoot is the root of the tree of SVG elements of the SVG graphic, equivalent to the Document Object Model (DOM)  in an internet browser. This is created after parsing the SVG xml text and allows you to manipulate elements and parameters before actually rendering the graphic. You can also use it to measure element dimensions.

I’ll give an example here how you can use both to render an SVG graphic an then to post process the graphic to draw some outlines around some of the elements in the SVG graphic.

We use the following simple SVG graphic and we will draw outlines around the text, star group an rotated ellipse.

 

This SVG graphic looks like this

 

Now for the code.

In a new Delphi VCL application, using one form with a standard TButton and TImage control, on the OnClick of the button we do the following:

  1. First we will create an SVGRoot object and parse the SVG text
  2. Then we will calculate the size of the entire SVG and set the bitmap size accordingly
  3. Then we will render the SVG to the bitmap
  4. Then we will draw rectangles around the three elements
  5. Last we assign the bitmap to the TImage control

 

Step 1, create SVGRoot object and parse the SVG text.

 

Step 2, calculate the size of the entire SVG and set the bitmap size accordingly

Next we want to know the dimensions of the SVG graphic. In this case it is not very difficult because the svg element has a with (480) and a height(320) defined. But for this example I’ll show how to calculate the size of an arbitrary SVG graphic.

The ISVGRoot interface has a method “CalcIntrinsicSize”  for calculating the outer dimensions of an SVG graphic.

This method is defined as follows:

So it needs a render context and the bounds of a parent object, this is the outer container. The function returns a rectangle with the dimensions of the SVG graphic.

Why does it need a render context? Because the SVG graphic may contain text and it needs a render context to have access to the font system.

The aParentBounds is used in cases where the SVG size is a percentage of it’s parent or container object.

So to use this we need to create a render context first. Since we don’t have to actually render the SVG yet, we can create a render context based on an arbitrary sized bitmap, so we take a bitmap of size 1 by 1.

 

Step 3, render the SVG to the bitmap

Now we are going to render the SVG to the bitmap using ISVGRoot and ISVGRenderContext.

So just as with drawing on a Firemonkey canvas, we need to enclose any drawing with BeginScene and EndScene commands. We could also modify the matrix of the render context to scale or rotate or translate the SVG graphic.

The global procedure “SVGRenderToRenderContext” is used to draw the SVG contained in “SVGRoot” to the render context “RC”.

This procedure is defined as follows:

The parameter “aRenderOptions” can have a combination of the following settings:

  • sroFilters: SVG filters will be rendered if these are defined in the SVG graphic
  • sroClippath: clippaths will be rendered if these are defined in the SVG graphic
  • sroEvents: mouse pointer events will be enabled for the SVG graphic, for this a Object state tree will be generated

Because filters, clippaths en events need extra, in some cases a lot of resources, they are made optional.

The last option “sroEvents” is interesting if we want to have measurements of individual elements in the SVG graphic. If we want to enable mouse pointer events, we need to know the dimensions of each visible element. The renderer will in that case create a so called “ObjectState” tree , while rendering the SVG graphic.

The “ObjectState” tree will contain a ScreenBBox (bounding box in screen dimensions) of every element visible on the screen. Note that sometimes an element can be drawn multiple times on the screen, if it is referenced by a “use” element. In that case it will be present more than once in the Object State tree.

So we will use the “ObjectState” tree to draw outlines around elements on the rendered SVG.

Step 4, draw rectangles around the three elements and step 5, assign bitmap to TImage control

This produces the following output on the VCL form.

 

 

You can download the sources here, to compile it, you need the demo or the full version of the SVG control package v2.2

SVGDrawing

Leave a Comment