X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Frrd_graph.c;h=2d1785f40d8102f829aa8204dd7a82bb985812c7;hb=c5200a11ec773ecc9bc2d30ffadd0af4a2317741;hp=4af6f82a3f97307f47aac6ec7aa14515312879c2;hpb=dd0cc409db510efe7cde8d7f0df6ec370be16c60;p=rrdtool.git diff --git a/src/rrd_graph.c b/src/rrd_graph.c index 4af6f82..2d1785f 100644 --- a/src/rrd_graph.c +++ b/src/rrd_graph.c @@ -235,6 +235,7 @@ enum gf_en gf_conv( conv_if(AREA, GF_AREA); conv_if(STACK, GF_STACK); conv_if(TICK, GF_TICK); + conv_if(TEXTALIGN, GF_TEXTALIGN); conv_if(DEF, GF_DEF); conv_if(CDEF, GF_CDEF); conv_if(VDEF, GF_VDEF); @@ -327,16 +328,16 @@ int im_free( free(im->gdes); if (im->font_options) cairo_font_options_destroy(im->font_options); - - status = cairo_status (im->cr); + + status = cairo_status(im->cr); if (im->cr) cairo_destroy(im->cr); if (im->surface) cairo_surface_destroy(im->surface); if (status) - fprintf(stderr,"OOPS: Cairo has issuesm it can't even die: %s\n", - cairo_status_to_string (status)); + fprintf(stderr, "OOPS: Cairo has issuesm it can't even die: %s\n", + cairo_status_to_string(status)); return 0; } @@ -1542,6 +1543,7 @@ int print_calc( graphelement = 1; break; case GF_COMMENT: + case GF_TEXTALIGN: case GF_DEF: case GF_CDEF: case GF_VDEF: @@ -1578,6 +1580,7 @@ int leg_place( int glue = 0; int i, ii, mark = 0; char prt_fctn; /*special printfunctions */ + char default_txtalign = TXA_JUSTIFIED; /*default line orientation */ int *legspace; if (!(im->extra_flags & NOLEGEND) & !(im->extra_flags & ONLY_GRAPH)) { @@ -1595,6 +1598,10 @@ int leg_place( /* hide legends for rules which are not displayed */ + if (im->gdes[i].gf == GF_TEXTALIGN) { + default_txtalign = im->gdes[i].txtalign; + } + if (!(im->extra_flags & FORCE_RULES_LEGEND)) { if (im->gdes[i].gf == GF_HRULE && (im->gdes[i].yrule < im->minval @@ -1632,22 +1639,24 @@ int leg_place( return -1; } - - /* remove exess space */ + /* \n -> \l */ if (prt_fctn == 'n') { prt_fctn = 'l'; } + /* remove exess space from the end of the legend for \g */ while (prt_fctn == 'g' && leg_cc > 0 && im->gdes[i].legend[leg_cc - 1] == ' ') { leg_cc--; im->gdes[i].legend[leg_cc] = '\0'; } + if (leg_cc != 0) { + + /* no interleg space if string ends in \g */ legspace[i] = (prt_fctn == 'g' ? 0 : interleg); if (fill > 0) { - /* no interleg space if string ends in \g */ fill += legspace[i]; } fill += gfx_get_text_width(im, fill + border, @@ -1664,10 +1673,25 @@ int leg_place( if (prt_fctn == 'g') { prt_fctn = '\0'; } - if (prt_fctn == '\0') { - if (i == im->gdes_c - 1) - prt_fctn = 'l'; + if (prt_fctn == '\0') { + if (i == im->gdes_c - 1 || fill > im->ximg - 2 * border) { + /* just one legend item is left right or center */ + switch (default_txtalign) { + case TXA_RIGHT: + prt_fctn = 'r'; + break; + case TXA_CENTER: + prt_fctn = 'c'; + break; + case TXA_JUSTIFIED: + prt_fctn = 'j'; + break; + default: + prt_fctn = 'l'; + break; + } + } /* is it time to place the legends ? */ if (fill > im->ximg - 2 * border) { if (leg_c > 1) { @@ -1675,11 +1699,10 @@ int leg_place( i--; fill = fill_last; leg_c--; - prt_fctn = 'j'; - } else { - prt_fctn = 'l'; } - + } + if (leg_c == 1 && prt_fctn == 'j') { + prt_fctn = 'l'; } } @@ -1971,6 +1994,10 @@ double frexp10( return mnt; } +/* from http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm */ +/* yes we are loosing precision by doing tos with floats instead of doubles + but it seems more stable this way. */ + static int AlmostEqual2sComplement( float A, float B, @@ -2406,11 +2433,12 @@ void axis_paint( /* arrow for X and Y axis direction */ - gfx_new_area(im, im->xorigin + im->xsize + 2, im->yorigin - 2, im->xorigin + im->xsize + 2, im->yorigin + 3, im->xorigin + im->xsize + 7, im->yorigin + 0.5, /* LINEOFFSET */ + + gfx_new_area(im, im->xorigin + im->xsize + 2, im->yorigin - 3, im->xorigin + im->xsize + 2, im->yorigin + 3, im->xorigin + im->xsize + 7, im->yorigin, /* horyzontal */ im->graph_col[GRC_ARROW]); gfx_close_path(im); - gfx_new_area(im, im->xorigin - 2, im->yorigin - im->ysize - 2, im->xorigin + 3, im->yorigin - im->ysize - 2, im->xorigin + 0.5, im->yorigin - im->ysize - 7, /* LINEOFFSET */ + gfx_new_area(im, im->xorigin - 3, im->yorigin - im->ysize - 2, im->xorigin + 3, im->yorigin - im->ysize - 2, im->xorigin, im->yorigin - im->ysize - 7, /* vertical */ im->graph_col[GRC_ARROW]); gfx_close_path(im); @@ -2843,11 +2871,38 @@ int graph_size_location( return 0; } -/* from http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm */ -/* yes we are loosing precision by doing tos with floats instead of doubles - but it seems more stable this way. */ +static cairo_status_t cairo_write_func_filehandle( + void *closure, + const unsigned char *data, + unsigned int length) +{ + if (fwrite(data, length, 1, closure) != 1) + return CAIRO_STATUS_WRITE_ERROR; + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t cairo_copy_to_buffer( + void *closure, + const unsigned char *data, + unsigned int length) +{ + image_desc_t *im = closure; + + im->rendered_image = + realloc(im->rendered_image, im->rendered_image_size + length); + if (im->rendered_image == NULL) { + return CAIRO_STATUS_WRITE_ERROR; + } + + memcpy(im->rendered_image + im->rendered_image_size, data, length); + + im->rendered_image_size += length; + + return CAIRO_STATUS_SUCCESS; +} + /* draw that picture thing ... */ int graph_paint( image_desc_t *im, @@ -2928,19 +2983,31 @@ int graph_paint( im->yimg * im->zoom); break; case IF_PDF: - im->surface = - cairo_pdf_surface_create(im->graphfile, im->ximg * im->zoom, - im->yimg * im->zoom); + im->gridfit = 0; + im->surface = strlen(im->graphfile) + ? cairo_pdf_surface_create(im->graphfile, im->ximg * im->zoom, + im->yimg * im->zoom) + : cairo_pdf_surface_create_for_stream(&cairo_copy_to_buffer, im, + im->ximg * im->zoom, + im->yimg * im->zoom); break; case IF_EPS: - im->surface = - cairo_ps_surface_create(im->graphfile, im->ximg * im->zoom, - im->yimg * im->zoom); + im->gridfit = 0; + im->surface = strlen(im->graphfile) + ? cairo_ps_surface_create(im->graphfile, im->ximg * im->zoom, + im->yimg * im->zoom) + : cairo_ps_surface_create_for_stream(&cairo_copy_to_buffer, im, + im->ximg * im->zoom, + im->yimg * im->zoom); break; case IF_SVG: - im->surface = - cairo_svg_surface_create(im->graphfile, im->ximg * im->zoom, - im->yimg * im->zoom); + im->gridfit = 0; + im->surface = strlen(im->graphfile) + ? cairo_svg_surface_create(im->graphfile, im->ximg * im->zoom, + im->yimg * im->zoom) + : cairo_svg_surface_create_for_stream(&cairo_copy_to_buffer, im, + im->ximg * im->zoom, + im->yimg * im->zoom); cairo_svg_surface_restrict_to_version(im->surface, CAIRO_SVG_VERSION_1_1); break; @@ -2979,6 +3046,7 @@ int graph_paint( case GF_PRINT: case GF_GPRINT: case GF_COMMENT: + case GF_TEXTALIGN: case GF_HRULE: case GF_VRULE: case GF_XPORT: @@ -3272,14 +3340,34 @@ int graph_paint( switch (im->imgformat) { case IF_PNG: - if (cairo_surface_write_to_png(im->surface, im->graphfile) != - CAIRO_STATUS_SUCCESS) { + { + cairo_status_t status; + + if (strlen(im->graphfile) == 0) { + status = + cairo_surface_write_to_png_stream(im->surface, + &cairo_copy_to_buffer, im); + } else if (strcmp(im->graphfile, "-") == 0) { + status = + cairo_surface_write_to_png_stream(im->surface, + &cairo_write_func_filehandle, + (void *) stdout); + } else { + status = cairo_surface_write_to_png(im->surface, im->graphfile); + } + + if (status != CAIRO_STATUS_SUCCESS) { rrd_set_error("Could not save png to '%s'", im->graphfile); return 1; } + } break; default: - cairo_show_page(im->cr); + if (strlen(im->graphfile)) { + cairo_show_page(im->cr); + } else { + cairo_surface_finish(im->surface); + } break; } return 0; @@ -3381,9 +3469,6 @@ int rrd_graph( /* a dummy surface so that we can measure text sizes for placements */ im.surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 10, 10); im.cr = cairo_create(im.surface); - - - /* not currently using this ... */ im.graphhandle = stream; rrd_graph_options(argc, argv, &im); @@ -3392,11 +3477,17 @@ int rrd_graph( return -1; } + if (optind >= argc) { + rrd_set_error("missing filename"); + return -1; + } + if (strlen(argv[optind]) >= MAXPATH) { rrd_set_error("filename (including path) too long"); im_free(&im); return -1; } + strncpy(im.graphfile, argv[optind], MAXPATH - 1); im.graphfile[MAXPATH - 1] = '\0'; @@ -3453,6 +3544,60 @@ int rrd_graph( return 0; } +/* a simplified version of the above that just creates the graph in memory + and returns a pointer to it. */ + +unsigned char *rrd_graph_in_memory( + int argc, + char **argv, + char ***prdata, + int *xsize, + int *ysize, + double *ymin, + double *ymax, + size_t * img_size) +{ + image_desc_t im; + + rrd_graph_init(&im); + + /* a dummy surface so that we can measure text sizes for placements */ + im.surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 10, 10); + im.cr = cairo_create(im.surface); + + rrd_graph_options(argc, argv, &im); + if (rrd_test_error()) { + im_free(&im); + return NULL; + } + + rrd_graph_script(argc, argv, &im, 1); + if (rrd_test_error()) { + im_free(&im); + return NULL; + } + + /* Everything is now read and the actual work can start */ + + /* by not assigning a name to im.graphfile data will be written to + newly allocated memory on im.rendered_image ... */ + + (*prdata) = NULL; + if (graph_paint(&im, prdata) == -1) { + im_free(&im); + return NULL; + } + + *xsize = im.ximg; + *ysize = im.yimg; + *ymin = im.minval; + *ymax = im.maxval; + *img_size = im.rendered_image_size; + im_free(&im); + + return im.rendered_image; +} + void rrd_graph_init( image_desc_t *im) { @@ -3475,6 +3620,8 @@ void rrd_graph_init( im->yimg = 0; im->xsize = 400; im->ysize = 100; + im->rendered_image_size = 0; + im->rendered_image = NULL; im->step = 0; im->ylegend[0] = '\0'; im->title[0] = '\0'; @@ -3487,6 +3634,7 @@ void rrd_graph_init( im->symbol = ' '; im->viewfactor = 1.0; im->imgformat = IF_PNG; + im->graphfile[0] = '\0'; im->cr = NULL; im->surface = NULL; im->extra_flags = 0; @@ -3952,11 +4100,6 @@ void rrd_graph_options( } } - if (optind >= argc) { - rrd_set_error("missing filename"); - return; - } - if (im->logarithmic == 1 && im->minval <= 0) { rrd_set_error ("for a logarithmic yaxis you must specify a lower-limit > 0");