- svg_close_tag_single_line(fp);
- /* support for node->tabwidth missing */
- svg_write_text(fp, node->text);
- svg_end_tag(fp, "text");
- if (node->angle != 0)
- svg_end_tag(fp, "g");
-}
-
-int gfx_render_svg (gfx_canvas_t *canvas,
- art_u32 width, art_u32 height,
- gfx_color_t background, FILE *fp){
- gfx_node_t *node = canvas->firstnode;
- /* Find the first font used, and assume it is the mostly used
- one. It reduces the number of font-familty attributes. */
- while (node) {
- if (node->type == GFX_TEXT && node->filename) {
- svg_default_font = afm_get_font_name(node->filename);
- break;
- }
- node = node->next;
- }
- fputs(
-"<?xml version=\"1.0\" standalone=\"no\"?>\n"
-"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\"\n"
-" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n"
-"<!--\n"
-" SVG file created by\n"
-" RRDtool " PACKAGE_VERSION " Tobias Oetiker, http://tobi.oetiker.ch\n"
-"\n"
-" The width/height attributes in the outhermost svg node\n"
-" are just default sizes for the browser which is used\n"
-" if the svg file is openened directly without being\n"
-" embedded in an html file.\n"
-" The viewBox is the local coord system for rrdtool.\n"
-"-->\n", fp);
- svg_start_tag(fp, "svg");
- fputs(" width=\"", fp);
- svg_write_number(fp, width * canvas->zoom);
- fputs("\" height=\"", fp);
- svg_write_number(fp, height * canvas->zoom);
- fputs("\" x=\"0\" y=\"0\" viewBox=\"", fp);
- svg_write_number(fp, -LINEOFFSET);
- fputs(" ", fp);
- svg_write_number(fp, -LINEOFFSET);
- fputs(" ", fp);
- svg_write_number(fp, width - LINEOFFSET);
- fputs(" ", fp);
- svg_write_number(fp, height - LINEOFFSET);
- fputs("\" preserveAspectRatio=\"xMidYMid\"", fp);
- fprintf(fp, " font-family=\"%s\"", svg_default_font); /* default font */
- fputs(" stroke-linecap=\"round\" stroke-linejoin=\"round\"", fp);
- fputs(" xmlns=\"http://www.w3.org/2000/svg\"", fp);
- fputs(" xmlns:xlink=\"http://www.w3.org/1999/xlink\"", fp);
- svg_close_tag(fp);
- svg_start_tag(fp, "rect");
- fprintf(fp, " x=\"0\" y=\"0\" width=\"%d\" height=\"%d\"", width, height);
- svg_write_color(fp, background, "fill");
- svg_close_tag_empty_node(fp);
- node = canvas->firstnode;
- while (node) {
- switch (node->type) {
- case GFX_LINE:
- svg_multi_path(fp, &node);
- break;
- case GFX_AREA:
- svg_area(fp, node);
- break;
- case GFX_TEXT:
- svg_text(fp, node);
- }
- node = node->next;
- }
- svg_end_tag(fp, "svg");
- return 0;
+ fputs(" points=\"", fp);
+ for (i = 0; i < node->points; i++) {
+ ArtVpath *vec = node->path + i;
+ double x = vec->x - LINEOFFSET;
+ double y = vec->y - LINEOFFSET;
+
+ switch (vec->code) {
+ case ART_MOVETO_OPEN: /* fall-through */
+ case ART_MOVETO:
+ svg_write_number(fp, x);
+ putc(',', fp);
+ svg_write_number(fp, y);
+ startX = x;
+ startY = y;
+ break;
+ case ART_LINETO:
+ if (i == node->points - 2
+ && node->path[i + 1].code == ART_END
+ && fabs(x - startX) < 0.001 && fabs(y - startY) < 0.001) {
+ break; /* poly area always closed, no need for last point */
+ }
+ putc(' ', fp);
+ svg_write_number(fp, x);
+ putc(',', fp);
+ svg_write_number(fp, y);
+ break;
+ case ART_CURVETO:
+ break; /* unsupported */
+ case ART_END:
+ break; /* nop */
+ }
+ }
+ fputs("\"", fp);
+ svg_close_tag_empty_node(fp);
+}
+
+static void svg_text(
+ FILE * fp,
+ gfx_node_t *node)
+{
+ pdf_coords g;
+ const char *fontname;
+
+ /* as svg has 0,0 in top-left corner (like most screens) instead of
+ bottom-left corner like pdf and eps, we have to fake the coords
+ using offset and inverse sin(r) value */
+ int page_height = 1000;
+
+ pdf_calc(page_height, node, &g);
+ if (node->angle != 0) {
+ svg_start_tag(fp, "g");
+ /* can't use svg_write_number as 2 decimals is far from enough to avoid
+ skewed text */
+ fprintf(fp, " transform=\"matrix(%f,%f,%f,%f,%f,%f)\"",
+ g.ma, -g.mb, -g.mc, g.md, g.tmx, page_height - g.tmy);
+ svg_close_tag(fp);
+ }
+ svg_start_tag(fp, "text");
+ if (!node->angle) {
+ fputs(" x=\"", fp);
+ svg_write_number(fp, g.tmx);
+ fputs("\" y=\"", fp);
+ svg_write_number(fp, page_height - g.tmy);
+ fputs("\"", fp);
+ }
+ fontname = afm_get_font_name(node->filename);
+ if (strcmp(fontname, svg_default_font))
+ fprintf(fp, " font-family=\"%s\"", fontname);
+ fputs(" font-size=\"", fp);
+ svg_write_number(fp, node->size);
+ fputs("\"", fp);
+ if (!svg_color_is_black(node->color))
+ svg_write_color(fp, node->color, "fill");
+ svg_close_tag_single_line(fp);
+ /* support for node->tabwidth missing */
+ svg_write_text(fp, node->text);
+ svg_end_tag(fp, "text");
+ if (node->angle != 0)
+ svg_end_tag(fp, "g");
+}
+
+int gfx_render_svg(
+ gfx_canvas_t *canvas,
+ art_u32 width,
+ art_u32 height,
+ gfx_color_t background,
+ FILE * fp)
+{
+ gfx_node_t *node = canvas->firstnode;
+
+ /* Find the first font used, and assume it is the mostly used
+ one. It reduces the number of font-familty attributes. */
+ while (node) {
+ if (node->type == GFX_TEXT && node->filename) {
+ svg_default_font = afm_get_font_name(node->filename);
+ break;
+ }
+ node = node->next;
+ }
+ fputs("<?xml version=\"1.0\" standalone=\"no\"?>\n"
+ "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\"\n"
+ " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n"
+ "<!--\n"
+ " SVG file created by\n"
+ " RRDtool " PACKAGE_VERSION
+ " Tobias Oetiker, http://tobi.oetiker.ch\n" "\n"
+ " The width/height attributes in the outhermost svg node\n"
+ " are just default sizes for the browser which is used\n"
+ " if the svg file is openened directly without being\n"
+ " embedded in an html file.\n"
+ " The viewBox is the local coord system for rrdtool.\n" "-->\n",
+ fp);
+ svg_start_tag(fp, "svg");
+ fputs(" width=\"", fp);
+ svg_write_number(fp, width * canvas->zoom);
+ fputs("\" height=\"", fp);
+ svg_write_number(fp, height * canvas->zoom);
+ fputs("\" x=\"0\" y=\"0\" viewBox=\"", fp);
+ svg_write_number(fp, -LINEOFFSET);
+ fputs(" ", fp);
+ svg_write_number(fp, -LINEOFFSET);
+ fputs(" ", fp);
+ svg_write_number(fp, width - LINEOFFSET);
+ fputs(" ", fp);
+ svg_write_number(fp, height - LINEOFFSET);
+ fputs("\" preserveAspectRatio=\"xMidYMid\"", fp);
+ fprintf(fp, " font-family=\"%s\"", svg_default_font); /* default font */
+ fputs(" stroke-linecap=\"round\" stroke-linejoin=\"round\"", fp);
+ fputs(" xmlns=\"http://www.w3.org/2000/svg\"", fp);
+ fputs(" xmlns:xlink=\"http://www.w3.org/1999/xlink\"", fp);
+ svg_close_tag(fp);
+ svg_start_tag(fp, "rect");
+ fprintf(fp, " x=\"0\" y=\"0\" width=\"%d\" height=\"%d\"", width, height);
+ svg_write_color(fp, background, "fill");
+ svg_close_tag_empty_node(fp);
+ node = canvas->firstnode;
+ while (node) {
+ switch (node->type) {
+ case GFX_LINE:
+ svg_multi_path(fp, &node);
+ break;
+ case GFX_AREA:
+ svg_area(fp, node);
+ break;
+ case GFX_TEXT:
+ svg_text(fp, node);
+ }
+ node = node->next;
+ }
+ svg_end_tag(fp, "svg");
+ return 0;