Scalable Vector Graphics (SVG) images

Ibex supports the inclusion of Scalable Vector Graphics (SVG) images in the PDF file. SVG images retain their vector format inside the PDF file, so will remain precise under high magnification unlike bitmap images which will be come pixellated.

SVG images are inserted into the document using either the <fo:external-graphic> or <fo:instream-foreign-object> elements. Images can be included inline like this:

<fo:block border="1pt solid red">
	<fo:instream-foreign-object>
		<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20">
			<rect width="10" height="10" fill="green"/>
		</svg>
	</fo:instream-foreign-object>
</fo:block>

or from an external file like this:

<fo:block border="1pt solid red">
	<fo:external-graphic src="url(file.svg)"/>
</fo:block>

where the external file contains the SVG image, for example:

<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20">
	<rect width="10" height="10" fill="green"/>
</svg>

If an image occurs more than once in the document it should be loaded from an external file so that it is only store in the PDF once.

Namespaces

The SVG image must begin with the <svg> element in the namespace "http://www.w3.org/2000/svg". Images which do not declare the namespace will not be included in the PDF, they will be ignored. The https namespace "https://www.w3.org/2000/svg" does not work.

Image size

The size of the image should be specified using the width and height attributes on the outer <svg> element. These can be absolute measurements such as "3cm" or scalar values such as "400". Scalar values are assumed to be pixels and are converted to inches based on 1 pixel = 1/96 inch. Percentages cannot be effectively used; the size of the block containing the image is determined from the size of the image, at the time the image is processed the size of the containing block is unknown because it is dependent on the size of the image.

Summary of supported elements

This section briefly documents the degree to which SVG elements are supported in Ibex. It is not an SVG manual. Information on the SVG specification can be found at http://www.w3.org/TR/SVG11/expanded-toc.html.

Animation of SVG elements using javascript is not supported.

<svg>

The <svg> element is used to define the size and shape of the image (using the width and height attributes) and to establish a new coordinate system using the viewBox attribute.

<g>

The <g> element is used to move the coordinate system using the transform attribute. Supported transform operations are:

Operation Effect
translate(x,y) translate the coordinate system x units horizontally and y units vertically
translate(x) translate the coordinate system x units horizontally and zero units vertically
matrix(a,b,c,d,e,f) multiply the current transformation matrix by the one specified
scale(x,y) scale the coordinate system x units horizontally and y units vertically
rotate(angle) rotate the coordinate system angle degrees about the origin
rotate(angle,x,y) rotate the coordinate system angle degrees about the point x,y
skewX(angle) skew the coordinate system angle degrees along the X axis
skewY(angle) skew the coordinate system angle degrees units along the Y axis

Multiple transformations can be performed by placing them one after the other in the transform attribute, like this:

<g transform="translate(10,20) scale(2,3) rotate(30)">

Transforms will be applied in the order in which they appear.

<defs>

The <defs> element is supported as a container for other elements. See <symbol> below for an example.

<desc>

The <desc> element is ignored.

<title>

The <title> element is ignored.

<symbol>

The <symbol> element is supported. The following image shows an example of definining a system using <symbol> and retrieving it using <use>.

<?xml version="1.0" standalone="yes"?>
<svg width="10cm" height="3cm" viewBox="0 0 100 30" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
	<defs>
		<symbol id="MySymbol" viewBox="0 0 20 20">
			<rect x="1" y="1" width="8" height="8"/>
			<rect x="11" y="1" width="8" height="8"/>
			<rect x="1" y="11" width="8" height="8"/>
			<rect x="11" y="11" width="8" height="8"/>
		</symbol>
	</defs>
	<use x="45" y="10" width="100" height="100" xlink:href="#MySymbol" fill="blue" />
</svg>

The element will find the symbol element with id="#MySymbol" and display the content of this element, which should look like this:

Figure 16-1: SVG Symbol

<use>

The <use> element is supported, see above for an example. Note that as this element uses the xlink:href attribute it is necessary to declare the xmlns:xlink="http://www.w3.org/1999/xlink" namespace.

<image>

The <image> element is supported. This element embeds an image inside the SVG image. For example this image will display a rectangle and on top of that display the image held in the file "use_symbol.svg":

<?xml version="1.0"?>
<svg width="4cm" height="2cm" viewBox="0 0 200 100" xmlns="http://www.w3.org/2000/svg" version="1.1" preserveAspectRatio="none">
	<rect width="300" height="150" stroke="red" stroke-width="1" fill="silver"/>
	<image x="20" y="20" xlink:href="use_symbol.svg" width="100" height="100"/>
</svg>

<switch>

The <switch> element is ignored.

<path>

The <path> element is supported. Internally PDF does not support quadratic Bézier curves so they are converted to cubic Bézier curves. The following SVG draws a simple curve with marked end points:

<?xml version="1.0" standalone="no"?>
<svg width="6cm" height="5cm" viewBox="0 0 1200 600" xmlns="http://www.w3.org/2000/svg">
	<rect x="1" y="1" width="1198" height="598" fill="none" stroke="blue" stroke-width="1" />
	<path d="M200,300 Q400,50 600,300 T1000,300" fill="none" stroke="red" stroke-width="5"  />
	<!-- End points -->
	<g fill="black" >
		<circle cx="200" cy="300" r="10"/>
		<circle cx="600" cy="300" r="10"/>
		<circle cx="1000" cy="300" r="10"/>
	</g>
	<!-- Control points and lines from end points to control points -->
	<g fill="#888888" >
		<circle cx="400" cy="50" r="10"/>
		<circle cx="800" cy="550" r="10"/>
	</g>
	<path d="M200,300 L400,50 L600,300L800,550 L1000,300"fill="none" stroke="#888888" stroke-width="2" />
</svg>

The curve looks like this:

Path line join shapes

The shape where a path changes direction is set with the stroke-linejoin attribute. Possible values are:

Value Shape
stroke-linejoin="miter"
stroke-linejoin="bevel"
stroke-linejoin="round"

<style>

The <style> element is currently implemented to some extent in .Net. In .Net the class attribute can be used in conjunction with a style to apply that style to an element.

<rect>

The <rect> element is supported. A simple rectangle can be drawn like this:

<svg xmlns="http://www.w3.org/2000/svg" width="400" height="120" >
<rect x="10" y="10" width="100" height="100" fill="none" stroke="red"/>
</svg>

resulting in this image:

<circle>

The <circle> element is supported. A simple circle can be drawn like this:

<svg xmlns="http://www.w3.org/2000/svg" width="400" height="120" >
	<circle cx="50" cy="50" r="30" fill="none" stroke="red"/>
</svg>

resulting in this image:

<ellipse>

The <ellipse> element is supported. A simple ellipse can be drawn like this:

<svg xmlns="http://www.w3.org/2000/svg" width="400" height="200" >
	<ellipse cx="100" cy="100" rx="75" ry="50" fill="none" stroke="black"/>
</svg>

resulting in this image:

<line>

The <line> element is supported. A simple line can be drawn like this:

<svg xmlns="http://www.w3.org/2000/svg" width="400" height="400" >
<line x1="10" y1="10" x2="100" y2="10" stroke="blue" stroke-width="4"/>
</svg>

resulting in this image:

Line end shapes

The shape of the end of a line is set with the stroke-linecap attribute. Possible values are:

Value Shape
stroke-linecap="butt"
stroke-linecap="round"
stroke-linecap="square"

The end of the line is the same shape as the default stroke-linecap="butt" but projects further beyond the end coordinate.

Dashed lines

Dashed lines are supported using the stroke-dasharray attribute. A dashed line can be drawn like this:

<svg xmlns="http://www.w3.org/2000/svg" width="400" height="400" >
<line x1="10" y1="10" x2="100" y2="10" stroke="blue" stroke-width="4" stroke-dasharray="3 2"/>
</svg>

resulting in this image:

<polyline>

The <polyline> element is supported. A simple polyline can be drawn like this:

<svg xmlns="http://www.w3.org/2000/svg" width="12cm" height="4cm" viewBox="0 0 1200 400">
<polyline fill="none" stroke="blue" stroke-width="10"
	points="50,375,150,375 150,325 250,325 250,375,350,375 350,250 450,250 450,375,550,375 550,175 650,175 650,375,
	750,375 750,100 850,100 850,375,950,375 950,25 1050,25 1050,375,1150,375" />
</svg>

resulting in this image:

<polygon>

The <polygon> element is supported. A simple polygon can be drawn like this:

<svg xmlns="http://www.w3.org/2000/svg" width="12cm" height="4cm" viewBox="0 0 1200 400">
	<polygon fill="red" stroke="blue" stroke-width="10" points="350,75  379,161 469,161 397,215,423,301 350,250 277,301 303,215,231,161 321,161" />
	<polygon fill="lime" stroke="blue" stroke-width="10" points="850,75  958,137.5 958,262.5,850,325 742,262.6 742,137.5" />
</svg>

resulting in this image:

<text>

The <text> element is supported.

amp;lt;tspan>

The <tspan> element is not implemented.

<textpath>

The <textpath> element is not implemented.

<pattern>

The <pattern> element is not implemented.

Opacity

The attributes stroke-opacity and fill-opacity are supported. Using the group opacity attribute to apply opacity to a group of elements is not supported, instead the opacity value is applied as if stroke-opacity and fill-opacity has been specified. This example shows a transparent blue rectangle drawn over an opaque red rectangle.

<svg xmlns="http://www.w3.org/2000/svg" width="400" height="140" >
	<rect width="400" height="140" fill="none" stroke="silver"/>
	<g transform="translate(10,10)">
		<rect width="100" height="100" fill="red"/>
	</g>
	<g transform="translate(30,30)">
		<rect width="100" height="100" fill="blue" stroke-width="1" fill-opacity="0.3" />
	</g>
</svg>

resulting in this image:

Markers

Markers are supported at the start and end of and elements. The element contains a separate drawing which can be reused. This example shows an arrowhead which is drawn at the each end of a line:

<?xml version="1.0" standalone="no"?>
<svg width="4in" height="2in" viewBox="0 0 4000 2000" version="1.1" xmlns="http://www.w3.org/2000/svg">
	<defs>
		<marker id="RedTriangle" viewBox="0 0 10 10" refX="0" refY="5" markerUnits="strokeWidth" markerWidth="4" markerHeight="3" orient="auto" fill="red">
			<path d="M 0 0 L 10 5 L 0 10 z" />
		</marker>
	</defs>

	<rect x="10" y="10" width="3980" height="1980" fill="none" stroke="blue" stroke-width="10" />
	<g transform="translate(400,1700) scale(.8)">
		<line x1="0" x2="1000" y1="0" y2="0" stroke="red" stroke-width="100" marker-end="url(#RedTriangle)" marker-start="url(#RedTriangle)"/>
	</g>
	<g transform="translate(400,700) scale(.8)">
	<line x1="0" x2="1000" y1="300" y2="0" stroke="red" stroke-width="30" marker-end="url(#RedTriangle)" marker-start="url(#RedTriangle)"/>
	</g>
</svg>

In this example the arrowhead appears once in the SVG, and is rendered four times. Each time it is rendered its rotaton and size are changed to match the rotation and size of the line.

Linear gradients

Linear gradients are supported. This example produces a gradient from red to yellow horizontally:

<?xml version="1.0" standalone="no"?>
<svg width="8cm" height="4cm" viewBox="0 0 800 400" version="1.1" xmlns="http://www.w3.org/2000/svg">
	<g>
		<defs>
			<linearGradient id="MyGradient" x1="100" x2="500" gradientUnits="userSpaceOnUse">
				<stop offset="5%" stop-color="#F60" />
				<stop offset="95%" stop-color="#FF6" />
			</linearGradient>
		</defs>
		
		<rect fill="none" stroke="blue" x="1" y="1" width="798" height="398"/>
		<rect fill="url(#MyGradient)" stroke="black" stroke-width="5" x="100" y="100" width="600" height="200"/>
	</g>
</svg>

producing this image:

The interpretation of the values specified for the coordinates x1/x2/y1/y2 of the linearGradient element changes depending on value specified for gradientUnits. When gradientUnits="userSpaceOnUse" the specified values are in "user space", which is the space defined by the prevailing <g> element. The specified coordinates are relative to the prevailing <g> element, so two elements which use the same gradient as their fill color will appear differently if they are placed in different locations on the page. This SVG image shows rectangles using the same gradient in conjunction with gradientUnits="userSpaceOnUse"

<?xml version="1.0" standalone="no"?>
<svg width="8cm" height="3cm" viewBox="0 0 1000 450" version="1.1" xmlns="http://www.w3.org/2000/svg">
	<g>
		<defs>
			<linearGradient id="linear_userSpaceOnUse" gradientUnits="userSpaceOnUse" x1="100" y1="100" x2="700" y2="300">
				<stop offset="5%" stop-color="#ff0000" />
				<stop offset="95%" stop-color="#0000ff" />
			</linearGradient>
		</defs>

		<rect fill="none" stroke="blue" x="1" y="1" width="990" height="440"/>
		<g transform="translate(10,50)">
			<rect fill="url(#linear_userSpaceOnUse)" x="10" y="10" width="600" height="100"/>
			<rect fill="url(#linear_userSpaceOnUse)" x="200" y="120" width="600" height="100"/>
		</g>
	</g>
</svg>

producing this image:

When gradientUnits="objectBoundingBox" the specified values are relative to the bounding box of the element being filled, and should be expressed as fractions of the dimensions of the element being filled. The values for coordinates should be in the range [0..1], so for example specifying x1="0" starts the gradient at the left hand edge of the element being filled, and specifying x1="0.2" starts the gradient at 20% of the width of that element. As the gradient is positioned relative to the element being filled, two element using the same gradient will appear the same regardless of the position of the element.

This SVG image shows rectangles using the same gradient in conjunction with gradientUnits="objectBoundingBox"

<?xml version="1.0" standalone="no"?>
<svg width="8cm" height="3cm" viewBox="0 0 1000 450" version="1.1" xmlns="http://www.w3.org/2000/svg">
	<g>
		<defs>
			<linearGradient id="linear_objectBoundingBox" x1="0" y1="0" x2="1" y2="1">
				<stop offset="5%" stop-color="#ff0000" />
				<stop offset="95%" stop-color="#0000ff" />
			</linearGradient>
		</defs>
	
		<rect fill="none" stroke="blue" x="1" y="1" width="990" height="440"/>
		<g transform="translate(10,50)">
			<rect fill="url(#linear_userSpaceOnUse)" x="10" y="10" width="600" height="100"/>
			<rect fill="url(#linear_userSpaceOnUse)" x="200" y="120" width="600" height="100"/>
		</g>
	</g>
</svg>

producing this image:

Radial gradients

Radial gradients are supported from version 5.7.6 onwards. The interpretation of the values specified for the coordinates cx/cy/r/fx/fy of the radialGradient element changes depending on value specified for gradientUnits.

When gradientUnits="userSpaceOnUse" the specified values are in "user space", which is the space defined by the prevailing <g> element. The specified coordinates are relative to the prevailing <g> element, so two elements which use the same gradient as their fill color will appear differently if they are placed in different locations on the page.

This SVG image shows rectangles using the same gradient in conjunction with gradientUnits="userSpaceOnUse"

<?xml version="1.0" standalone="no"?>
<svg width="8cm" height="3cm" viewBox="0 0 1000 550" version="1.1" xmlns="http://www.w3.org/2000/svg">
	<g>
		<defs>
			<radialGradient id="radial_userSpaceOnUse" gradientUnits="userSpaceOnUse" cx="400" cy="200" r="300" fx="400" fy="200">
				<stop offset="0%" stop-color="green" />
				<stop offset="50%" stop-color="blue" />
				<stop offset="100%" stop-color="red" />
			</radialGradient>
		</defs>
		<rect fill="none" stroke="blue" x="1" y="1" width="990" height="530"/>
		<rect fill="url(#radial_userSpaceOnUse)" stroke="black" stroke-width="5" x="100" y="100" width="600" height="200"/>
		<rect fill="url(#radial_userSpaceOnUse)" stroke="black" stroke-width="5" x="100" y="310" width="600" height="200"/>
	</g>
</svg>

producing the image below, in which you can clearly see the gradient circles are centered within the first rectangle.

When gradientUnits="objectBoundingBox" the specified values are relative to the bounding box of the element being filled, and should be expressed as fractions of the dimensions of the element being filled. The values for coordinates should be in the range [0..1], so for example specifying x1="0" starts the gradient at the left hand edge of the element being filled, and specifying x1="0.2" starts the gradient at 20% of the width of that element. As the gradient is positioned relative to the element being filled, two element using the same gradient will appear the same regardless of the position of the element.

This SVG image shows rectangles using the same gradient in conjunction with gradientUnits="userSpaceOnUse" producing the image below.