#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"); }