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;
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;
}
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;
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;
}
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,
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;
/* 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){
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);
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 );
}
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++) {
}
+/* ------- 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;
}
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)
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)
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);
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);
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 <path..> tags take less space than
<line..> 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 */
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;
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++;
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);
*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;
}
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) {
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;
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(
- "<?xml version=\"1.0\" standalone=\"yes\"?>\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 RRDtool,\n"
- " Tobias Oetiker <tobi@oetike.ch>, 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);
+"<?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 RRDtool,\n"
+" Tobias Oetiker <tobi@oetike.ch>, 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 * 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);
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) {
}
svg_end_tag(fp, "svg");
return 0;
- }
+}
#define LIBART_COMPILATION
#include <libart.h>
+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 };
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;
{
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;
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,
/* 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,
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);
/* 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 */
/* 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);
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);
}
free (im->gdes[i].rpnp);
}
free(im->gdes);
+ gfx_destroy(im->canvas);
return 0;
}
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);
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)
int
-horizontal_grid(gfx_canvas_t *canvas, image_desc_t *im)
+horizontal_grid(image_desc_t *im)
{
double range;
double scaledrange;
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];
}
}
- 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] );
/* 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 */
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] );
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,
void
vertical_grid(
- gfx_canvas_t *canvas,
image_desc_t *im )
{
int xlab_sel; /* which sort of label and 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]);
}
/* 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 */
#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,
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]);
}
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 );
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]);
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,
}
/* 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;
for (n=0;n<strlen(im->ylegend);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,
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,
&& 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,
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)
{
Radius *= 0.8;
}
- node=gfx_new_area(canvas,
+ node=gfx_new_area(im->canvas,
PieCenterX+sin(startangle)*Radius,
PieCenterY-cos(startangle)*Radius,
PieCenterX,
** 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,
int piechart = 0;
double PieStart=0.0;
FILE *fo;
- gfx_canvas_t *canvas;
gfx_node_t *node;
double areazero = 0.0;
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,
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,
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;i<im->gdes_c;i++){
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,
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,
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]),
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);
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;i<im->gdes_c;i++){
};
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);
};
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);
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;
}
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;
im->title[0] = '\0';
im->minval = DNAN;
im->maxval = DNAN;
- im->interlaced = 0;
im->unitsexponent= 9999;
im->extra_flags= 0;
im->rigid = 0;
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;i<DIM(graph_col);i++)
im->graph_col[i]=graph_col[i];
im->ysize = long_tmp;
break;
case 'i':
- im->interlaced = 1;
+ im->canvas->interlaced = 1;
break;
case 'r':
im->rigid = 1;
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;
}
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){
}
} else {
rrd_set_error("invalid color def format");
- return -1;
+ return;
}
break;
case 'n':{
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;
}
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);
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 */
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 */
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 */
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 *);
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 *);