Features:
- circle
- line
- color
- opacity
- animation
Code:
1 #include <stdio.h> 2 #include <string.h> 3 #include <libxml/encoding.h> 4 #include <libxml/xmlwriter.h> 5 #include <libxml/xmlIO.h> 6 7 #include "svg.h" 8 9 xmlOutputWriteCallback iowrite(void *context, const char *buf, unsigned int 10 len) 11 { 12 FILE *fp = (FILE*)context; 13 fprintf(fp, "%.*s\n", len, buf); 14 15 return len; 16 } 17 18 xmlOutputCloseCallback ioclose(void *context) 19 { 20 FILE *fp = (FILE*)context; 21 fclose(fp); 22 23 return 0; 24 } 25 26 struct svg_ctx* svg_surface(char *filename, int width, int height) 27 { 28 char buf[20]; 29 FILE *fp; 30 struct svg_ctx* ret; 31 xmlOutputBufferPtr xobp; 32 xmlTextWriterPtr xtwp; 33 34 fp = fopen(filename, "w"); 35 if (fp == NULL) 36 { 37 fprintf(stderr, "could not open %s for writing\n", filename); 38 exit(-1); 39 } 40 41 xobp = xmlOutputBufferCreateIO((xmlOutputWriteCallback)iowrite, ( 42 xmlOutputCloseCallback)ioclose, fp, NULL); 43 xtwp = xmlNewTextWriter(xobp); 44 xmlTextWriterSetIndent(xtwp, 1); 45 46 xmlTextWriterStartDocument(xtwp, "1.0", "UTF-8", NULL); 47 xmlTextWriterStartDTD(xtwp, (xmlChar*)"svg" , (xmlChar*)"-//W3C//DTD SVG 48 1.1//EN", (xmlChar*)"http://www.w3. 49 org/Graphics/SVG/1.1/DTD/svg11.dtd"); 50 xmlTextWriterEndDTD(xtwp); 51 52 53 xmlTextWriterStartElement(xtwp, (xmlChar*)"svg"); 54 xmlTextWriterWriteAttribute(xtwp, (xmlChar*)"xmlns", (xmlChar*)"http: 55 //www.w3.org/2000/svg"); 56 xmlTextWriterWriteAttribute(xtwp, (xmlChar*)"version", (xmlChar*)"1.1"); 57 xmlTextWriterWriteAttribute(xtwp, (xmlChar*)"baseProfile", (xmlChar*) 58 "full"); 59 snprintf(buf, sizeof(buf)-1, "%dpx", width); 60 xmlTextWriterWriteAttribute(xtwp, (xmlChar*)"width", (xmlChar*)buf); 61 snprintf(buf, sizeof(buf)-1, "%dpx", height); 62 xmlTextWriterWriteAttribute(xtwp, (xmlChar*)"height", (xmlChar*)buf); 63 64 ret = malloc(sizeof(struct svg_ctx)); 65 ret->xtwp = xtwp; 66 ret->fp = fp; 67 68 return ret; 69 } 70 71 void svg_appearance_attributes(struct svg_ctx *sc, struct svg_appearance 72 *sa) 73 { 74 char buf[20]; 75 76 snprintf(buf, sizeof(buf)-1, "#%02x%02x%02x", sa->fill_color[0], sa-> 77 fill_color[1], sa->fill_color[2]); 78 xmlTextWriterWriteAttribute(sc->xtwp, (xmlChar*)"fill", (xmlChar*)buf); 79 snprintf(buf, sizeof(buf)-1, "#%02x%02x%02x", sa->stroke_color[0], sa-> 80 stroke_color[1], sa->stroke_color[2]); 81 xmlTextWriterWriteAttribute(sc->xtwp, (xmlChar*)"stroke", (xmlChar*)buf); 82 snprintf(buf, sizeof(buf)-1, "%f", sa->opacity); 83 xmlTextWriterWriteAttribute(sc->xtwp, (xmlChar*)"fill-opacity", (xmlChar*) 84 buf); 85 xmlTextWriterWriteAttribute(sc->xtwp, (xmlChar*)"stroke-opacity", ( 86 xmlChar*)buf); 87 snprintf(buf, sizeof(buf)-1, "%d", sa->stroke_width); 88 xmlTextWriterWriteAttribute(sc->xtwp, (xmlChar*)"stroke-width", (xmlChar*) 89 buf); 90 } 91 92 void svg_animate(struct svg_ctx *sc, char *attribute, float begin, float 93 duration, char *from, char *to) 94 { 95 char buf[20]; 96 97 xmlTextWriterStartElement(sc->xtwp, (xmlChar*)"animate"); 98 xmlTextWriterWriteAttribute(sc->xtwp, (xmlChar*)"attributeName", ( 99 xmlChar*)attribute); 100 xmlTextWriterWriteAttribute(sc->xtwp, (xmlChar*)"fill", (xmlChar*) 101 "freeze"); 102 xmlTextWriterWriteAttribute(sc->xtwp, (xmlChar*)"attributeType", ( 103 xmlChar*)"XML"); 104 snprintf(buf, sizeof(buf)-1, "%f", begin); 105 xmlTextWriterWriteAttribute(sc->xtwp, (xmlChar*)"begin", (xmlChar*)buf); 106 snprintf(buf, sizeof(buf)-1, "%f", duration); 107 xmlTextWriterWriteAttribute(sc->xtwp, (xmlChar*)"dur", (xmlChar*)buf); 108 xmlTextWriterWriteAttribute(sc->xtwp, (xmlChar*)"from", (xmlChar*)from); 109 xmlTextWriterWriteAttribute(sc->xtwp, (xmlChar*)"to", (xmlChar*)to); 110 111 112 xmlTextWriterEndElement(sc->xtwp); 113 } 114 115 void svg_animate_float(struct svg_ctx *sc, char *attribute, float begin, 116 float duration, float from, float to) 117 { 118 char from_c[20], to_c[20]; 119 120 snprintf(from_c, sizeof(from_c)-1, "%f", from); 121 snprintf(to_c, sizeof(to_c)-1, "%f", to); 122 123 svg_animate(sc, attribute, begin, duration, from_c, to_c); 124 } 125 126 void svg_pos_animate(struct svg_ctx *sc, struct svg_pos *sp, struct svg_pos 127 *spn, char *svg_x, char *svg_y, float begin, float 128 duration) 129 { 130 if (sp->x != spn->x) 131 svg_animate_float(sc, svg_x, begin, duration, sp->x, spn->x); 132 if (sp->y != spn->y) 133 svg_animate_float(sc, svg_y, begin, duration, sp->y, spn->y); 134 } 135 136 void svg_appearance_animate(struct svg_ctx *sc, struct svg_appearance *sa, 137 struct svg_appearance *san, float begin, float 138 duration) 139 { 140 char from_c[20], to_c[20]; 141 142 if (sa->opacity != san->opacity) 143 { 144 svg_animate_float(sc, "fill-opacity", begin, duration, sa->opacity, 145 san->opacity); 146 svg_animate_float(sc, "stroke-opacity", begin, duration, sa->opacity, 147 san->opacity); 148 } 149 150 if (sa->fill_color[0] != san->fill_color[0] || 151 sa->fill_color[1] != san->fill_color[1] || 152 sa->fill_color[2] != san->fill_color[2]) 153 { 154 snprintf(from_c, sizeof(from_c)-1, "#%02x%02x%02x", sa->fill_color[0], 155 sa->fill_color[1], sa->fill_color[2]); 156 snprintf(to_c, sizeof(to_c)-1, "#%02x%02x%02x", san->fill_color[0], 157 san->fill_color[1], san->fill_color[2]); 158 159 svg_animate(sc, "fill", begin, duration, from_c, to_c); 160 } 161 162 if (sa->stroke_color[0] != san->stroke_color[0] || 163 sa->stroke_color[1] != san->stroke_color[1] || 164 sa->stroke_color[2] != san->stroke_color[2]) 165 { 166 snprintf(from_c, sizeof(from_c)-1, "#%02x%02x%02x", sa->stroke_color[ 167 0], sa->stroke_color[1], sa->stroke_color[2]); 168 snprintf(to_c, sizeof(to_c)-1, "#%02x%02x%02x", san->stroke_color[0], 169 san->stroke_color[1], san->stroke_color[2]); 170 171 svg_animate(sc, "stroke", begin, duration, from_c, to_c); 172 } 173 174 if (sa->stroke_width != san->stroke_width) 175 { 176 snprintf(from_c, sizeof(from_c)-1, "%d", sa->stroke_width); 177 snprintf(to_c, sizeof(to_c)-1, "%d", san->stroke_width); 178 179 svg_animate(sc, "stroke-width", begin, duration, from_c, to_c); 180 } 181 } 182 183 void svg_circle(struct svg_ctx *sc, struct svg_circle *sci) 184 { 185 char buf[20]; 186 struct svg_circle *sci_first = sci; 187 188 xmlTextWriterStartElement(sc->xtwp, (xmlChar*)"circle"); 189 snprintf(buf, sizeof(buf)-1, "%f", sci->pos.x); 190 xmlTextWriterWriteAttribute(sc->xtwp, (xmlChar*)"cx", (xmlChar*)buf); 191 snprintf(buf, sizeof(buf)-1, "%f", sci->pos.y); 192 xmlTextWriterWriteAttribute(sc->xtwp, (xmlChar*)"cy", (xmlChar*)buf); 193 snprintf(buf, sizeof(buf)-1, "%f", sci->r); 194 xmlTextWriterWriteAttribute(sc->xtwp, (xmlChar*)"r", (xmlChar*)buf); 195 196 svg_appearance_attributes(sc, &sci->sa); 197 198 // now animation 199 while (sci->next != NULL && sci->next != sci_first) 200 { 201 svg_pos_animate(sc, &sci->pos, &sci->next->pos, "cx", "cy", sci-> 202 begin, sci->duration); 203 svg_appearance_animate(sc, &sci->sa, &sci->next->sa, sci->begin, sci-> 204 duration); 205 if (sci->next->r != sci->r) 206 svg_animate_float(sc, "r", sci->begin, sci->duration, sci->r, sci-> 207 next->r); 208 209 sci = sci->next; 210 } 211 212 xmlTextWriterEndElement(sc->xtwp); 213 } 214 215 void svg_line(struct svg_ctx *sc, struct svg_line *sl) 216 { 217 char buf[20]; 218 struct svg_line *sl_first; 219 220 xmlTextWriterStartElement(sc->xtwp, (xmlChar*)"line"); 221 snprintf(buf, sizeof(buf)-1, "%f", sl->pos1.x); 222 xmlTextWriterWriteAttribute(sc->xtwp, (xmlChar*)"x1", (xmlChar*)buf); 223 snprintf(buf, sizeof(buf)-1, "%f", sl->pos1.y); 224 xmlTextWriterWriteAttribute(sc->xtwp, (xmlChar*)"y1", (xmlChar*)buf); 225 snprintf(buf, sizeof(buf)-1, "%f", sl->pos2.x); 226 xmlTextWriterWriteAttribute(sc->xtwp, (xmlChar*)"x2", (xmlChar*)buf); 227 snprintf(buf, sizeof(buf)-1, "%f", sl->pos2.y); 228 xmlTextWriterWriteAttribute(sc->xtwp, (xmlChar*)"y2", (xmlChar*)buf); 229 230 svg_appearance_attributes(sc, &sl->sa); 231 232 // now animation 233 while (sl->next != NULL && sl->next != sl_first) 234 { 235 svg_pos_animate(sc, &sl->pos1, &sl->next->pos1, "x1", "y1", sl->begin, 236 sl->duration); 237 svg_pos_animate(sc, &sl->pos2, &sl->next->pos2, "x2", "y2", sl->begin, 238 sl->duration); 239 svg_appearance_animate(sc, &sl->sa, &sl->next->sa, sl->begin, sl-> 240 duration); 241 242 sl = sl->next; 243 } 244 245 xmlTextWriterEndElement(sc->xtwp); 246 } 247 248 void svg_end(struct svg_ctx *sc) 249 { 250 xmlTextWriterEndElement(sc->xtwp); 251 xmlFreeTextWriter(sc->xtwp); 252 253 free(sc); 254 } 255 256 void svg_copy_appearance(struct svg_appearance *src, struct svg_appearance 257 *dest) 258 { 259 dest->opacity = src->opacity; 260 dest->fill_color[0] = src->fill_color[0]; 261 dest->fill_color[1] = src->fill_color[1]; 262 dest->fill_color[2] = src->fill_color[2]; 263 264 dest->stroke_color[0] = src->stroke_color[0]; 265 dest->stroke_color[1] = src->stroke_color[1]; 266 dest->stroke_color[2] = src->stroke_color[2]; 267 268 dest->stroke_width = src->stroke_width; 269 } 270 271 void svg_fill_default_appearance(struct svg_appearance *sa) 272 { 273 sa->fill_color[0] = 0; 274 sa->fill_color[1] = 0xff; 275 sa->fill_color[2] = 0; 276 277 sa->stroke_color[0] = 0; 278 sa->stroke_color[1] = 0; 279 sa->stroke_color[2] = 0xff; 280 281 sa->opacity = 0.5; 282 sa->stroke_width = 1; 283 } 284 285 int main(int argc, char **argv) 286 { 287 struct svg_ctx *sc; 288 struct svg_circle sci, scj; 289 struct svg_line sl, sm; 290 291 sc = svg_surface("test.svg", 400, 300); 292 svg_fill_default_appearance(&sci.sa); 293 294 sci.pos.x = 100; 295 sci.pos.y = 100; 296 sci.r = 50; 297 sci.begin = 5; 298 sci.duration = 10; 299 sci.next = &scj; 300 scj.pos.x = sci.pos.x+90; 301 scj.pos.y = sci.pos.y+30; 302 scj.r = sci.r+10; 303 scj.next = NULL; 304 svg_copy_appearance(&sci.sa, &scj.sa); 305 scj.sa.opacity = 1; 306 scj.sa.fill_color[0] = 0xff; 307 scj.sa.stroke_color[0] = 0xff; 308 svg_circle(sc, &sci); 309 310 svg_copy_appearance(&sci.sa, &sl.sa); 311 sl.pos1.x = 300; 312 sl.pos1.y = 100; 313 sl.pos2.x = 100; 314 sl.pos2.y = 100; 315 316 svg_copy_appearance(&sl.sa, &sm.sa); 317 sm.pos1.x = sl.pos1.x; 318 sm.pos1.y = sl.pos1.y; 319 sm.pos2.x = sl.pos2.x+30; 320 sm.pos2.y = sl.pos2.y; 321 sm.sa.stroke_width = 5; 322 sl.duration = 5; 323 324 sl.sa.opacity = 0.5; 325 sl.sa.stroke_width = 2; 326 sl.next = &sm; 327 svg_line(sc, &sl); 328 329 svg_end(sc); 330 331 return 0; 332 }
Header file (svg.h):
1 #ifndef _SVG_H 2 #define _SVG_H 3 struct svg_ctx 4 { 5 xmlTextWriterPtr xtwp; 6 FILE *fp; 7 }; 8 9 struct svg_pos 10 { 11 float x, y; 12 }; 13 14 struct svg_appearance 15 { 16 float opacity; 17 unsigned char fill_color[3]; 18 unsigned char stroke_color[3]; 19 20 unsigned int stroke_width; 21 }; 22 23 struct svg_circle 24 { 25 struct svg_pos pos; 26 float r; 27 28 struct svg_appearance sa; 29 30 //animation 31 struct svg_circle *next; 32 float begin, duration; 33 }; 34 35 struct svg_line 36 { 37 struct svg_pos pos1; 38 struct svg_pos pos2; 39 40 struct svg_appearance sa; 41 42 //animation 43 float begin, duration; 44 struct svg_line *next; 45 }; 46 #endif
Compile:gcc `xml2-config --cflags --libs` svg.c -o svg -Wall -g
Open with firefox or chromium

