#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "svg.h"
#define USE_ACTUAL 1 // use dimensions inferred from drawing
// rather than fixed 24x24in from Corel
// template...
static void appendstringtosvg (svg * psvg, char *text) {
int l = strlen (psvg->svg) + strlen (text) + 1;
char *p = realloc (psvg->svg, l); // unoptimal way to extend strings...
if (p) psvg->svg = p;
strcat (psvg->svg, text);
}
static void appendnumbertosvg (svg * psvg, int n) {
char sn[16];
sprintf (sn, "%0d", n * 100 / 254); // mm to in
appendstringtosvg (psvg, sn);
}
static void appenddecimalnumbertosvg (svg * psvg, int n) {
char sn[16];
sprintf (sn, "%0.3f", (float) n / 2540.0); // mm to in - maybe a small
// rounding issue...
appendstringtosvg (psvg, sn);
}
svg *svg_create (int width, int height) {
svg *psvg = malloc (sizeof (svg));
if (psvg != NULL) {
*psvg = (svg) {
.svg = NULL,
.width = width,
.height = height,
.finalized = false
};
psvg->svg = malloc (1);
psvg->svg[0] = '\0';
appendstringtosvg (psvg,
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
appendstringtosvg (psvg,
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");
appendstringtosvg (psvg, "<!-- Creator: CorelDRAW X7 -->\n");
appendstringtosvg (psvg,
"<svg xmlns=\"http://www.w3.org/2000/svg\" xml:space=\"preserve\" width=\"");
#ifdef USE_ACTUAL
appenddecimalnumbertosvg (psvg, width);
#else
appendstringtosvg (psvg, "24");
#endif
appendstringtosvg (psvg, "in\" height=\"");
#ifdef USE_ACTUAL
appenddecimalnumbertosvg (psvg, height);
#else
appendstringtosvg (psvg, "24");
#endif
appendstringtosvg (psvg,
"in\" version=\"1.1\" style=\"shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd\"");
appendstringtosvg (psvg, " viewBox=\"0 0 ");
#ifdef USE_ACTUAL
appendnumbertosvg (psvg, width);
appendstringtosvg (psvg, " ");
appendnumbertosvg (psvg, height);
#else
appendstringtosvg (psvg, "24000 24000");
#endif
appendstringtosvg (psvg, "\"");
appendstringtosvg (psvg,
" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n");
appendstringtosvg (psvg, " <defs>\n");
appendstringtosvg (psvg, " <style type=\"text/css\">\n");
appendstringtosvg (psvg, " <![CDATA[\n");
appendstringtosvg (psvg, " .str0 {stroke:red}\n");
appendstringtosvg (psvg, " .str1 {stroke:black}\n");
appendstringtosvg (psvg, " .fil0 {fill:none}\n");
appendstringtosvg (psvg, " ]]>\n");
appendstringtosvg (psvg, " </style>\n");
appendstringtosvg (psvg, " </defs>\n");
appendstringtosvg (psvg, " <g id=\"Layer_x0020_1\">\n");
appendstringtosvg (psvg,
" <metadata id=\"CorelCorpID_0Corel-Layer\"/>\n");
return psvg;
} else {
return NULL;
}
}
void svg_finalize (svg * psvg) {
appendstringtosvg (psvg, " </g>\n");
appendstringtosvg (psvg, "</svg>\n");
psvg->finalized = true;
}
void svg_print (svg * psvg) {
printf ("%s\n", psvg->svg);
}
void svg_save (svg * psvg, char *filepath) {
FILE *fp;
if (!psvg->finalized) svg_finalize (psvg);
fp = fopen (filepath, "w");
if (fp != NULL) {
fwrite (psvg->svg, 1, strlen (psvg->svg), fp);
fclose (fp);
}
}
void svg_free (svg * psvg) {
free (psvg->svg);
free (psvg);
}
void svg_circle (svg * psvg, char *stroke, int strokewidth, char *fill, int r,
int cx, int cy)
{
appendstringtosvg (psvg, " <circle stroke=\"");
appendstringtosvg (psvg, stroke);
appendstringtosvg (psvg, "\" stroke-width=\"");
appendnumbertosvg (psvg, strokewidth);
appendstringtosvg (psvg, "\" fill=\"");
appendstringtosvg (psvg, fill);
appendstringtosvg (psvg, "\" r=\"");
appendnumbertosvg (psvg, r);
appendstringtosvg (psvg, "\" cy=\"");
appendnumbertosvg (psvg, cy);
appendstringtosvg (psvg, "\" cx=\"");
appendnumbertosvg (psvg, cx);
appendstringtosvg (psvg, "\" />\n");
}
void svg_line (svg * psvg, char *stroke, int strokewidth, int x1, int y1,
int x2, int y2) {
if ((strokewidth <= 1) && (strcmp (stroke, "#FF0000") == 0)) {
appendstringtosvg (psvg, " <line class=\"fil0 str0\" ");
} else {
appendstringtosvg (psvg, " <line stroke=\"");
appendstringtosvg (psvg, stroke);
appendstringtosvg (psvg, "\" stroke-width=\"");
appendnumbertosvg (psvg, strokewidth);
appendstringtosvg (psvg, "\" ");
}
appendstringtosvg (psvg, " x1=\"");
appendnumbertosvg (psvg, x1);
appendstringtosvg (psvg, "\" y1=\"");
appendnumbertosvg (psvg, y1);
appendstringtosvg (psvg, "\" x2=\"");
appendnumbertosvg (psvg, x2);
appendstringtosvg (psvg, "\" y2=\"");
appendnumbertosvg (psvg, y2);
appendstringtosvg (psvg, "\" />\n");
}
void svg_rectangle (svg * psvg, int width, int height, int x, int y,
char *fill, char *stroke, int strokewidth, int radiusx,
int radiusy) {
appendstringtosvg (psvg, " <rect");
if ( (strcmp (fill, "#FFFFFF") == 0)
&& (strokewidth <= 1)
&& (strcmp (stroke, "#FF0000") == 0)) {
appendstringtosvg (psvg, " class=\"fil0 str0\"");
} else {
appendstringtosvg (psvg, " fill=\"");
appendstringtosvg (psvg, fill);
appendstringtosvg (psvg, "\"");
// appendstringtosvg(psvg, " fill-opacity=\"0.0\"");
appendstringtosvg (psvg, " stroke=\"");
appendstringtosvg (psvg, stroke);
appendstringtosvg (psvg, "\" stroke-width=\"");
appendnumbertosvg (psvg, strokewidth);
appendstringtosvg (psvg, "\"");
}
appendstringtosvg (psvg, " x=\"");
appendnumbertosvg (psvg, x);
appendstringtosvg (psvg, "\" y=\"");
appendnumbertosvg (psvg, y);
appendstringtosvg (psvg, "\" width=\"");
appendnumbertosvg (psvg, width);
appendstringtosvg (psvg, "\" height=\"");
appendnumbertosvg (psvg, height);
if ((radiusx != 0) && (radiusy != 0)) {
appendstringtosvg (psvg, "\" rx=\"");
appendnumbertosvg (psvg, radiusx);
appendstringtosvg (psvg, "\" ry=\"");
appendnumbertosvg (psvg, radiusy);
}
appendstringtosvg (psvg, "\" />\n");
}
void svg_fill (svg * psvg, char *Fill) {
svg_rectangle (psvg, psvg->width, psvg->height, 0, 0, Fill, Fill, 0, 0, 0);
}
void svg_text (svg * psvg, int x, int y, char *fontfamily, int fontsize,
char *fill, char *stroke, char *text, char *transform) {
appendstringtosvg (psvg, " <text x=\"");
appendnumbertosvg (psvg, x);
appendstringtosvg (psvg, "\" y = \"");
appendnumbertosvg (psvg, y);
appendstringtosvg (psvg, "\" font-family=\"");
appendstringtosvg (psvg, fontfamily);
appendstringtosvg (psvg, "\" stroke=\"");
appendstringtosvg (psvg, stroke);
appendstringtosvg (psvg, "\" fill=\"");
appendstringtosvg (psvg, fill);
appendstringtosvg (psvg, "\" font-size=\"");
appendnumbertosvg (psvg, fontsize);
appendstringtosvg (psvg, "\"");
appendstringtosvg (psvg, transform);
appendstringtosvg (psvg, ">");
appendstringtosvg (psvg, text);
appendstringtosvg (psvg, "</text>\n");
}
void svg_ellipse (svg * psvg, int cx, int cy, int rx, int ry, char *fill,
char *stroke, int strokewidth) {
appendstringtosvg (psvg, " <ellipse cx=\"");
appendnumbertosvg (psvg, cx);
appendstringtosvg (psvg, "\" cy=\"");
appendnumbertosvg (psvg, cy);
appendstringtosvg (psvg, "\" rx=\"");
appendnumbertosvg (psvg, rx);
appendstringtosvg (psvg, "\" ry=\"");
appendnumbertosvg (psvg, ry);
appendstringtosvg (psvg, "\" fill=\"");
appendstringtosvg (psvg, fill);
appendstringtosvg (psvg, "\" stroke=\"");
appendstringtosvg (psvg, stroke);
appendstringtosvg (psvg, "\" stroke-width=\"");
appendnumbertosvg (psvg, strokewidth);
appendstringtosvg (psvg, "\" />\n");
}