From badb4b5a280242c6991970d25c4069bc12e77f10 Mon Sep 17 00:00:00 2001 From: oetiker Date: Wed, 3 Apr 2002 14:52:15 +0000 Subject: [PATCH] As gfx_canvas_t now has excatly the same lifespan as image_desc_t, I've made 'gfx_canvas_t canvas' a member of image_desc_t and dropped it as a separate parameter in all function calls. imgformat, interlaced and zoom are moved to gfx_canvas_t. I have dropped my old fontlib-enum as imgformat contains that information. The gfx_render_xxx switch is moved to rrd_gfx so rrd_graph is (almost) only bothered with image formats in cmd line parsing. gfx_close_path is added. gfx_new_dashed_line is added with 2 new arguments: length of a dash and length between dashes. gfx_new_line is still there for plain lines. Having dash-length == 0 creates normal line. rrd_graph.c is not updated for dashed lines. It's not decided how one should specify which and how lines are dashed. An extension of the color specification? svg is updated for dashes and opacity, but libart code is not. I've fixed indent in SVG, all lines had a space before func decl. etc. Misc small fixes, e.g. sscanf of gfx_color_t, position of x-axis arrow. --- Peter Speck git-svn-id: svn://svn.oetiker.ch/rrdtool/trunk/program@114 a5681a0c-68f1-0310-ab6d-d61299d08faa --- src/rrd_gfx.c | 282 +++++++++++++++++++++++++++++------------------- src/rrd_gfx.h | 28 ++++- src/rrd_graph.c | 163 +++++++++++++--------------- src/rrd_graph.h | 21 ++-- 4 files changed, 282 insertions(+), 212 deletions(-) diff --git a/src/rrd_gfx.c b/src/rrd_gfx.c index e36910d..7ca6450 100644 --- a/src/rrd_gfx.c +++ b/src/rrd_gfx.c @@ -32,6 +32,7 @@ gfx_node_t *gfx_new_node( gfx_canvas_t *canvas,enum gfx_en type){ node->path = NULL; /* path */ node->points = 0; node->points_max =0; + node->closed_path = 0; node->svp = NULL; /* svp */ node->filename = NULL; /* font or image filename */ node->text = NULL; @@ -56,6 +57,9 @@ gfx_canvas_t *gfx_new_canvas (void) { gfx_canvas_t *canvas = art_new(gfx_canvas_t,1); canvas->firstnode = NULL; canvas->lastnode = NULL; + canvas->imgformat = IF_PNG; /* we default to PNG output */ + canvas->interlaced = 0; + canvas->zoom = 1.0; return canvas; } @@ -64,6 +68,14 @@ gfx_node_t *gfx_new_line(gfx_canvas_t *canvas, double x0, double y0, double x1, double y1, double width, gfx_color_t color){ + return gfx_new_dashed_line(canvas, x0, y0, x1, y1, width, color, 0, 0); +} + +gfx_node_t *gfx_new_dashed_line(gfx_canvas_t *canvas, + double x0, double y0, + double x1, double y1, + double width, gfx_color_t color, + double dash_on, double dash_off){ gfx_node_t *node; ArtVpath *vec; @@ -79,6 +91,8 @@ gfx_node_t *gfx_new_line(gfx_canvas_t *canvas, node->points_max = 3; node->color = color; node->size = width; + node->dash_on = dash_on; + node->dash_off = dash_off; node->path = vec; return node; } @@ -153,7 +167,9 @@ int gfx_add_point (gfx_node_t *node, return 0; } - +void gfx_close_path (gfx_node_t *node) { + node->closed_path = 1; +} /* create a text node */ gfx_node_t *gfx_new_text (gfx_canvas_t *canvas, @@ -182,7 +198,32 @@ gfx_node_t *gfx_new_text (gfx_canvas_t *canvas, return node; } -double gfx_get_text_width ( double start, char* font, double size, +int gfx_render(gfx_canvas_t *canvas, + art_u32 width, art_u32 height, + gfx_color_t background, FILE *fp){ + switch (canvas->imgformat) { + case IF_PNG: + return gfx_render_png (canvas, width, height, background, fp); + case IF_SVG: + return gfx_render_svg (canvas, width, height, background, fp); + default: + return -1; + } +} + +double gfx_get_text_width ( gfx_canvas_t *canvas, + double start, char* font, double size, + double tabwidth, char* text){ + switch (canvas->imgformat) { + case IF_PNG: + return gfx_get_text_width_libart (canvas, start, font, size, tabwidth, text); + default: + return size * strlen(text); + } +} + +double gfx_get_text_width_libart ( gfx_canvas_t *canvas, + double start, char* font, double size, double tabwidth, char* text){ FT_GlyphSlot slot; @@ -237,7 +278,6 @@ static int gfx_save_png (art_u8 *buffer, FILE *fp, /* render grafics into png image */ int gfx_render_png (gfx_canvas_t *canvas, art_u32 width, art_u32 height, - double zoom, gfx_color_t background, FILE *fp){ @@ -245,8 +285,8 @@ int gfx_render_png (gfx_canvas_t *canvas, gfx_node_t *node = canvas->firstnode; art_u8 red = background >> 24, green = (background >> 16) & 0xff; art_u8 blue = (background >> 8) & 0xff, alpha = ( background & 0xff ); - unsigned long pys_width = width * zoom; - unsigned long pys_height = height * zoom; + unsigned long pys_width = width * canvas->zoom; + unsigned long pys_height = height * canvas->zoom; const int bytes_per_pixel = 3; unsigned long rowstride = pys_width*bytes_per_pixel; /* bytes per pixel */ art_u8 *buffer = art_new (art_u8, rowstride*pys_height); @@ -259,12 +299,17 @@ int gfx_render_png (gfx_canvas_t *canvas, ArtVpath *vec; double dst[6]; ArtSVP *svp; - art_affine_scale(dst,zoom,zoom); + if (node->closed_path) { + /* libart uses end==start for closed as indicator of closed path */ + gfx_add_point(node, node->path[0].x, node->path[0].y); + node->closed_path = 0; + } + art_affine_scale(dst,canvas->zoom,canvas->zoom); vec = art_vpath_affine_transform(node->path,dst); if(node->type == GFX_LINE){ svp = art_svp_vpath_stroke ( vec, ART_PATH_STROKE_JOIN_ROUND, ART_PATH_STROKE_CAP_ROUND, - node->size*zoom,1,1); + node->size*canvas->zoom,1,1); } else { svp = art_svp_from_vpath ( vec ); } @@ -303,11 +348,11 @@ int gfx_render_png (gfx_canvas_t *canvas, error = FT_Set_Char_Size(face, /* handle to face object */ (long)(node->size*64), (long)(node->size*64), - (long)(100*zoom), - (long)(100*zoom)); + (long)(100*canvas->zoom), + (long)(100*canvas->zoom)); if ( error ) break; - pen_x = node->x * zoom; - pen_y = node->y * zoom; + pen_x = node->x * canvas->zoom; + pen_y = node->y * canvas->zoom; slot = face->glyph; for(text=(unsigned char *)node->text;*text;text++) { @@ -471,8 +516,14 @@ static int gfx_save_png (art_u8 *buffer, FILE *fp, long width, long height, lon } +/* ------- SVG ------- + SVG reference: + http://www.w3.org/TR/SVG/ +*/ static int svg_indent = 0; static int svg_single_line = 0; +static const char *svg_default_font = "Helvetica"; + static void svg_print_indent(FILE *fp) { int i; @@ -483,28 +534,28 @@ static void svg_print_indent(FILE *fp) } static void svg_start_tag(FILE *fp, const char *name) - { +{ svg_print_indent(fp); putc('<', fp); fputs(name, fp); svg_indent++; - } +} - static void svg_close_tag_single_line(FILE *fp) - { +static void svg_close_tag_single_line(FILE *fp) +{ svg_single_line++; putc('>', fp); - } +} - static void svg_close_tag(FILE *fp) - { +static void svg_close_tag(FILE *fp) +{ putc('>', fp); if (!svg_single_line) putc('\n', fp); - } +} - static void svg_end_tag(FILE *fp, const char *name) - { +static void svg_end_tag(FILE *fp, const char *name) +{ /* name is NULL if closing empty-node tag */ svg_indent--; if (svg_single_line) @@ -518,15 +569,15 @@ static void svg_start_tag(FILE *fp, const char *name) putc('/', fp); } svg_close_tag(fp); - } +} - static void svg_close_tag_empty_node(FILE *fp) - { +static void svg_close_tag_empty_node(FILE *fp) +{ svg_end_tag(fp, NULL); - } +} - static void svg_write_text(FILE *fp, const char *p) - { +static void svg_write_text(FILE *fp, const char *p) +{ char ch; const char *start, *last; if (!p) @@ -554,10 +605,10 @@ static void svg_start_tag(FILE *fp, const char *name) default: putc(ch, fp); } } - } +} - static void svg_write_number(FILE *fp, double d) - { +static void svg_write_number(FILE *fp, double d) +{ /* omit decimals if integer to reduce filesize */ char buf[60], *p; snprintf(buf, sizeof(buf), "%.2f", d); @@ -575,41 +626,64 @@ static void svg_start_tag(FILE *fp, const char *name) break; } fputs(buf, fp); - } +} - static int svg_color_is_black(int c) - { - /* gfx_color_t is RRGGBBAA, svg can use #RRGGBB like html */ - c = (int)((c >> 8) & 0xFFFFFF); - return !c; - } +static int svg_color_is_black(int c) +{ + /* gfx_color_t is RRGGBBAA */ + return c == 0x000000FF; +} - static void svg_write_color(FILE *fp, int c) - { - /* gfx_color_t is RRGGBBAA, svg can use #RRGGBB like html */ - c = (int)((c >> 8) & 0xFFFFFF); - if ((c & 0x0F0F0F) == ((c >> 4) & 0x0F0F0F)) { +static void svg_write_color(FILE *fp, gfx_color_t c, const char *attr) +{ + /* gfx_color_t is RRGGBBAA, svg can use #RRGGBB and #RGB like html */ + gfx_color_t rrggbb = (int)((c >> 8) & 0xFFFFFF); + gfx_color_t opacity = c & 0xFF; + fprintf(fp, " %s=\"", attr); + if ((rrggbb & 0x0F0F0F) == ((rrggbb >> 4) & 0x0F0F0F)) { /* css2 short form, #rgb is #rrggbb, not #r0g0b0 */ - fprintf(fp, "#%03X", - ( ((c >> 8) & 0xF00) - | ((c >> 4) & 0x0F0) - | ( c & 0x00F))); + fprintf(fp, "#%03lX", + ( ((rrggbb >> 8) & 0xF00) + | ((rrggbb >> 4) & 0x0F0) + | ( rrggbb & 0x00F))); } else { - fprintf(fp, "#%06X", c); + fprintf(fp, "#%06lX", rrggbb); } + fputs("\"", fp); + if (opacity != 0xFF) { + fprintf(fp, " stroke-opacity=\""); + svg_write_number(fp, opacity / 255.0); + fputs("\"", fp); } +} - static int svg_is_int_step(double a, double b) - { +static void svg_common_path_attributes(FILE *fp, gfx_node_t *node) +{ + fputs(" stroke-width=\"", fp); + svg_write_number(fp, node->size); + fputs("\"", fp); + svg_write_color(fp, node->color, "stroke"); + fputs(" fill=\"none\"", fp); + if (node->dash_on != 0 && node->dash_off != 0) { + fputs(" stroke-dasharray=\"", fp); + svg_write_number(fp, node->dash_on); + fputs(",", fp); + svg_write_number(fp, node->dash_off); + fputs("\"", fp); + } +} + +static int svg_is_int_step(double a, double b) +{ double diff = fabs(a - b); return floor(diff) == diff; - } +} - static int svg_path_straight_segment(FILE *fp, +static int svg_path_straight_segment(FILE *fp, double lastA, double currentA, double currentB, gfx_node_t *node, int segment_idx, int isx, char absChar, char relChar) - { +{ if (!svg_is_int_step(lastA, currentA)) { putc(absChar, fp); svg_write_number(fp, currentA); @@ -630,23 +704,18 @@ static void svg_start_tag(FILE *fp, const char *name) putc(relChar, fp); svg_write_number(fp, currentA - lastA); return 0; - } +} - static void svg_path(FILE *fp, gfx_node_t *node, int multi) - { +static void svg_path(FILE *fp, gfx_node_t *node, int multi) +{ int i; double lastX = 0, lastY = 0; /* for straight lines tags take less space than tags because of the efficient packing in the 'd' attribute */ svg_start_tag(fp, "path"); - if (!multi) { - fputs(" stroke-width=\"", fp); - svg_write_number(fp, node->size); - fputs("\" stroke=\"", fp); - svg_write_color(fp, node->color); - fputs("\" fill=\"none\"", fp); - } + if (!multi) + svg_common_path_attributes(fp, node); fputs(" d=\"", fp); /* specification of the 'd' attribute: */ /* http://www.w3.org/TR/SVG/paths.html#PathDataGeneralInformation */ @@ -684,12 +753,14 @@ static void svg_start_tag(FILE *fp, const char *name) lastX = x; lastY = y; } + if (node->closed_path) + fputs(" Z", fp); fputs("\"", fp); svg_close_tag_empty_node(fp); - } +} - static void svg_multi_path(FILE *fp, gfx_node_t **nodeR) - { +static void svg_multi_path(FILE *fp, gfx_node_t **nodeR) +{ /* optimize for multiple paths with the same color, penwidth, etc. */ int num = 1; gfx_node_t *node = *nodeR; @@ -697,7 +768,9 @@ static void svg_start_tag(FILE *fp, const char *name) while (next) { if (next->type != node->type || next->size != node->size - || next->color != node->color) + || next->color != node->color + || next->dash_on != node->dash_on + || next->dash_off != node->dash_off) break; next = next->next; num++; @@ -707,11 +780,7 @@ static void svg_start_tag(FILE *fp, const char *name) return; } svg_start_tag(fp, "g"); - fputs(" stroke-width=\"", fp); - svg_write_number(fp, node->size); - fputs("\" stroke=\"", fp); - svg_write_color(fp, node->color); - fputs("\" fill=\"none\"", fp); + svg_common_path_attributes(fp, node); svg_close_tag(fp); while (num && node) { svg_path(fp, node, 1); @@ -721,16 +790,16 @@ static void svg_start_tag(FILE *fp, const char *name) *nodeR = node; } svg_end_tag(fp, "g"); - } +} - static void svg_area(FILE *fp, gfx_node_t *node) - { +static void svg_area(FILE *fp, gfx_node_t *node) +{ int i; double startX = 0, startY = 0; svg_start_tag(fp, "polygon"); - fputs(" fill=\"", fp); - svg_write_color(fp, node->color); - fputs("\" points=\"", fp); + fputs(" ", fp); + svg_write_color(fp, node->color, "fill"); + fputs(" points=\"", fp); for (i = 0; i < node->points; i++) { ArtVpath *vec = node->path + i; double x = vec->x - LINEOFFSET; @@ -761,10 +830,10 @@ static void svg_start_tag(FILE *fp, const char *name) } fputs("\"", fp); svg_close_tag_empty_node(fp); - } +} - static void svg_text(FILE *fp, gfx_node_t *node) - { +static void svg_text(FILE *fp, gfx_node_t *node) +{ double x = node->x - LINEOFFSET; double y = node->y - LINEOFFSET; if (node->angle != 0) { @@ -790,14 +859,13 @@ static void svg_start_tag(FILE *fp, const char *name) svg_write_number(fp, x); fputs("\" y=\"", fp); svg_write_number(fp, y); + if (strcmp(node->filename, svg_default_font)) + fprintf(fp, " font-family=\"%s\"", node->filename); fputs("\" font-size=\"", fp); svg_write_number(fp, node->size); fputs("\"", fp); - if (!svg_color_is_black(node->color)) { - fputs(" fill=\"", fp); - svg_write_color(fp, node->color); - fputs("\"", fp); - } + if (!svg_color_is_black(node->color)) + svg_write_color(fp, node->color, "fill"); switch (node->halign) { case GFX_H_RIGHT: fputs(" text-anchor=\"end\"", fp); break; case GFX_H_CENTER: fputs(" text-anchor=\"middle\"", fp); break; @@ -810,32 +878,31 @@ static void svg_start_tag(FILE *fp, const char *name) svg_end_tag(fp, "text"); if (node->angle != 0) svg_end_tag(fp, "g"); - } +} - int gfx_render_svg (gfx_canvas_t *canvas, +int gfx_render_svg (gfx_canvas_t *canvas, art_u32 width, art_u32 height, - double zoom, gfx_color_t background, FILE *fp){ gfx_node_t *node = canvas->firstnode; fputs( - "\n" - "\n" - "\n", fp); +"\n" +"\n" +"\n", fp); svg_start_tag(fp, "svg"); fputs(" width=\"", fp); - svg_write_number(fp, width * zoom); + svg_write_number(fp, width * canvas->zoom); fputs("\" height=\"", fp); - svg_write_number(fp, height * zoom); + svg_write_number(fp, height * canvas->zoom); fputs("\" x=\"0\" y=\"0\" viewBox=\"", fp); svg_write_number(fp, -LINEOFFSET); fputs(" ", fp); @@ -845,13 +912,12 @@ static void svg_start_tag(FILE *fp, const char *name) fputs(" ", fp); svg_write_number(fp, height - LINEOFFSET); fputs("\" preserveAspectRatio=\"xMidYMid\"", fp); - fputs(" font-family=\"Helvetica\"", fp); /* default font */ + fprintf(fp, " font-family=\"%s\"", svg_default_font); /* default font */ + fputs(" stroke-linecap=\"round\" stroke-linejoin=\"round\"", fp); svg_close_tag(fp); svg_start_tag(fp, "rect"); fprintf(fp, " x=\"0\" y=\"0\" width=\"%d\" height=\"%d\"", width, height); - fputs(" style=\"fill:", fp); - svg_write_color(fp, background); - fputs("\"", fp); + svg_write_color(fp, background, "fill"); svg_close_tag_empty_node(fp); while (node) { switch (node->type) { @@ -868,4 +934,4 @@ static void svg_start_tag(FILE *fp, const char *name) } svg_end_tag(fp, "svg"); return 0; - } +} diff --git a/src/rrd_gfx.h b/src/rrd_gfx.h index 504f425..ed107cb 100644 --- a/src/rrd_gfx.h +++ b/src/rrd_gfx.h @@ -9,6 +9,7 @@ #define LIBART_COMPILATION #include +enum gfx_if_en {IF_PNG=0,IF_SVG}; enum gfx_en { GFX_LINE=0,GFX_AREA,GFX_TEXT }; enum gfx_h_align_en { GFX_H_NULL=0, GFX_H_LEFT, GFX_H_RIGHT, GFX_H_CENTER }; enum gfx_v_align_en { GFX_V_NULL=0, GFX_V_TOP, GFX_V_BOTTOM, GFX_V_CENTER }; @@ -18,14 +19,16 @@ typedef struct gfx_node_t { enum gfx_en type; /* type of graph element */ gfx_color_t color; /* color of element 0xRRGGBBAA alpha 0xff is solid*/ double size; /* font size, line width */ + double dash_on, dash_off; /* dash line fragments lengths */ ArtVpath *path; /* path */ + int closed_path; int points; int points_max; ArtSVP *svp; /* svp */ char *filename; /* font or image filename */ char *text; double x,y; /* position */ - double angle; + double angle; /* text angle */ enum gfx_h_align_en halign; /* text alignement */ enum gfx_v_align_en valign; /* text alignement */ double tabwidth; @@ -37,6 +40,9 @@ typedef struct gfx_canvas_t { struct gfx_node_t *firstnode; struct gfx_node_t *lastnode; + enum gfx_if_en imgformat; /* image format */ + int interlaced; /* will the graph be interlaced? */ + double zoom; /* zoom for graph */ } gfx_canvas_t; @@ -48,6 +54,12 @@ gfx_node_t *gfx_new_line (gfx_canvas_t *canvas, double x1, double y1, double width, gfx_color_t color); +gfx_node_t *gfx_new_dashed_line (gfx_canvas_t *canvas, + double x0, double y0, + double x1, double y1, + double width, gfx_color_t color, + double dash_on, double dash_off); + /* create a new area */ gfx_node_t *gfx_new_area (gfx_canvas_t *canvas, double x0, double y0, @@ -58,6 +70,9 @@ gfx_node_t *gfx_new_area (gfx_canvas_t *canvas, /* add a point to a line or to an area */ int gfx_add_point (gfx_node_t *node, double x, double y); +/* close current path so it ends at the same point as it started */ +void gfx_close_path (gfx_node_t *node); + /* create a text node */ gfx_node_t *gfx_new_text (gfx_canvas_t *canvas, @@ -69,7 +84,8 @@ gfx_node_t *gfx_new_text (gfx_canvas_t *canvas, char* text); /* measure width of a text string */ -double gfx_get_text_width ( double start, char* font, double size, +double gfx_get_text_width ( gfx_canvas_t *canvas, + double start, char* font, double size, double tabwidth, char* text); @@ -77,9 +93,14 @@ double gfx_get_text_width ( double start, char* font, double size, /* turn graph into a png image */ int gfx_render_png (gfx_canvas_t *canvas, art_u32 width, art_u32 height, - double zoom, gfx_color_t background, FILE *fo); +double gfx_get_text_width_libart ( gfx_canvas_t *canvas, + double start, char* font, double size, + double tabwidth, char* text); +int gfx_render (gfx_canvas_t *canvas, + art_u32 width, art_u32 height, + gfx_color_t background, FILE *fo); /* free memory used by nodes this will also remove memory required for node chain and associated material */ @@ -90,7 +111,6 @@ int gfx_destroy (gfx_canvas_t *canvas); /* turn graph into an svg image */ int gfx_render_svg (gfx_canvas_t *canvas, art_u32 width, art_u32 height, - double zoom, gfx_color_t background, FILE *fo); diff --git a/src/rrd_graph.c b/src/rrd_graph.c index 8b9e679..537a03f 100644 --- a/src/rrd_graph.c +++ b/src/rrd_graph.c @@ -179,9 +179,10 @@ enum gf_en gf_conv(char *string){ return (-1); } -enum if_en if_conv(char *string){ +enum gfx_if_en if_conv(char *string){ conv_if(PNG,IF_PNG) + conv_if(SVG,IF_SVG) return (-1); } @@ -247,6 +248,7 @@ im_free(image_desc_t *im) free (im->gdes[i].rpnp); } free(im->gdes); + gfx_destroy(im->canvas); return 0; } @@ -1291,7 +1293,8 @@ leg_place(image_desc_t *im) im->gdes[i].gf != GF_COMMENT) { fill += box; } - fill += gfx_get_text_width(fill+border,im->text_prop[TEXT_PROP_LEGEND].font, + fill += gfx_get_text_width(im->canvas, fill+border, + im->text_prop[TEXT_PROP_LEGEND].font, im->text_prop[TEXT_PROP_LEGEND].size, im->tabwidth, im->gdes[i].legend); @@ -1338,7 +1341,8 @@ leg_place(image_desc_t *im) im->gdes[ii].leg_x = leg_x; im->gdes[ii].leg_y = leg_y; leg_x += - gfx_get_text_width(leg_x,im->text_prop[TEXT_PROP_LEGEND].font, + gfx_get_text_width(im->canvas, leg_x, + im->text_prop[TEXT_PROP_LEGEND].font, im->text_prop[TEXT_PROP_LEGEND].size, im->tabwidth, im->gdes[ii].legend) @@ -1370,7 +1374,7 @@ leg_place(image_desc_t *im) int -horizontal_grid(gfx_canvas_t *canvas, image_desc_t *im) +horizontal_grid(image_desc_t *im) { double range; double scaledrange; @@ -1379,7 +1383,7 @@ horizontal_grid(gfx_canvas_t *canvas, image_desc_t *im) double gridstep; double scaledstep; char graph_label[100]; - double x0,x1,y0,y1; + double x0,x1,y0; int labfact,gridind; int decimals, fractionals; char labfmt[64]; @@ -1480,20 +1484,20 @@ horizontal_grid(gfx_canvas_t *canvas, image_desc_t *im) } } - gfx_new_text ( canvas, + gfx_new_text ( im->canvas, x0-im->text_prop[TEXT_PROP_AXIS].size/1.5, y0, im->graph_col[GRC_FONT], im->text_prop[TEXT_PROP_AXIS].font, im->text_prop[TEXT_PROP_AXIS].size, im->tabwidth, 0.0, GFX_H_RIGHT, GFX_V_CENTER, graph_label ); - gfx_new_line ( canvas, + gfx_new_line ( im->canvas, x0-2,y0, x1+2,y0, MGRIDWIDTH, im->graph_col[GRC_MGRID] ); } else { - gfx_new_line ( canvas, + gfx_new_line ( im->canvas, x0-1,y0, x1+1,y0, GRIDWIDTH, im->graph_col[GRC_GRID] ); @@ -1506,13 +1510,13 @@ horizontal_grid(gfx_canvas_t *canvas, image_desc_t *im) /* logaritmic horizontal grid */ int -horizontal_log_grid(gfx_canvas_t *canvas, image_desc_t *im) +horizontal_log_grid(image_desc_t *im) { double pixpex; int ii,i; int minoridx=0, majoridx=0; char graph_label[100]; - double x0,x1,y0,y1; + double x0,x1,y0; double value, pixperstep, minstep; /* find grid spaceing */ @@ -1547,7 +1551,7 @@ horizontal_log_grid(gfx_canvas_t *canvas, image_desc_t *im) while(yloglab[minoridx][++i] > 0){ y0 = ytr(im,value * yloglab[minoridx][i]); if (y0 <= im->yorigin - im->ysize) break; - gfx_new_line ( canvas, + gfx_new_line ( im->canvas, x0-1,y0, x1+1,y0, GRIDWIDTH, im->graph_col[GRC_GRID] ); @@ -1564,13 +1568,13 @@ horizontal_log_grid(gfx_canvas_t *canvas, image_desc_t *im) while(yloglab[majoridx][++i] > 0){ y0 = ytr(im,value * yloglab[majoridx][i]); if (y0 <= im->yorigin - im->ysize) break; - gfx_new_line ( canvas, + gfx_new_line ( im->canvas, x0-2,y0, x1+2,y0, MGRIDWIDTH, im->graph_col[GRC_MGRID] ); sprintf(graph_label,"%3.0e",value * yloglab[majoridx][i]); - gfx_new_text ( canvas, + gfx_new_text ( im->canvas, x0-im->text_prop[TEXT_PROP_AXIS].size/1.5, y0, im->graph_col[GRC_FONT], im->text_prop[TEXT_PROP_AXIS].font, @@ -1585,7 +1589,6 @@ horizontal_log_grid(gfx_canvas_t *canvas, image_desc_t *im) void vertical_grid( - gfx_canvas_t *canvas, image_desc_t *im ) { int xlab_sel; /* which sort of label and grid ? */ @@ -1629,7 +1632,7 @@ vertical_grid( /* are we inside the graph ? */ if (ti < im->start || ti > im->end) continue; x0 = xtr(im,ti); - gfx_new_line(canvas,x0,y0+1, x0,y1-1,GRIDWIDTH, im->graph_col[GRC_GRID]); + gfx_new_line(im->canvas,x0,y0+1, x0,y1-1,GRIDWIDTH, im->graph_col[GRC_GRID]); } @@ -1643,7 +1646,7 @@ vertical_grid( /* are we inside the graph ? */ if (ti < im->start || ti > im->end) continue; x0 = xtr(im,ti); - gfx_new_line(canvas,x0,y0+2, x0,y1-2,MGRIDWIDTH, im->graph_col[GRC_MGRID]); + gfx_new_line(im->canvas,x0,y0+2, x0,y1-2,MGRIDWIDTH, im->graph_col[GRC_MGRID]); } /* paint the labels below the graph */ @@ -1662,7 +1665,7 @@ vertical_grid( #else # error "your libc has no strftime I guess we'll abort the exercise here." #endif - gfx_new_text ( canvas, + gfx_new_text ( im->canvas, xtr(im,tilab), y0+im->text_prop[TEXT_PROP_AXIS].size/1.5, im->graph_col[GRC_FONT], im->text_prop[TEXT_PROP_AXIS].font, @@ -1677,33 +1680,32 @@ vertical_grid( void axis_paint( - image_desc_t *im, - gfx_canvas_t *canvas + image_desc_t *im ) { /* draw x and y axis */ - gfx_new_line ( canvas, im->xorigin+im->xsize,im->yorigin, + gfx_new_line ( im->canvas, im->xorigin+im->xsize,im->yorigin, im->xorigin+im->xsize,im->yorigin-im->ysize, GRIDWIDTH, im->graph_col[GRC_GRID]); - gfx_new_line ( canvas, im->xorigin,im->yorigin-im->ysize, + gfx_new_line ( im->canvas, im->xorigin,im->yorigin-im->ysize, im->xorigin+im->xsize,im->yorigin-im->ysize, GRIDWIDTH, im->graph_col[GRC_GRID]); - gfx_new_line ( canvas, im->xorigin-4,im->yorigin, + gfx_new_line ( im->canvas, im->xorigin-4,im->yorigin, im->xorigin+im->xsize+4,im->yorigin, MGRIDWIDTH, im->graph_col[GRC_GRID]); - gfx_new_line ( canvas, im->xorigin,im->yorigin+4, + gfx_new_line ( im->canvas, im->xorigin,im->yorigin+4, im->xorigin,im->yorigin-im->ysize-4, MGRIDWIDTH, im->graph_col[GRC_GRID]); /* arrow for X axis direction */ - gfx_new_area ( canvas, - im->xorigin+im->xsize+4, im->yorigin-3, - im->xorigin+im->xsize+4, im->yorigin+3, - im->xorigin+im->xsize+9, im->yorigin, + gfx_new_area ( im->canvas, + im->xorigin+im->xsize+3, im->yorigin-3, + im->xorigin+im->xsize+3, im->yorigin+4, + im->xorigin+im->xsize+8, im->yorigin+0.5, // LINEOFFSET im->graph_col[GRC_ARROW]); @@ -1711,19 +1713,15 @@ axis_paint( } void -grid_paint( - image_desc_t *im, - gfx_canvas_t *canvas - - ) +grid_paint(image_desc_t *im) { long i; int res=0; - double x0,x1,x2,x3,y0,y1,y2,y3; /* points for filled graph and more*/ + double x0,y0; /* points for filled graph and more*/ gfx_node_t *node; /* draw 3d border */ - node = gfx_new_area (canvas, 0,im->ygif, + node = gfx_new_area (im->canvas, 0,im->ygif, 2,im->ygif-2, 2,2,im->graph_col[GRC_SHADEA]); gfx_add_point( node , im->xgif - 2, 2 ); @@ -1731,7 +1729,7 @@ grid_paint( gfx_add_point( node , 0,0 ); /* gfx_add_point( node , 0,im->ygif ); */ - node = gfx_new_area (canvas, 2,im->ygif-2, + node = gfx_new_area (im->canvas, 2,im->ygif-2, im->xgif-2,im->ygif-2, im->xgif - 2, 2, im->graph_col[GRC_SHADEB]); @@ -1742,19 +1740,19 @@ grid_paint( if (im->draw_x_grid == 1 ) - vertical_grid(canvas, im); + vertical_grid(im); if (im->draw_y_grid == 1){ if(im->logarithmic){ - res = horizontal_log_grid(canvas,im); + res = horizontal_log_grid(im); } else { - res = horizontal_grid(canvas,im); + res = horizontal_grid(im); } /* dont draw horizontal grid if there is no min and max val */ if (! res ) { char *nodata = "No Data found"; - gfx_new_text(canvas,im->xgif/2, (2*im->yorigin-im->ysize) / 2, + gfx_new_text(im->canvas,im->xgif/2, (2*im->yorigin-im->ysize) / 2, im->graph_col[GRC_FONT], im->text_prop[TEXT_PROP_AXIS].font, im->text_prop[TEXT_PROP_AXIS].size, @@ -1764,15 +1762,15 @@ grid_paint( } /* yaxis description */ - #if 0 - gfx_new_text( canvas, + if (im->canvas->imgformat != IF_PNG) { + gfx_new_text( im->canvas, 7, (im->yorigin - im->ysize/2), im->graph_col[GRC_FONT], im->text_prop[TEXT_PROP_AXIS].font, im->text_prop[TEXT_PROP_AXIS].size, im->tabwidth, 270.0, GFX_H_CENTER, GFX_V_CENTER, im->ylegend); - #else + } else { /* horrible hack until we can actually print vertically */ { int n; @@ -1781,7 +1779,7 @@ grid_paint( for (n=0;nylegend);n++) { s[0]=im->ylegend[n]; s[1]='\0'; - gfx_new_text(canvas,7,im->text_prop[TEXT_PROP_AXIS].size*(l-n), + gfx_new_text(im->canvas,7,im->text_prop[TEXT_PROP_AXIS].size*(l-n), im->graph_col[GRC_FONT], im->text_prop[TEXT_PROP_AXIS].font, im->text_prop[TEXT_PROP_AXIS].size, im->tabwidth, 270.0, @@ -1789,10 +1787,10 @@ grid_paint( s); } } - #endif + } /* graph title */ - gfx_new_text( canvas, + gfx_new_text( im->canvas, im->xgif/2, im->text_prop[TEXT_PROP_TITLE].size, im->graph_col[GRC_FONT], im->text_prop[TEXT_PROP_TITLE].font, @@ -1814,27 +1812,27 @@ grid_paint( && im->gdes[i].gf != GF_COMMENT) { int boxH, boxV; - boxH = gfx_get_text_width(0, + boxH = gfx_get_text_width(im->canvas, 0, im->text_prop[TEXT_PROP_AXIS].font, im->text_prop[TEXT_PROP_AXIS].size, im->tabwidth,"M") * 1.25; boxV = boxH; - node = gfx_new_area(canvas, + node = gfx_new_area(im->canvas, x0,y0-boxV, x0,y0, x0+boxH,y0, im->gdes[i].col); gfx_add_point ( node, x0+boxH, y0-boxV ); - node = gfx_new_line(canvas, + node = gfx_new_line(im->canvas, x0,y0-boxV, x0,y0, 1,0x000000FF); gfx_add_point(node,x0+boxH,y0); gfx_add_point(node,x0+boxH,y0-boxV); - gfx_add_point(node,x0,y0-boxV); + gfx_close_path(node); x0 += boxH / 1.25 * 2; } - gfx_new_text ( canvas, x0, y0, + gfx_new_text ( im->canvas, x0, y0, im->graph_col[GRC_FONT], im->text_prop[TEXT_PROP_AXIS].font, im->text_prop[TEXT_PROP_AXIS].size, @@ -1864,17 +1862,19 @@ int lazy_check(image_desc_t *im){ return 0; if ((fd = fopen(im->graphfile,"rb")) == NULL) return 0; /* the file does not exist */ - switch (im->imgformat) { + switch (im->canvas->imgformat) { case IF_PNG: size = PngSize(fd,&(im->xgif),&(im->ygif)); break; + default: + size = 1; } fclose(fd); return size; } void -pie_part(gfx_canvas_t *canvas, gfx_color_t color, +pie_part(image_desc_t *im, gfx_color_t color, double PieCenterX, double PieCenterY, double Radius, double startangle, double endangle) { @@ -1904,7 +1904,7 @@ pie_part(gfx_canvas_t *canvas, gfx_color_t color, Radius *= 0.8; } - node=gfx_new_area(canvas, + node=gfx_new_area(im->canvas, PieCenterX+sin(startangle)*Radius, PieCenterY-cos(startangle)*Radius, PieCenterX, @@ -1961,7 +1961,7 @@ graph_size_location(image_desc_t *im, int elements, int piechart ) ** automatically has some vertical spacing. The horizontal ** spacing is added here, on each side. */ - Xtitle = gfx_get_text_width(0, + Xtitle = gfx_get_text_width(im->canvas, 0, im->text_prop[TEXT_PROP_TITLE].font, im->text_prop[TEXT_PROP_TITLE].size, im->tabwidth, @@ -2074,7 +2074,6 @@ graph_paint(image_desc_t *im, char ***calcpr) int piechart = 0; double PieStart=0.0; FILE *fo; - gfx_canvas_t *canvas; gfx_node_t *node; double areazero = 0.0; @@ -2130,12 +2129,10 @@ graph_paint(image_desc_t *im, char ***calcpr) if(graph_size_location(im,i,piechart)==-1) return -1; - canvas=gfx_new_canvas(); - /* the actual graph is created by going through the individual graph elements and then drawing them */ - node=gfx_new_area ( canvas, + node=gfx_new_area ( im->canvas, 0, 0, im->xgif, 0, im->xgif, im->ygif, @@ -2144,7 +2141,7 @@ graph_paint(image_desc_t *im, char ***calcpr) gfx_add_point(node,0, im->ygif); if (piechart != 2) { - node=gfx_new_area ( canvas, + node=gfx_new_area ( im->canvas, im->xorigin, im->yorigin, im->xorigin + im->xsize, im->yorigin, im->xorigin + im->xsize, im->yorigin-im->ysize, @@ -2157,11 +2154,11 @@ graph_paint(image_desc_t *im, char ***calcpr) if (im->maxval < 0.0) areazero = im->maxval; - axis_paint(im,canvas); + axis_paint(im); } if (piechart) { - pie_part(canvas,im->graph_col[GRC_CANVAS],im->pie_x,im->pie_y,im->piesize*0.5,0,2*M_PI); + pie_part(im,im->graph_col[GRC_CANVAS],im->pie_x,im->pie_y,im->piesize*0.5,0,2*M_PI); } for(i=0;igdes_c;i++){ @@ -2182,7 +2179,7 @@ graph_paint(image_desc_t *im, char ***calcpr) im->gdes[i].p_data[ii] > 0.0) { /* generate a tick */ - gfx_new_line(canvas, im -> xorigin + ii, + gfx_new_line(im->canvas, im -> xorigin + ii, im -> yorigin - (im -> gdes[i].yrule * im -> ysize), im -> xorigin + ii, im -> yorigin, @@ -2215,7 +2212,7 @@ graph_paint(image_desc_t *im, char ***calcpr) if ( ! isnan(im->gdes[i].p_data[ii-1]) && ! isnan(im->gdes[i].p_data[ii])){ if (node == NULL){ - node = gfx_new_line(canvas, + node = gfx_new_line(im->canvas, ii-1+im->xorigin,ytr(im,im->gdes[i].p_data[ii-1]), ii+im->xorigin,ytr(im,im->gdes[i].p_data[ii]), im->gdes[i].linewidth, @@ -2242,7 +2239,7 @@ graph_paint(image_desc_t *im, char ***calcpr) ybase = ytr(im,areazero); } area_start = ii-1; - node = gfx_new_area(canvas, + node = gfx_new_area(im->canvas, ii-1+im->xorigin,ybase, ii-1+im->xorigin,ytr(im,im->gdes[i].p_data[ii-1]), ii+im->xorigin,ytr(im,im->gdes[i].p_data[ii]), @@ -2288,7 +2285,7 @@ graph_paint(image_desc_t *im, char ***calcpr) im->gdes[i].yrule = im->gdes[im->gdes[i].vidx].vf.val; if (finite(im->gdes[i].yrule)) { /* even the fetched var can be NaN */ - pie_part(canvas,im->gdes[i].col, + pie_part(im,im->gdes[i].col, im->pie_x,im->pie_y,im->piesize*0.4, M_PI*2.0*PieStart/100.0, M_PI*2.0*(PieStart+im->gdes[i].yrule)/100.0); @@ -2302,7 +2299,7 @@ graph_paint(image_desc_t *im, char ***calcpr) im->draw_y_grid=0; } /* grid_paint also does the text */ - grid_paint(im,canvas); + grid_paint(im); /* the RULES are the last thing to paint ... */ for(i=0;igdes_c;i++){ @@ -2314,7 +2311,7 @@ graph_paint(image_desc_t *im, char ***calcpr) }; if(im->gdes[i].yrule >= im->minval && im->gdes[i].yrule <= im->maxval) - gfx_new_line(canvas, + gfx_new_line(im->canvas, im->xorigin,ytr(im,im->gdes[i].yrule), im->xorigin+im->xsize,ytr(im,im->gdes[i].yrule), 1.0,im->gdes[i].col); @@ -2325,7 +2322,7 @@ graph_paint(image_desc_t *im, char ***calcpr) }; if(im->gdes[i].xrule >= im->start && im->gdes[i].xrule <= im->end) - gfx_new_line(canvas, + gfx_new_line(im->canvas, xtr(im,im->gdes[i].xrule),im->yorigin, xtr(im,im->gdes[i].xrule),im->yorigin-im->ysize, 1.0,im->gdes[i].col); @@ -2349,15 +2346,9 @@ graph_paint(image_desc_t *im, char ***calcpr) return (-1); } } - switch (im->imgformat) { - case IF_PNG: - gfx_render_png (canvas,im->xgif,im->ygif,im->zoom,0x0,fo); - break; - } + gfx_render (im->canvas,im->xgif,im->ygif,0x0,fo); if (strcmp(im->graphfile,"-") != 0) fclose(fo); - - gfx_destroy(canvas); return 0; } @@ -2485,7 +2476,7 @@ rrd_graph(int argc, char **argv, char ***prdata, int *xsize, int *ysize) filename--; } - sprintf((*prdata)[0],im.imginfo,filename,(long)(im.zoom*im.xgif),(long)(im.zoom*im.ygif)); + sprintf((*prdata)[0],im.imginfo,filename,(long)(im.canvas->zoom*im.xgif),(long)(im.canvas->zoom*im.ygif)); } im_free(&im); return 0; @@ -2506,7 +2497,6 @@ rrd_graph_init(image_desc_t *im) im->title[0] = '\0'; im->minval = DNAN; im->maxval = DNAN; - im->interlaced = 0; im->unitsexponent= 9999; im->extra_flags= 0; im->rigid = 0; @@ -2520,8 +2510,7 @@ rrd_graph_init(image_desc_t *im) im->prt_c = 0; im->gdes_c = 0; im->gdes = NULL; - im->zoom = 1.0; - im->imgformat = IF_PNG; /* we default to PNG output */ + im->canvas = gfx_new_canvas(); for(i=0;igraph_col[i]=graph_col[i]; @@ -2709,7 +2698,7 @@ rrd_graph_options(int argc, char *argv[],image_desc_t *im) im->ysize = long_tmp; break; case 'i': - im->interlaced = 1; + im->canvas->interlaced = 1; break; case 'r': im->rigid = 1; @@ -2718,7 +2707,7 @@ rrd_graph_options(int argc, char *argv[],image_desc_t *im) im->imginfo = optarg; break; case 'a': - if((im->imgformat = if_conv(optarg)) == -1) { + if((im->canvas->imgformat = if_conv(optarg)) == -1) { rrd_set_error("unsupported graphics format '%s'",optarg); return; } @@ -2733,7 +2722,7 @@ rrd_graph_options(int argc, char *argv[],image_desc_t *im) break; case 'c': if(sscanf(optarg, - "%10[A-Z]#%8x", + "%10[A-Z]#%8lx", col_nam,&color) == 2){ int ci; if((ci=grc_conv(col_nam)) != -1){ @@ -2743,7 +2732,7 @@ rrd_graph_options(int argc, char *argv[],image_desc_t *im) } } else { rrd_set_error("invalid color def format"); - return -1; + return; } break; case 'n':{ @@ -2788,8 +2777,8 @@ rrd_graph_options(int argc, char *argv[],image_desc_t *im) break; } case 'm': - im->zoom= atof(optarg); - if (im->zoom <= 0.0) { + im->canvas->zoom = atof(optarg); + if (im->canvas->zoom <= 0.0) { rrd_set_error("zoom factor must be > 0"); return; } @@ -3100,12 +3089,12 @@ rrd_graph_color(image_desc_t *im, char *var, char *err, int optional) switch (n) { case 7: - sscanf(color,"#%6x%n",&col,&n); + sscanf(color,"#%6lx%n",&col,&n); col = (col << 8) + 0xff /* shift left by 8 */; if (n!=7) rrd_set_error("Color problem in %s",err); break; case 9: - sscanf(color,"#%8x%n",&col,&n); + sscanf(color,"#%8lx%n",&col,&n); if (n==9) break; default: rrd_set_error("Color problem in %s",err); diff --git a/src/rrd_graph.h b/src/rrd_graph.h index 8fb96d6..3abb154 100644 --- a/src/rrd_graph.h +++ b/src/rrd_graph.h @@ -25,8 +25,6 @@ enum gf_en {GF_PRINT=0,GF_GPRINT,GF_COMMENT,GF_HRULE,GF_VRULE,GF_LINE, GF_DEF, GF_CDEF, GF_VDEF, GF_PART}; -enum if_en {IF_PNG=0,IF_SVG}; - enum vdef_op_en { VDEF_MAXIMUM /* like the MAX in (G)PRINT */ ,VDEF_MINIMUM /* like the MIN in (G)PRINT */ @@ -119,7 +117,6 @@ typedef struct image_desc_t { char graphfile[MAXPATH]; /* filename for graphic */ long xsize,ysize,piesize; /* graph area size in pixels */ - double zoom; /* zoom for graph */ gfx_color_t graph_col[__GRC_END__]; /* real colors for the graph */ text_prop_t text_prop[TEXT_PROP_LAST]; /* text properties */ char ylegend[200]; /* legend along the yaxis */ @@ -142,14 +139,12 @@ typedef struct image_desc_t { int lazy; /* only update the gif if there is reasonable probablility that the existing one is out of date */ int logarithmic; /* scale the yaxis logarithmic */ - enum if_en imgformat; /* image format */ /* status information */ long xorigin,yorigin;/* where is (0,0) of the graph */ long pie_x,pie_y; /* where is the centerpoint */ long xgif,ygif; /* total size of the gif */ - int interlaced; /* will the graph be interlaced? */ double magfact; /* numerical magnitude*/ long base; /* 1000 or 1024 depending on what we graph */ char symbol; /* magnitude symbol for y-axis */ @@ -160,14 +155,14 @@ typedef struct image_desc_t { long prt_c; /* number of print elements */ long gdes_c; /* number of graphics elements */ graph_desc_t *gdes; /* points to an array of graph elements */ - + gfx_canvas_t *canvas; /* graphics library */ } image_desc_t; /* Prototypes */ int xtr(image_desc_t *,time_t); int ytr(image_desc_t *, double); enum gf_en gf_conv(char *); -enum if_en if_conv(char *); +enum gfx_if_en if_conv(char *); enum tmt_en tmt_conv(char *); enum grc_en grc_conv(char *); enum grc_en text_prop_conv(char *); @@ -186,14 +181,14 @@ time_t find_first_time( time_t, enum tmt_en, long); time_t find_next_time( time_t, enum tmt_en, long); int print_calc(image_desc_t *, char ***); int leg_place(image_desc_t *); -int horizontal_grid(gfx_canvas_t *,image_desc_t *); -int horizontal_log_grid(gfx_canvas_t *, image_desc_t *); -void vertical_grid(gfx_canvas_t *, image_desc_t *); -void axis_paint( image_desc_t *, gfx_canvas_t *); -void grid_paint( image_desc_t *, gfx_canvas_t *); +int horizontal_grid(image_desc_t *); +int horizontal_log_grid(image_desc_t *); +void vertical_grid(image_desc_t *); +void axis_paint(image_desc_t *); +void grid_paint(image_desc_t *); int lazy_check(image_desc_t *); int graph_paint(image_desc_t *, char ***); -void pie_part(gfx_canvas_t *, gfx_color_t, double, double, double, double, double); +void pie_part(image_desc_t *, gfx_color_t, double, double, double, double, double); int gdes_alloc(image_desc_t *); int scan_for_col(char *, int, char *); int rrd_graph(int, char **, char ***, int *, int *); -- 2.30.2