Changed the structure of returned SVG data to image, shapes and paths
- Needed support to SVG image size, hence added following: - added NSVGImage, which holds image size and list of shapes - added NSVGShape which holds color/store and list of paths
This commit is contained in:
parent
d79b9db71f
commit
572bbb2d4d
19
README.md
19
README.md
@ -14,19 +14,20 @@ NanoSVG supports a wide range of SVG features, if somehing is missing, feel free
|
|||||||
|
|
||||||
``` C
|
``` C
|
||||||
// Load
|
// Load
|
||||||
struct SNVGPath* plist;
|
struct SNVGImage* image;
|
||||||
plist = nsvgParseFromFile("test.svg.");
|
image = nsvgParseFromFile("test.svg.");
|
||||||
|
printf("size: %f x %f\n", image->width, image->height);
|
||||||
// Use
|
// Use...
|
||||||
for (NSVGPath* it = plist; it; it = it->next) {
|
for (shape = image->shapes; shape != NULL; shape = shape->next) {
|
||||||
for (i = 0; i < npts-1; i += 3) {
|
for (path = shape->paths; path != NULL; path = path->next) {
|
||||||
float* p = &pts[i*2];
|
for (i = 0; i < path->npts-1; i += 3) {
|
||||||
|
float* p = &path->pts[i*2];
|
||||||
drawCubicBez(p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7]);
|
drawCubicBez(p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Delete
|
// Delete
|
||||||
nsvgDelete(plist);
|
nsvgDelete(image);
|
||||||
```
|
```
|
||||||
|
|
||||||
## Using NanoSVG in your project
|
## Using NanoSVG in your project
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
#define NANOSVG_IMPLEMENTATION
|
#define NANOSVG_IMPLEMENTATION
|
||||||
#include "nanosvg.h"
|
#include "nanosvg.h"
|
||||||
|
|
||||||
struct NSVGPath* g_plist = NULL;
|
struct NSVGImage* g_image = NULL;
|
||||||
|
|
||||||
static unsigned char bgColor[4] = {205,202,200,255};
|
static unsigned char bgColor[4] = {205,202,200,255};
|
||||||
static unsigned char lineColor[4] = {0,160,192,255};
|
static unsigned char lineColor[4] = {0,160,192,255};
|
||||||
@ -80,17 +80,19 @@ static void cubicBez(float x1, float y1, float x2, float y2,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void calcBounds(struct NSVGPath* plist, float* bounds)
|
static void calcBounds(struct NSVGImage* image, float* bounds)
|
||||||
{
|
{
|
||||||
struct NSVGPath* it;
|
struct NSVGShape* shape;
|
||||||
|
struct NSVGPath* path;
|
||||||
int i;
|
int i;
|
||||||
bounds[0] = FLT_MAX;
|
bounds[0] = FLT_MAX;
|
||||||
bounds[1] = FLT_MAX;
|
bounds[1] = FLT_MAX;
|
||||||
bounds[2] = -FLT_MAX;
|
bounds[2] = -FLT_MAX;
|
||||||
bounds[3] = -FLT_MAX;
|
bounds[3] = -FLT_MAX;
|
||||||
for (it = plist; it; it = it->next) {
|
for (shape = image->shapes; shape != NULL; shape = shape->next) {
|
||||||
for (i = 0; i < it->npts; i++) {
|
for (path = shape->paths; path != NULL; path = path->next) {
|
||||||
float* p = &it->pts[i*2];
|
for (i = 0; i < path->npts; i++) {
|
||||||
|
float* p = &path->pts[i*2];
|
||||||
bounds[0] = minf(bounds[0], p[0]);
|
bounds[0] = minf(bounds[0], p[0]);
|
||||||
bounds[1] = minf(bounds[1], p[1]);
|
bounds[1] = minf(bounds[1], p[1]);
|
||||||
bounds[2] = maxf(bounds[2], p[0]);
|
bounds[2] = maxf(bounds[2], p[0]);
|
||||||
@ -98,6 +100,7 @@ static void calcBounds(struct NSVGPath* plist, float* bounds)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void drawPath(float* pts, int npts, char closed, float tol)
|
void drawPath(float* pts, int npts, char closed, float tol)
|
||||||
{
|
{
|
||||||
@ -164,7 +167,8 @@ void drawframe(GLFWwindow* window)
|
|||||||
{
|
{
|
||||||
int width = 0, height = 0;
|
int width = 0, height = 0;
|
||||||
float bounds[4], view[4], cx, cy, w, h, aspect, px;
|
float bounds[4], view[4], cx, cy, w, h, aspect, px;
|
||||||
struct NSVGPath* it;
|
struct NSVGShape* shape;
|
||||||
|
struct NSVGPath* path;
|
||||||
|
|
||||||
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
|
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
|
||||||
glfwGetFramebufferSize(window, &width, &height);
|
glfwGetFramebufferSize(window, &width, &height);
|
||||||
@ -179,7 +183,7 @@ void drawframe(GLFWwindow* window)
|
|||||||
glLoadIdentity();
|
glLoadIdentity();
|
||||||
|
|
||||||
// Fit view to bounds
|
// Fit view to bounds
|
||||||
calcBounds(g_plist, bounds);
|
calcBounds(g_image, bounds);
|
||||||
cx = (bounds[0]+bounds[2])/2;
|
cx = (bounds[0]+bounds[2])/2;
|
||||||
cy = (bounds[3]+bounds[1])/2;
|
cy = (bounds[3]+bounds[1])/2;
|
||||||
w = (bounds[2]-bounds[0])/2;
|
w = (bounds[2]-bounds[0])/2;
|
||||||
@ -210,9 +214,11 @@ void drawframe(GLFWwindow* window)
|
|||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
|
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
for (it = g_plist; it; it = it->next) {
|
for (shape = g_image->shapes; shape != NULL; shape = shape->next) {
|
||||||
drawPath(it->pts, it->npts, it->closed, px * 1.5f);
|
for (path = shape->paths; path != NULL; path = path->next) {
|
||||||
drawControlPts(it->pts, it->npts, it->closed);
|
drawPath(path->pts, path->npts, path->closed, px * 1.5f);
|
||||||
|
drawControlPts(path->pts, path->npts, path->closed);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
glfwSwapBuffers(window);
|
glfwSwapBuffers(window);
|
||||||
@ -247,9 +253,9 @@ int main()
|
|||||||
glEnable(GL_LINE_SMOOTH);
|
glEnable(GL_LINE_SMOOTH);
|
||||||
|
|
||||||
|
|
||||||
g_plist = nsvgParseFromFile("../example/nano.svg");
|
g_image = nsvgParseFromFile("../example/nano.svg");
|
||||||
if (g_plist == NULL) {
|
if (g_image == NULL) {
|
||||||
printf("Could not open test.svg\n");
|
printf("Could not open SVG image.\n");
|
||||||
glfwTerminate();
|
glfwTerminate();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -260,7 +266,7 @@ int main()
|
|||||||
glfwPollEvents();
|
glfwPollEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
nsvgDelete(g_plist);
|
nsvgDelete(g_image);
|
||||||
|
|
||||||
glfwTerminate();
|
glfwTerminate();
|
||||||
return 0;
|
return 0;
|
||||||
|
227
src/nanosvg.h
227
src/nanosvg.h
@ -33,41 +33,58 @@ extern "C" {
|
|||||||
|
|
||||||
/* Example Usage:
|
/* Example Usage:
|
||||||
// Load
|
// Load
|
||||||
struct SNVGPath* plist;
|
struct SNVGImage* image;
|
||||||
plist = nsvgParseFromFile("test.svg.");
|
image = nsvgParseFromFile("test.svg.");
|
||||||
|
printf("size: %f x %f\n", image->width, image->height);
|
||||||
// Use...
|
// Use...
|
||||||
for (NSVGPath* it = plist; it; it = it->next) {
|
for (shape = image->shapes; shape != NULL; shape = shape->next) {
|
||||||
for (i = 0; i < npts-1; i += 3) {
|
for (path = shape->paths; path != NULL; path = path->next) {
|
||||||
float* p = &pts[i*2];
|
for (i = 0; i < path->npts-1; i += 3) {
|
||||||
|
float* p = &path->pts[i*2];
|
||||||
drawCubicBez(p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7]);
|
drawCubicBez(p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Delete
|
// Delete
|
||||||
nsvgDelete(plist);
|
nsvgDelete(image);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct NSVGPath
|
struct NSVGPath
|
||||||
{
|
{
|
||||||
float* pts; // Cubic bezier points: x0,y0, [cpx1,cpx1,cpx2,cpy2,x1,y1], ...
|
float* pts; // Cubic bezier points: x0,y0, [cpx1,cpx1,cpx2,cpy2,x1,y1], ...
|
||||||
int npts; // Total number of bezier points.
|
int npts; // Total number of bezier points.
|
||||||
unsigned int shapeId; // Sequence number if a SVG shape, used to identify paths belonging to same shape.
|
char closed; // Flag indicating if shapes should be treated as closed.
|
||||||
|
struct NSVGPath* next; // Pointer to next path, or NULL if last element.
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NSVGShape
|
||||||
|
{
|
||||||
unsigned int fillColor; // Fill color
|
unsigned int fillColor; // Fill color
|
||||||
unsigned int strokeColor; // Stroke color
|
unsigned int strokeColor; // Stroke color
|
||||||
float strokeWidth; // Stroke width (scaled)
|
float strokeWidth; // Stroke width (scaled)
|
||||||
char hasFill; // Flag indicating if fill exists.
|
char hasFill; // Flag indicating if fill exists.
|
||||||
char hasStroke; // Flag indicating id store exists
|
char hasStroke; // Flag indicating id store exists
|
||||||
char closed; // Flag indicating if shapes should be treated as closed.
|
struct NSVGPath* paths; // Linked list of paths in the image.
|
||||||
struct NSVGPath* next; // Pointer to next path, or NULL if last element.
|
struct NSVGShape* next; // Pointer to next shape, or NULL if last element.
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NSVGImage
|
||||||
|
{
|
||||||
|
float width; // Width of the image, or -1.0f of not set.
|
||||||
|
float height; // Height of the image, or -1.0f of not set.
|
||||||
|
char wunits[8]; // Units of the width attribute
|
||||||
|
char hunits[8]; // Units of the height attribute
|
||||||
|
struct NSVGShape* shapes; // Linked list of shapes in the image.
|
||||||
};
|
};
|
||||||
|
|
||||||
// Parses SVG file from a file, returns linked list of paths.
|
// Parses SVG file from a file, returns linked list of paths.
|
||||||
struct NSVGPath* nsvgParseFromFile(const char* filename);
|
struct NSVGImage* nsvgParseFromFile(const char* filename);
|
||||||
|
|
||||||
// Parses SVG file from a null terminated string, returns linked list of paths.
|
// Parses SVG file from a null terminated string, returns linked list of paths.
|
||||||
struct NSVGPath* nsvgParse(char* input);
|
struct NSVGImage* nsvgParse(char* input);
|
||||||
|
|
||||||
// Deletes list of paths.
|
// Deletes list of paths.
|
||||||
void nsvgDelete(struct NSVGPath* plist);
|
void nsvgDelete(struct NSVGImage* image);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
};
|
};
|
||||||
@ -99,6 +116,8 @@ static int nsvg__isnum(char c)
|
|||||||
return strchr("0123456789+-.eE", c) != 0;
|
return strchr("0123456789+-.eE", c) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline float nsvg__maxf(float a, float b) { return a > b ? a : b; }
|
||||||
|
|
||||||
|
|
||||||
// Simple XML parser
|
// Simple XML parser
|
||||||
|
|
||||||
@ -238,8 +257,8 @@ struct NSVGParser
|
|||||||
float* pts;
|
float* pts;
|
||||||
int npts;
|
int npts;
|
||||||
int cpts;
|
int cpts;
|
||||||
unsigned int shapeId;
|
|
||||||
struct NSVGPath* plist;
|
struct NSVGPath* plist;
|
||||||
|
struct NSVGImage* image;
|
||||||
char pathFlag;
|
char pathFlag;
|
||||||
char defsFlag;
|
char defsFlag;
|
||||||
};
|
};
|
||||||
@ -324,10 +343,15 @@ static struct NSVGParser* nsvg__createParser()
|
|||||||
{
|
{
|
||||||
struct NSVGParser* p;
|
struct NSVGParser* p;
|
||||||
p = (struct NSVGParser*)malloc(sizeof(struct NSVGParser));
|
p = (struct NSVGParser*)malloc(sizeof(struct NSVGParser));
|
||||||
if (!p)
|
if (p == NULL) goto error;
|
||||||
return NULL;
|
|
||||||
memset(p, 0, sizeof(struct NSVGParser));
|
memset(p, 0, sizeof(struct NSVGParser));
|
||||||
|
|
||||||
|
p->image = (struct NSVGImage*)malloc(sizeof(struct NSVGImage));
|
||||||
|
if (p->image == NULL) goto error;
|
||||||
|
memset(p->image, 0, sizeof(struct NSVGImage));
|
||||||
|
p->image->width = -1.0f;
|
||||||
|
p->image->height = -1.0f;
|
||||||
|
|
||||||
// Init style
|
// Init style
|
||||||
nsvg__xformSetIdentity(p->attr[0].xform);
|
nsvg__xformSetIdentity(p->attr[0].xform);
|
||||||
p->attr[0].fillColor = 0;
|
p->attr[0].fillColor = 0;
|
||||||
@ -340,13 +364,18 @@ static struct NSVGParser* nsvg__createParser()
|
|||||||
p->attr[0].visible = 1;
|
p->attr[0].visible = 1;
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (p) {
|
||||||
|
if (p->image) free(p->image);
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nsvg__deleteParser(struct NSVGParser* p)
|
static void nsvg__deletePaths(struct NSVGPath* path)
|
||||||
{
|
{
|
||||||
struct NSVGPath* path;
|
|
||||||
struct NSVGPath* next;
|
struct NSVGPath* next;
|
||||||
path = p->plist;
|
|
||||||
while (path) {
|
while (path) {
|
||||||
next = path->next;
|
next = path->next;
|
||||||
if (path->pts)
|
if (path->pts)
|
||||||
@ -354,10 +383,17 @@ static void nsvg__deleteParser(struct NSVGParser* p)
|
|||||||
free(path);
|
free(path);
|
||||||
path = next;
|
path = next;
|
||||||
}
|
}
|
||||||
if (p->pts)
|
}
|
||||||
|
|
||||||
|
static void nsvg__deleteParser(struct NSVGParser* p)
|
||||||
|
{
|
||||||
|
if (p != NULL) {
|
||||||
|
nsvg__deletePaths(p->plist);
|
||||||
|
nsvgDelete(p->image);
|
||||||
free(p->pts);
|
free(p->pts);
|
||||||
free(p);
|
free(p);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void nsvg__resetPath(struct NSVGParser* p)
|
static void nsvg__resetPath(struct NSVGParser* p)
|
||||||
{
|
{
|
||||||
@ -429,24 +465,56 @@ static void nsvg__popAttr(struct NSVGParser* p)
|
|||||||
p->attrHead--;
|
p->attrHead--;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nsvg__createPath(struct NSVGParser* p, char closed)
|
static void nsvg__addShape(struct NSVGParser* p)
|
||||||
|
{
|
||||||
|
struct NSVGAttrib* attr = nsvg__getAttr(p);
|
||||||
|
float scale = 1.0f;
|
||||||
|
|
||||||
|
if (p->plist == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
struct NSVGShape* shape = (struct NSVGShape*)malloc(sizeof(struct NSVGShape));
|
||||||
|
if (shape == NULL) goto error;
|
||||||
|
memset(shape, 0, sizeof(struct NSVGShape));
|
||||||
|
|
||||||
|
scale = nsvg__maxf(fabsf(attr->xform[0]), fabsf(attr->xform[3]));
|
||||||
|
shape->hasFill = attr->hasFill;
|
||||||
|
shape->hasStroke = attr->hasStroke;
|
||||||
|
shape->strokeWidth = attr->strokeWidth * scale;
|
||||||
|
|
||||||
|
shape->fillColor = attr->fillColor;
|
||||||
|
if (shape->hasFill)
|
||||||
|
shape->fillColor |= (unsigned int)(attr->fillOpacity*255) << 24;
|
||||||
|
|
||||||
|
shape->strokeColor = attr->strokeColor;
|
||||||
|
if (shape->hasStroke)
|
||||||
|
shape->strokeColor |= (unsigned int)(attr->strokeOpacity*255) << 24;
|
||||||
|
|
||||||
|
shape->paths = p->plist;
|
||||||
|
p->plist = NULL;
|
||||||
|
|
||||||
|
shape->next = p->image->shapes;
|
||||||
|
p->image->shapes = shape;
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (shape) free(shape);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nsvg__addPath(struct NSVGParser* p, char closed)
|
||||||
{
|
{
|
||||||
float* t = NULL;
|
float* t = NULL;
|
||||||
struct NSVGAttrib* attr = NULL;
|
struct NSVGAttrib* attr = nsvg__getAttr(p);
|
||||||
struct NSVGPath* path = NULL;
|
struct NSVGPath* path = NULL;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (p == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (p->npts == 0)
|
if (p->npts == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (closed)
|
if (closed)
|
||||||
nsvg__lineTo(p, p->pts[0], p->pts[1]);
|
nsvg__lineTo(p, p->pts[0], p->pts[1]);
|
||||||
|
|
||||||
attr = nsvg__getAttr(p);
|
|
||||||
|
|
||||||
path = (struct NSVGPath*)malloc(sizeof(struct NSVGPath));
|
path = (struct NSVGPath*)malloc(sizeof(struct NSVGPath));
|
||||||
if (path == NULL) goto error;
|
if (path == NULL) goto error;
|
||||||
memset(path, 0, sizeof(struct NSVGPath));
|
memset(path, 0, sizeof(struct NSVGPath));
|
||||||
@ -461,20 +529,6 @@ static void nsvg__createPath(struct NSVGParser* p, char closed)
|
|||||||
for (i = 0; i < p->npts; ++i)
|
for (i = 0; i < p->npts; ++i)
|
||||||
nsvg__xformPoint(&path->pts[i*2], &path->pts[i*2+1], p->pts[i*2], p->pts[i*2+1], t);
|
nsvg__xformPoint(&path->pts[i*2], &path->pts[i*2+1], p->pts[i*2], p->pts[i*2+1], t);
|
||||||
|
|
||||||
path->hasFill = attr->hasFill;
|
|
||||||
path->hasStroke = attr->hasStroke;
|
|
||||||
path->strokeWidth = attr->strokeWidth * fabsf(t[0]);
|
|
||||||
|
|
||||||
path->fillColor = attr->fillColor;
|
|
||||||
if (path->hasFill)
|
|
||||||
path->fillColor |= (unsigned int)(attr->fillOpacity*255) << 24;
|
|
||||||
|
|
||||||
path->strokeColor = attr->strokeColor;
|
|
||||||
if (path->hasStroke)
|
|
||||||
path->strokeColor |= (unsigned int)(attr->strokeOpacity*255) << 24;
|
|
||||||
|
|
||||||
path->shapeId = p->shapeId;
|
|
||||||
|
|
||||||
path->next = p->plist;
|
path->next = p->plist;
|
||||||
p->plist = path;
|
p->plist = path;
|
||||||
|
|
||||||
@ -1382,7 +1436,7 @@ static void nsvg__parsePath(struct NSVGParser* p, const char** attr)
|
|||||||
if (cmd == 'M' || cmd == 'm') {
|
if (cmd == 'M' || cmd == 'm') {
|
||||||
// Commit path.
|
// Commit path.
|
||||||
if (p->npts > 0)
|
if (p->npts > 0)
|
||||||
nsvg__createPath(p, closedFlag);
|
nsvg__addPath(p, closedFlag);
|
||||||
// Start new subpath.
|
// Start new subpath.
|
||||||
nsvg__resetPath(p);
|
nsvg__resetPath(p);
|
||||||
closedFlag = 0;
|
closedFlag = 0;
|
||||||
@ -1392,7 +1446,7 @@ static void nsvg__parsePath(struct NSVGParser* p, const char** attr)
|
|||||||
closedFlag = 1;
|
closedFlag = 1;
|
||||||
// Commit path.
|
// Commit path.
|
||||||
if (p->npts > 0)
|
if (p->npts > 0)
|
||||||
nsvg__createPath(p, closedFlag);
|
nsvg__addPath(p, closedFlag);
|
||||||
// Start new subpath.
|
// Start new subpath.
|
||||||
nsvg__resetPath(p);
|
nsvg__resetPath(p);
|
||||||
closedFlag = 0;
|
closedFlag = 0;
|
||||||
@ -1402,7 +1456,7 @@ static void nsvg__parsePath(struct NSVGParser* p, const char** attr)
|
|||||||
}
|
}
|
||||||
// Commit path.
|
// Commit path.
|
||||||
if (p->npts)
|
if (p->npts)
|
||||||
nsvg__createPath(p, closedFlag);
|
nsvg__addPath(p, closedFlag);
|
||||||
} else {
|
} else {
|
||||||
tmp[0] = attr[i];
|
tmp[0] = attr[i];
|
||||||
tmp[1] = attr[i + 1];
|
tmp[1] = attr[i + 1];
|
||||||
@ -1411,6 +1465,8 @@ static void nsvg__parsePath(struct NSVGParser* p, const char** attr)
|
|||||||
nsvg__parseAttribs(p, tmp);
|
nsvg__parseAttribs(p, tmp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsvg__addShape(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nsvg__parseRect(struct NSVGParser* p, const char** attr)
|
static void nsvg__parseRect(struct NSVGParser* p, const char** attr)
|
||||||
@ -1462,7 +1518,9 @@ static void nsvg__parseRect(struct NSVGParser* p, const char** attr)
|
|||||||
nsvg__cubicBezTo(p, x, y+ry*(1-NSVG_KAPPA90), x+rx*(1-NSVG_KAPPA90), y, x+rx, y);
|
nsvg__cubicBezTo(p, x, y+ry*(1-NSVG_KAPPA90), x+rx*(1-NSVG_KAPPA90), y, x+rx, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsvg__createPath(p, 1);
|
nsvg__addPath(p, 1);
|
||||||
|
|
||||||
|
nsvg__addShape(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1490,7 +1548,9 @@ static void nsvg__parseCircle(struct NSVGParser* p, const char** attr)
|
|||||||
nsvg__cubicBezTo(p, cx-r, cy-r*NSVG_KAPPA90, cx-r*NSVG_KAPPA90, cy-r, cx, cy-r);
|
nsvg__cubicBezTo(p, cx-r, cy-r*NSVG_KAPPA90, cx-r*NSVG_KAPPA90, cy-r, cx, cy-r);
|
||||||
nsvg__cubicBezTo(p, cx+r*NSVG_KAPPA90, cy-r, cx+r, cy-r*NSVG_KAPPA90, cx+r, cy);
|
nsvg__cubicBezTo(p, cx+r*NSVG_KAPPA90, cy-r, cx+r, cy-r*NSVG_KAPPA90, cx+r, cy);
|
||||||
|
|
||||||
nsvg__createPath(p, 1);
|
nsvg__addPath(p, 1);
|
||||||
|
|
||||||
|
nsvg__addShape(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1521,7 +1581,9 @@ static void nsvg__parseEllipse(struct NSVGParser* p, const char** attr)
|
|||||||
nsvg__cubicBezTo(p, cx-rx, cy-ry*NSVG_KAPPA90, cx-rx*NSVG_KAPPA90, cy-ry, cx, cy-ry);
|
nsvg__cubicBezTo(p, cx-rx, cy-ry*NSVG_KAPPA90, cx-rx*NSVG_KAPPA90, cy-ry, cx, cy-ry);
|
||||||
nsvg__cubicBezTo(p, cx+rx*NSVG_KAPPA90, cy-ry, cx+rx, cy-ry*NSVG_KAPPA90, cx+rx, cy);
|
nsvg__cubicBezTo(p, cx+rx*NSVG_KAPPA90, cy-ry, cx+rx, cy-ry*NSVG_KAPPA90, cx+rx, cy);
|
||||||
|
|
||||||
nsvg__createPath(p, 1);
|
nsvg__addPath(p, 1);
|
||||||
|
|
||||||
|
nsvg__addShape(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1547,7 +1609,9 @@ static void nsvg__parseLine(struct NSVGParser* p, const char** attr)
|
|||||||
nsvg__moveTo(p, x1, y1);
|
nsvg__moveTo(p, x1, y1);
|
||||||
nsvg__lineTo(p, x2, y2);
|
nsvg__lineTo(p, x2, y2);
|
||||||
|
|
||||||
nsvg__createPath(p, 0);
|
nsvg__addPath(p, 0);
|
||||||
|
|
||||||
|
nsvg__addShape(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nsvg__parsePoly(struct NSVGParser* p, const char** attr, int closeFlag)
|
static void nsvg__parsePoly(struct NSVGParser* p, const char** attr, int closeFlag)
|
||||||
@ -1581,7 +1645,27 @@ static void nsvg__parsePoly(struct NSVGParser* p, const char** attr, int closeFl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nsvg__createPath(p, closeFlag);
|
nsvg__addPath(p, closeFlag);
|
||||||
|
|
||||||
|
nsvg__addShape(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nsvg__parseSVG(struct NSVGParser* p, const char** attr)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; attr[i]; i += 2) {
|
||||||
|
if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
|
||||||
|
if (strcmp(attr[i], "width") == 0) {
|
||||||
|
p->image->wunits[0] = '\0';
|
||||||
|
sscanf(attr[i + 1], "%f%s", &p->image->width, p->image->wunits);
|
||||||
|
printf("W units='%s'\n", p->image->wunits);
|
||||||
|
} else if (strcmp(attr[i], "height") == 0) {
|
||||||
|
p->image->hunits[0] = '\0';
|
||||||
|
sscanf(attr[i + 1], "%f%s", &p->image->height, p->image->hunits);
|
||||||
|
printf("H units='%s'\n", p->image->hunits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nsvg__startElement(void* ud, const char* el, const char** attr)
|
static void nsvg__startElement(void* ud, const char* el, const char** attr)
|
||||||
@ -1600,40 +1684,35 @@ static void nsvg__startElement(void* ud, const char* el, const char** attr)
|
|||||||
return;
|
return;
|
||||||
nsvg__pushAttr(p);
|
nsvg__pushAttr(p);
|
||||||
nsvg__parsePath(p, attr);
|
nsvg__parsePath(p, attr);
|
||||||
p->pathFlag = 1;
|
|
||||||
nsvg__popAttr(p);
|
nsvg__popAttr(p);
|
||||||
} else if (strcmp(el, "rect") == 0) {
|
} else if (strcmp(el, "rect") == 0) {
|
||||||
nsvg__pushAttr(p);
|
nsvg__pushAttr(p);
|
||||||
nsvg__parseRect(p, attr);
|
nsvg__parseRect(p, attr);
|
||||||
p->shapeId++;
|
|
||||||
nsvg__popAttr(p);
|
nsvg__popAttr(p);
|
||||||
} else if (strcmp(el, "circle") == 0) {
|
} else if (strcmp(el, "circle") == 0) {
|
||||||
nsvg__pushAttr(p);
|
nsvg__pushAttr(p);
|
||||||
nsvg__parseCircle(p, attr);
|
nsvg__parseCircle(p, attr);
|
||||||
p->shapeId++;
|
|
||||||
nsvg__popAttr(p);
|
nsvg__popAttr(p);
|
||||||
} else if (strcmp(el, "ellipse") == 0) {
|
} else if (strcmp(el, "ellipse") == 0) {
|
||||||
nsvg__pushAttr(p);
|
nsvg__pushAttr(p);
|
||||||
nsvg__parseEllipse(p, attr);
|
nsvg__parseEllipse(p, attr);
|
||||||
p->shapeId++;
|
|
||||||
nsvg__popAttr(p);
|
nsvg__popAttr(p);
|
||||||
} else if (strcmp(el, "line") == 0) {
|
} else if (strcmp(el, "line") == 0) {
|
||||||
nsvg__pushAttr(p);
|
nsvg__pushAttr(p);
|
||||||
nsvg__parseLine(p, attr);
|
nsvg__parseLine(p, attr);
|
||||||
p->shapeId++;
|
|
||||||
nsvg__popAttr(p);
|
nsvg__popAttr(p);
|
||||||
} else if (strcmp(el, "polyline") == 0) {
|
} else if (strcmp(el, "polyline") == 0) {
|
||||||
nsvg__pushAttr(p);
|
nsvg__pushAttr(p);
|
||||||
nsvg__parsePoly(p, attr, 0);
|
nsvg__parsePoly(p, attr, 0);
|
||||||
p->shapeId++;
|
|
||||||
nsvg__popAttr(p);
|
nsvg__popAttr(p);
|
||||||
} else if (strcmp(el, "polygon") == 0) {
|
} else if (strcmp(el, "polygon") == 0) {
|
||||||
nsvg__pushAttr(p);
|
nsvg__pushAttr(p);
|
||||||
nsvg__parsePoly(p, attr, 1);
|
nsvg__parsePoly(p, attr, 1);
|
||||||
p->shapeId++;
|
|
||||||
nsvg__popAttr(p);
|
nsvg__popAttr(p);
|
||||||
} else if (strcmp(el, "defs") == 0) {
|
} else if (strcmp(el, "defs") == 0) {
|
||||||
p->defsFlag = 1;
|
p->defsFlag = 1;
|
||||||
|
} else if (strcmp(el, "svg") == 0) {
|
||||||
|
nsvg__parseSVG(p, attr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1655,10 +1734,10 @@ static void nsvg__content(void* ud, const char* s)
|
|||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
struct NSVGPath* nsvgParse(char* input)
|
struct NSVGImage* nsvgParse(char* input)
|
||||||
{
|
{
|
||||||
struct NSVGParser* p;
|
struct NSVGParser* p;
|
||||||
struct NSVGPath* ret = 0;
|
struct NSVGImage* ret = 0;
|
||||||
|
|
||||||
p = nsvg__createParser();
|
p = nsvg__createParser();
|
||||||
if (p == NULL) {
|
if (p == NULL) {
|
||||||
@ -1667,20 +1746,20 @@ struct NSVGPath* nsvgParse(char* input)
|
|||||||
|
|
||||||
nsvg__parseXML(input, nsvg__startElement, nsvg__endElement, nsvg__content, p);
|
nsvg__parseXML(input, nsvg__startElement, nsvg__endElement, nsvg__content, p);
|
||||||
|
|
||||||
ret = p->plist;
|
ret = p->image;
|
||||||
p->plist = NULL;
|
p->image = NULL;
|
||||||
|
|
||||||
nsvg__deleteParser(p);
|
nsvg__deleteParser(p);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct NSVGPath* nsvgParseFromFile(const char* filename)
|
struct NSVGImage* nsvgParseFromFile(const char* filename)
|
||||||
{
|
{
|
||||||
FILE* fp = NULL;
|
FILE* fp = NULL;
|
||||||
int size;
|
int size;
|
||||||
char* data = NULL;
|
char* data = NULL;
|
||||||
struct NSVGPath* plist = NULL;
|
struct NSVGImage* image = NULL;
|
||||||
|
|
||||||
fp = fopen(filename, "rb");
|
fp = fopen(filename, "rb");
|
||||||
if (!fp) goto error;
|
if (!fp) goto error;
|
||||||
@ -1692,30 +1771,28 @@ struct NSVGPath* nsvgParseFromFile(const char* filename)
|
|||||||
fread(data, size, 1, fp);
|
fread(data, size, 1, fp);
|
||||||
data[size] = '\0'; // Must be null terminated.
|
data[size] = '\0'; // Must be null terminated.
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
plist = nsvgParse(data);
|
image = nsvgParse(data);
|
||||||
free(data);
|
free(data);
|
||||||
|
|
||||||
return plist;
|
return image;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
if (fp) fclose(fp);
|
if (fp) fclose(fp);
|
||||||
if (data) free(data);
|
if (data) free(data);
|
||||||
if (plist) nsvgDelete(plist);
|
if (image) nsvgDelete(image);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nsvgDelete(struct NSVGPath* plist)
|
void nsvgDelete(struct NSVGImage* image)
|
||||||
{
|
{
|
||||||
struct NSVGPath* path;
|
if (image) {
|
||||||
struct NSVGPath* next;
|
struct NSVGShape *next, *shape = image->shapes;
|
||||||
if (plist == NULL)
|
while (shape != NULL) {
|
||||||
return;
|
next = shape->next;
|
||||||
path = plist;
|
nsvg__deletePaths(shape->paths);
|
||||||
while (path) {
|
free(shape);
|
||||||
next = path->next;
|
shape = next;
|
||||||
if (path->pts) free(path->pts);
|
}
|
||||||
free(path);
|
|
||||||
path = next;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user