Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
This articles describes how to open SVG files in C++ application, work with Bezier curves and export to PDF.
Introduction
This code was written to demonstrate the process of parsing vector SVG files in C/C++ application, working with Bezier
curves, and saving the vector image to PDF. For ease of understanding, all processing in app only works in grayscale
mode. The code was written for Windows, but has no Windows-only dependencies and can be easily ported to Linux or
any embedded platform.
Scalable Vector Graphics (SVG) is a 2D vector image format widely used in Web development. The SVG format is
heavily based on XML standard. While the raster image (PNG, JPG, GIF, etc.) is composed of a fixed set of pixels, the
vector SVG image is composed of a fixed set of shapes, like circles, lines, rectangles, Bezier curves, etc. The advantage
of SVG format is that it can be easily scaled to any level without the loss of quality.
1 of 7 01/08/2018 11:34
Parse SVG Files to Bezier Curves in C++ and Sa... https://www.codeproject.com/Articles/1252897/...
Bézier curve is a parametric curve which is used to model smooth curves that can be scaled indefinitely. Bezier curve
can be represented as a set of control points. Quadratic and cubic Bezier curves are most common. Higher degree
curves are more computationally expensive to evaluate. When more complex shapes are needed, low order Bezier
curves are patched together, producing a composite Bezier curve. A composite Bezier curve is commonly referred to as
a path.
The Portable Document Format (PDF) is a file format to represent documents, including text formatting, raster images,
vector graphics, etc. Vector graphics in PDF are constructed with paths too. Paths are usually composed of lines and
cubic Bezier curves, but can also be constructed from the outlines of text. Paths in PDF can be stroked, filled, clipping.
Strokes and fills can use any color set in the graphics state, including patterns.
Background
For the processing of SVG files, I used brilliant library called nanosvg. It is small and lightweight and can be used even in
embedded development projects. To compose PDF files, I have used write-only libHaru library. Though not actively
developed now (2018), it still can be used in C/C++ projects.
//..
2 of 7 01/08/2018 11:34
Parse SVG Files to Bezier Curves in C++ and Sa... https://www.codeproject.com/Articles/1252897/...
SvgConverter converter;
converter.loadFromFile(fileInput); // load svg image to inner buffer
converter.convertToPDF(fileOutput); // parse and write image from buffer to pdf file
//..
class SvgConverter {
private:
NSVGimage * g_image;
std::string fileName;
public:
SvgConverter(std::string fileName);
SvgConverter();
bool isLoaded();
bool loadFromFile(std::string fileName);
bool convertToPDF(std::string fileName);
~SvgConverter();
private:
float distPtSeg(float x, float y, float px, float py, float qx, float qy);
void pdfcubicBez(HPDF_Page page, float x1, float y1, float x2, float y2,
float x3, float y3, float x4, float y4,
float tol, int level, Vector2f startPoint);
void pdfPath(HPDF_Page page, float* pts, int npts, char closed, float tol, bool
bFilled,
Vector2f startPoint);
static void error_handler(HPDF_STATUS error_no,
HPDF_STATUS detail_no,
void *user_data);
};
To approximate Bezier curve and draw it, we will use one of the properties of such curves.
Any cubic Bezier curve B from beginning to end can be divided into two curves, which together will describe the same
curve as B.
Converting and approximation method implementation, some code taken from nanosvg sample and adapted to PDF
coordinate system:
HPDF_Page_SetWidth(page, width);
HPDF_Page_SetHeight(page, height);
HPDF_Page_SetLineWidth(page, 0.1f); //initializing page
3 of 7 01/08/2018 11:34
Parse SVG Files to Bezier Curves in C++ and Sa... https://www.codeproject.com/Articles/1252897/...
return true;
}
float SvgConverter::distPtSeg(float x, float y, float px, float py, float qx, float
qy)
{
float pqx, pqy, dx, dy, d, t;
pqx = qx - px;
pqy = qy - py;
dx = x - px;
dy = y - py;
d = pqx*pqx + pqy*pqy;
t = pqx*dx + pqy*dy;
if (d > 0) t /= d;
if (t < 0) t = 0;
else if (t > 1) t = 1;
dx = px + t*pqx - x;
dy = py + t*pqy - y;
return dx*dx + dy*dy;
}
void SvgConverter::pdfcubicBez(HPDF_Page page, float x1, float y1, float x2, float y2,
float x3, float y3, float x4, float y4,
float tol, int level, Vector2f startPoint)
{
float x12, y12, x23, y23, x34, y34, x123, y123, x234, y234, x1234, y1234;
float d;
4 of 7 01/08/2018 11:34
Parse SVG Files to Bezier Curves in C++ and Sa... https://www.codeproject.com/Articles/1252897/...
You can use an application from console to include in some batch processing. Application receives two command line
arguments, where the first argument is SVG file path and the second is PDF file path.
For example:
Points of Interest
While trying to link C library to C++ project, first you have to disable precompiled headers for C files. This can be done
by selecting multiple C files first in Solution Explorer, right click, then go to "Precompiled Headers" tab and select "Not
using Precompiled Headers".
5 of 7 01/08/2018 11:34
Parse SVG Files to Bezier Curves in C++ and Sa... https://www.codeproject.com/Articles/1252897/...
Also, you need to wrap the C include files in an extern "C" directive:
extern "C" {
#include "libharu\hpdf.h"
#include "libharu\hpdf_utils.h"
}
Conclusion
Feel free to send me any comments and suggestions. If you find this approach useful, feel free to upvote the article. If
you find yourself wanting to improve the code, feel free to clone the github repository.
Good luck!
History
18th July, 2018 - First version
License
This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)
6 of 7 01/08/2018 11:34
Parse SVG Files to Bezier Curves in C++ and Sa... https://www.codeproject.com/Articles/1252897/...
Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile Article Copyright 2018 by Michael Moroz
Web01-2016 | 2.8.180728.1 | Last Updated 19 Jul 2018 Everything else Copyright © CodeProject, 1999-2018
7 of 7 01/08/2018 11:34