How to Create SVG Files Programmatically in C# .NET
With all the new devices on the market, screen sizes can be a real challenge for websites to manage, especially when it comes to graphics. Far too often, developers repurpose older JPEG or PNG files and try to change their size to match what they think will be an appropriate size. Then they test these on various devices to get a good 'idea' of how these images will appear. However, it is far more scalable and easier for designers to use Scalable Vector Graphics (SVG) in today's API world.
SVG is an XML-based vector image format for two-dimensional graphics. Though it has been around for nearly two decades, the ubiquitous presence of responsive designs and mobile devices has increased its demand in the last few years. Why has this demand increased? Because SVG is a vector image model capable of infinite scaling in size without loss of image quality on any resolution device and the graphical elements of SVG can be programmatically manipulated.
Why work with SVG programmatically?
You might wonder why one needs to create or alter SVG images programmatically when there are several available tools.
One of the obvious reasons (for developers, though) is the love for coding. Other reasons include,
- Cost offers advanced editing capabilities with premium packages as most of the tools.
- Additional installations of third-party (standalone) applications on server or client machines.
- SVGs are complex vector images; manually editing them is a tedious job.
- An extensive archive of images must be converted from another format to SVG.
To get a better understanding of these ideas, let's look at a simple use case as follows:
Use-case: Modern Website Image Utilization in Responsive Design
Suppose your company is shifting from legacy websites to a modern and responsive website compatible for display on any screen. The old website used JPEG or PNG images for icons and logos. The website developer is looking for SVG as an alternative so that the same image can be easily scaled for multiple devices. Creating an SVG image from scratch would be a time-consuming job. So, they want a tool that can be integrated within their application and convert all those images according to the device dimensions programmatically, without involving much manual effort.
Document Solutions (previously GrapeCity Documents) v5.1 provides a wide range of APIs with Document Solutions for PDF (DsPdf, formerly GcPdf) and Document Solutions for Imaging (DsImaging, formerly GcImaging) libraries to easily process and render SVG documents. The API helps make life easier for .NET developers to work with SVG documents programmatically and be able to create, modify, edit, render, and convert them.
Although Document Solutions APIs cover many functions for converting and manipulating images, we will break up these options into bite-sized pieces using a series of blogs. This blog is the first in the series and covers explicitly creating an SVG image from scratch.
Let’s get started by understanding the drawing basics of SVG images.
SVG Drawing Basics
An SVG image is stored as a list of instructions that provide a sequence of primitive geometric shapes, lines, and transformations drawn on a 2D canvas. The shapes are basic geometric shapes such as rectangles, circles, ellipses, lines, polylines, polygons, and glyph elements such as text or complex shapes created using the path element or a sequence of lines and arcs.
This is most easily visualized by thinking about an SVG image as a coordinate (two-dimensional) x-y plane with the origin at 0,0 at the top-left corner. The positive x-axis goes infinitely to the right, and the positive y-axis goes infinitely to the bottom, as shown below:
This plane runs endlessly. But since the image is to be viewed on a device, the size of the viewing area must be defined. This visible area is called a Viewport and is the window to see the SVG image. It could be the complete image or a portion of the image visible on the screen, as shown below:
Sometimes there is a need to focus on a smaller portion of the entire image, something like zooming. A ViewBox that crops a specific canvas area and covers it up onto the whole viewport is required for such scenarios. Thus, allowing a portion of the original image to scale and move along the coordinate axes as shown below:
The image is scaled down or zoomed out when the view box width and height are less than the viewport's dimension. However, if they are greater than the viewport's dimension, the image is scaled up or zoomed in.
SVG image is a collection of shapes with defined coordinates. To draw it, you need to give separate instructions for every element the same way you supply for drawing shapes on a cartesian plane using coordinates.
For example, to draw an image of an elliptical disc (or eye), you need to create two elements – a circle and an ellipse, providing the centers as the coordinate point and the radii to create an arc on the horizontal and vertical axis as shown in the image below:
Let's dive into the GcDocs Libraries (GcImaging) for C# .NET and create an SVG image programmatically.
Creating SVG From Scratch
Understanding the APIs
When DsImaging or DsPdf library is added to a project, SVG creation and manipulation APIs are found within a separate namespace - GrapeCity.Documents.Svg. It wraps all the objects to play with the DOM of an SVG image. The API is fully compatible with the SVG official specifications and works with SVG files without the need to get into the underlying details of the SVG file format.
The primary APIs corresponding to the drawing requirements of an SVG image is listed in the table below:
Drawing Requirement |
Available API |
Canvas |
The Root element of the GcSvgDocument class |
Viewport |
The dimensions (width and height) for the root element (RootSvg) |
ViewBox |
SvgViewBox structure |
Shape |
Svg<shape>Element class inherited from SvgGeometryElement Class |
Shape Attributes (center, path, radii, height, width, etc.) |
Properties with the shape element class |
Complex Shape (using path) |
Classes, enumerations, and structures related to Path such as SvgPathBuilder, SvgPathCommand, SvgPathElement, etc. |
Unit System |
Several unit enums such as SvgAngleUnit, SvgLengthUnit, SvgMarkerUnit etc. |
Formatting |
Several drawing classes, enumerations, and structures. |
Creating SVG Image
For this blog post, we will create the GrapeCity logo, as shown below, in SVG format using the DsImaging for C# .NET library:
Let's get started by importing the Imaging and SVG namespaces to the class file in the project:
using GrapeCity.Documents.Imaging;
using GrapeCity.Documents.Svg;
Now, configure the canvas for the SVG image using the GcSvgDocument class and Viewport settings defining the size of the logo as follows:
var svgDoc = new GcSvgDocument();
svgDoc.RootSvg.Width = new SvgLength(250, SvgLengthUnits.Pixels);
svgDoc.RootSvg.Height = new SvgLength(150, SvgLengthUnits.Pixels);
Next, draw the design of the logo on the configured canvas. Unlike raster formats, SVG is not created pixel-by-pixel but rather built using smaller components at a time. The image we are creating consists of circular discs and handles on both sides of this disc. For the circular disc, we will use an overlapping circle element and ellipse element and for the handles, we will create a closed region using the path element as depicted in the code below:
//Outer circle using Ellipse Element
var outerCircle = new SvgEllipseElement()
{
CenterX = new SvgLength(160, SvgLengthUnits.Pixels),
CenterY = new SvgLength(92, SvgLengthUnits.Pixels),
RadiusX = new SvgLength(90, SvgLengthUnits.Pixels),
RadiusY = new SvgLength(80, SvgLengthUnits.Pixels),
Fill = new SvgPaint(Color.FromArgb(81, 59, 116)),
Stroke = new SvgPaint(Color.FromArgb(81, 59, 116))
};
//Inner cirlce using Circle Element
var innerCircle = new SvgCircleElement()
{
CenterX = new SvgLength(160, SvgLengthUnits.Pixels),
CenterY = new SvgLength(92, SvgLengthUnits.Pixels),
Radius = new SvgLength(45, SvgLengthUnits.Pixels),
Fill = new SvgPaint(Color.White),
Stroke = new SvgPaint(Color.FromArgb(81, 59, 116))
};
//Configure Path builder to draw the left and right side logo handles
var pb = new SvgPathBuilder();
pb.AddMoveTo(false, 8, 121);
pb.AddLineTo(false, 297, 25);
pb.AddLineTo(false, 314, 68);
pb.AddLineTo(false, 23, 164);
pb.AddLineTo(false, 8, 121);
pb.AddClosePath();
var handles = new SvgPathElement()
{
PathData = pb.ToPathData(),
Fill = new SvgPaint(Color.FromArgb(81, 59, 116)),
};
Then add these elements to the SVG DOM. You can choose to use the Add or Insert method from SvgElementCollection class. We are using the Insert method as we want to control the indexes for the added elements as depicted in the code snippet below:
svgDoc.RootSvg.Children.Insert(0, handles);
svgDoc.RootSvg.Children.Insert(1, outerCircle);
svgDoc.RootSvg.Children.Insert(2, innerCircle);
Lastly, configure the view box to scale the image and fit it in the defined viewport size using the code below:
SvgViewBox view = new SvgViewBox();
view.MinX = 0;
view.MinY = 0;
view.Width = 320;
view.Height = 175;
svgDoc.RootSvg.ViewBox = view;
Finally, save the content to an SVG file as below:
svgDoc.Save("Logo.svg");
To get the best possible understanding of this example, please download the complete sample.
Also, visit the DsPdf demo and DsImaging demos to see many other shapes and images that can be drawn using the GcSvgDocument class in C# .NET.
Alternatively, with v5.1, it is now possible to use all common graphics operations to draw on an instance of the new GcSvgGraphics class, which can then be converted to GcSvgDocument and saved as an SVG or an SVGZ image. In addition, saving individual pages of GcPdfDocument or GcWordLayout in SVG and SVGZ formats is also supported. Have a look at What's New in GrapeCity Documents v5.1 as well as GcSvgGraphics demos.