fixed setlocale issues
[rrdtool.git] / src / rrd_graph.c
index 111aaa6..074ad44 100644 (file)
@@ -4,16 +4,24 @@
  * rrd__graph.c  make creates ne rrds
  ****************************************************************************/
 
-#if 0
-#include "rrd_tool.h"
-#endif
 
 #include <sys/stat.h>
+
+#include "rrd_tool.h"
+
 #ifdef WIN32
 #include <io.h>
 #include <fcntl.h>
 #endif
 
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#endif
+
 #include "rrd_graph.h"
 #include "rrd_graph_helper.h"
 
 
 
 #ifndef RRD_DEFAULT_FONT
+#ifdef WIN32
+#define RRD_DEFAULT_FONT "c:/winnt/fonts/COUR.TTF"
+#else
 #define RRD_DEFAULT_FONT "/usr/share/fonts/truetype/openoffice/ariosor.ttf" 
 /* #define RRD_DEFAULT_FONT "/usr/share/fonts/truetype/Arial.ttf" */
 #endif
+#endif
 
 
 text_prop_t text_prop[] = {   
@@ -119,7 +131,7 @@ xtr(image_desc_t *im,time_t mytime){
 }
 
 /* translate data values into y coordinates */
-int
+double
 ytr(image_desc_t *im, double value){
     static double pixie;
     double yval;
@@ -130,26 +142,25 @@ ytr(image_desc_t *im, double value){
        pixie = (double) im->ysize / (log10(im->maxval) - log10(im->minval));
       yval = im->yorigin;
     } else if(!im->logarithmic) {
-      yval = im->yorigin - pixie * (value - im->minval) + 0.5;
+      yval = im->yorigin - pixie * (value - im->minval);
     } else {
       if (value < im->minval) {
        yval = im->yorigin;
       } else {
-       yval = im->yorigin - pixie * (log10(value) - log10(im->minval)) + 0.5;
+       yval = im->yorigin - pixie * (log10(value) - log10(im->minval));
       }
     }
     /* make sure we don't return anything too unreasonable. GD lib can
        get terribly slow when drawing lines outside its scope. This is 
        especially problematic in connection with the rigid option */
     if (! im->rigid) {
-      return (int)yval;
-    } else if ((int)yval > im->yorigin) {
-      return im->yorigin+2;
-    } else if ((int) yval < im->yorigin - im->ysize){
-      return im->yorigin - im->ysize - 2;
-    } else {
-      return (int)yval;
+      /* keep yval as-is */
+    } else if (yval > im->yorigin) {
+      yval = im->yorigin+2;
+    } else if (yval < im->yorigin - im->ysize){
+      yval = im->yorigin - im->ysize - 2;
     } 
+    return yval;
 }
 
 
@@ -179,10 +190,12 @@ 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(GIF,IF_GIF)
     conv_if(PNG,IF_PNG)
+    conv_if(SVG,IF_SVG)
+    conv_if(EPS,IF_EPS)
+    conv_if(PDF,IF_PDF)
 
     return (-1);
 }
@@ -248,6 +261,7 @@ im_free(image_desc_t *im)
       free (im->gdes[i].rpnp);
     }
     free(im->gdes);
+    gfx_destroy(im->canvas);
     return 0;
 }
 
@@ -426,7 +440,73 @@ expand_range(image_desc_t *im)
 #endif
 }
 
-    
+void
+apply_gridfit(image_desc_t *im)
+{
+  if (isnan(im->minval) || isnan(im->maxval))
+    return;
+  ytr(im,DNAN);
+  if (im->logarithmic) {
+    double ya, yb, ypix, ypixfrac;
+    double log10_range = log10(im->maxval) - log10(im->minval);
+    ya = pow((double)10, floor(log10(im->minval)));
+    while (ya < im->minval)
+      ya *= 10;
+    if (ya > im->maxval)
+      return; /* don't have y=10^x gridline */
+    yb = ya * 10;
+    if (yb <= im->maxval) {
+      /* we have at least 2 y=10^x gridlines.
+        Make sure distance between them in pixels
+        are an integer by expanding im->maxval */
+      double y_pixel_delta = ytr(im, ya) - ytr(im, yb);
+      double factor = y_pixel_delta / floor(y_pixel_delta);
+      double new_log10_range = factor * log10_range;
+      double new_ymax_log10 = log10(im->minval) + new_log10_range;
+      im->maxval = pow(10, new_ymax_log10);
+      ytr(im, DNAN); /* reset precalc */
+      log10_range = log10(im->maxval) - log10(im->minval);
+    }
+    /* make sure first y=10^x gridline is located on 
+       integer pixel position by moving scale slightly 
+       downwards (sub-pixel movement) */
+    ypix = ytr(im, ya) + im->ysize; /* add im->ysize so it always is positive */
+    ypixfrac = ypix - floor(ypix);
+    if (ypixfrac > 0 && ypixfrac < 1) {
+      double yfrac = ypixfrac / im->ysize;
+      im->minval = pow(10, log10(im->minval) - yfrac * log10_range);
+      im->maxval = pow(10, log10(im->maxval) - yfrac * log10_range);
+      ytr(im, DNAN); /* reset precalc */
+    }
+  } else {
+    /* Make sure we have an integer pixel distance between
+       each minor gridline */
+    double ypos1 = ytr(im, im->minval);
+    double ypos2 = ytr(im, im->minval + im->ygrid_scale.gridstep);
+    double y_pixel_delta = ypos1 - ypos2;
+    double factor = y_pixel_delta / floor(y_pixel_delta);
+    double new_range = factor * (im->maxval - im->minval);
+    double gridstep = im->ygrid_scale.gridstep;
+    double minor_y, minor_y_px, minor_y_px_frac;
+    im->maxval = im->minval + new_range;
+    ytr(im, DNAN); /* reset precalc */
+    /* make sure first minor gridline is on integer pixel y coord */
+    minor_y = gridstep * floor(im->minval / gridstep);
+    while (minor_y < im->minval)
+      minor_y += gridstep;
+    minor_y_px = ytr(im, minor_y) + im->ysize; /* ensure > 0 by adding ysize */
+    minor_y_px_frac = minor_y_px - floor(minor_y_px);
+    if (minor_y_px_frac > 0 && minor_y_px_frac < 1) {
+      double yfrac = minor_y_px_frac / im->ysize;
+      double range = im->maxval - im->minval;
+      im->minval = im->minval - yfrac * range;
+      im->maxval = im->maxval - yfrac * range;
+      ytr(im, DNAN); /* reset precalc */
+    }
+    calc_horizontal_grid(im); /* recalc with changed im->maxval */
+  }
+}
+
 /* reduce data reimplementation by Alex */
 
 void
@@ -816,6 +896,17 @@ printf("DEBUG: value from vdef is %f\n",im->gdes[ptr].vf.val);
                    } /* if OP_VARIABLE */
                } /* loop through all rpi */
 
+                /* move the data pointers to the correct period */
+                for(rpi=0;im->gdes[gdi].rpnp[rpi].op != OP_END;rpi++){
+                    if(im->gdes[gdi].rpnp[rpi].op == OP_VARIABLE){
+                        long ptr = im->gdes[gdi].rpnp[rpi].ptr;
+                        if(im->gdes[gdi].start > im->gdes[ptr].start) {
+                            im->gdes[gdi].rpnp[rpi].data += im->gdes[gdi].rpnp[rpi].ds_cnt;
+                        }
+                     }
+                }
+        
+
                if(steparray == NULL){
                    rrd_set_error("rpn expressions without DEF"
                                " or CDEF variables are not supported");
@@ -1207,19 +1298,19 @@ print_calc(image_desc_t *im, char ***prdata)
            }
            }
            break;
-        case GF_COMMENT:
        case GF_LINE:
        case GF_AREA:
        case GF_TICK:
-       case GF_PART:
        case GF_STACK:
        case GF_HRULE:
        case GF_VRULE:
            graphelement = 1;
            break;
+        case GF_COMMENT:
        case GF_DEF:
        case GF_CDEF:       
        case GF_VDEF:       
+       case GF_PART:
            break;
        }
     }
@@ -1237,7 +1328,7 @@ leg_place(image_desc_t *im)
     int   border = im->text_prop[TEXT_PROP_LEGEND].size*2.0;
     int   fill=0, fill_last;
     int   leg_c = 0;
-    int   leg_x = border, leg_y = im->ygif;
+    int   leg_x = border, leg_y = im->yimg;
     int   leg_cc;
     int   glue = 0;
     int   i,ii, mark = 0;
@@ -1270,7 +1361,7 @@ leg_place(image_desc_t *im)
           leg_cc--;
           im->gdes[i].legend[leg_cc]='\0';
        }
-       if (leg_cc != 0 ){          
+       if (leg_cc != 0 ){
           legspace[i]=(prt_fctn=='g' ? 0 : interleg);
           
           if (fill > 0){ 
@@ -1281,7 +1372,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);
@@ -1297,7 +1389,7 @@ leg_place(image_desc_t *im)
            if (i == im->gdes_c -1 ) prt_fctn ='l';
            
            /* is it time to place the legends ? */
-           if (fill > im->xgif - 2*border){
+           if (fill > im->ximg - 2*border){
                if (leg_c > 1) {
                    /* go back one */
                    i--; 
@@ -1315,12 +1407,12 @@ leg_place(image_desc_t *im)
        if (prt_fctn != '\0'){
            leg_x = border;
            if (leg_c >= 2 && prt_fctn == 'j') {
-               glue = (im->xgif - fill - 2* border) / (leg_c-1);
+               glue = (im->ximg - fill - 2* border) / (leg_c-1);
            } else {
                glue = 0;
            }
-           if (prt_fctn =='c') leg_x =  (im->xgif - fill) / 2.0;
-           if (prt_fctn =='r') leg_x =  im->xgif - fill - border;
+           if (prt_fctn =='c') leg_x =  (im->ximg - fill) / 2.0;
+           if (prt_fctn =='r') leg_x =  im->ximg - fill - border;
 
            for(ii=mark;ii<=i;ii++){
                if(im->gdes[ii].legend[0]=='\0')
@@ -1328,7 +1420,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) 
@@ -1345,7 +1438,7 @@ leg_place(image_desc_t *im)
            mark = ii;
        }          
     }
-    im->ygif = leg_y+6;
+    im->yimg = leg_y;
     free(legspace);
   }
   return 0;
@@ -1360,21 +1453,15 @@ leg_place(image_desc_t *im)
 
 
 int
-horizontal_grid(gfx_canvas_t *canvas, image_desc_t   *im)
+calc_horizontal_grid(image_desc_t   *im)
 {
     double   range;
     double   scaledrange;
     int      pixel,i;
-    int      sgrid,egrid;
-    double   gridstep;
-    double   scaledstep;
-    char     graph_label[100];
-    double   x0,x1,y0,y1;
-    int      labfact,gridind;
+    int      gridind;
     int      decimals, fractionals;
-    char     labfmt[64];
 
-    labfact=2;
+    im->ygrid_scale.labfact=2;
     gridind=-1;
     range =  im->maxval - im->minval;
     scaledrange = range / im->magfact;
@@ -1396,25 +1483,25 @@ horizontal_grid(gfx_canvas_t *canvas, image_desc_t   *im)
            
            fractionals = floor(log10(range));
            if(fractionals < 0) /* small amplitude. */
-               sprintf(labfmt, "%%%d.%df", decimals - fractionals + 1, -fractionals + 1);
+               sprintf(im->ygrid_scale.labfmt, "%%%d.%df", decimals - fractionals + 1, -fractionals + 1);
            else
-               sprintf(labfmt, "%%%d.1f", decimals + 1);
-           gridstep = pow((double)10, (double)fractionals);
-           if(gridstep == 0) /* range is one -> 0.1 is reasonable scale */
-               gridstep = 0.1;
+               sprintf(im->ygrid_scale.labfmt, "%%%d.1f", decimals + 1);
+           im->ygrid_scale.gridstep = pow((double)10, (double)fractionals);
+           if(im->ygrid_scale.gridstep == 0) /* range is one -> 0.1 is reasonable scale */
+               im->ygrid_scale.gridstep = 0.1;
            /* should have at least 5 lines but no more then 15 */
-           if(range/gridstep < 5)
-                gridstep /= 10;
-           if(range/gridstep > 15)
-                gridstep *= 10;
-           if(range/gridstep > 5) {
-               labfact = 1;
-               if(range/gridstep > 8)
-                   labfact = 2;
+           if(range/im->ygrid_scale.gridstep < 5)
+                im->ygrid_scale.gridstep /= 10;
+           if(range/im->ygrid_scale.gridstep > 15)
+                im->ygrid_scale.gridstep *= 10;
+           if(range/im->ygrid_scale.gridstep > 5) {
+               im->ygrid_scale.labfact = 1;
+               if(range/im->ygrid_scale.gridstep > 8)
+                   im->ygrid_scale.labfact = 2;
            }
            else {
-               gridstep /= 5;
-               labfact = 5;
+               im->ygrid_scale.gridstep /= 5;
+               im->ygrid_scale.labfact = 5;
            }
        }
        else {
@@ -1428,33 +1515,40 @@ horizontal_grid(gfx_canvas_t *canvas, image_desc_t   *im)
            
            for(i=0; i<4;i++) {
               if (pixel * ylab[gridind].lfac[i] >=  2 * im->text_prop[TEXT_PROP_AXIS].size) {
-                 labfact =  ylab[gridind].lfac[i];
+                 im->ygrid_scale.labfact =  ylab[gridind].lfac[i];
                  break;
               }                          
            } 
            
-           gridstep = ylab[gridind].grid * im->magfact;
+           im->ygrid_scale.gridstep = ylab[gridind].grid * im->magfact;
        }
     } else {
-       gridstep = im->ygridstep;
-       labfact = im->ylabfact;
+       im->ygrid_scale.gridstep = im->ygridstep;
+       im->ygrid_scale.labfact = im->ylabfact;
     }
-    
-   x0=im->xorigin;
-   x1=im->xorigin+im->xsize;
+    return 1;
+}
+
+int draw_horizontal_grid(image_desc_t *im)
+{
+    int      i;
+    double   scaledstep;
+    char     graph_label[100];
+    double X0=im->xorigin;
+    double X1=im->xorigin+im->xsize;
    
-    sgrid = (int)( im->minval / gridstep - 1);
-    egrid = (int)( im->maxval / gridstep + 1);
-    scaledstep = gridstep/im->magfact;
+    int sgrid = (int)( im->minval / im->ygrid_scale.gridstep - 1);
+    int egrid = (int)( im->maxval / im->ygrid_scale.gridstep + 1);
+    scaledstep = im->ygrid_scale.gridstep/im->magfact;
     for (i = sgrid; i <= egrid; i++){
-       y0=ytr(im,gridstep*i);
-       if ( y0 >= im->yorigin-im->ysize
-                && y0 <= im->yorigin){       
-           if(i % labfact == 0){               
+       double Y0=ytr(im,im->ygrid_scale.gridstep*i);
+       if ( Y0 >= im->yorigin-im->ysize
+                && Y0 <= im->yorigin){       
+           if(i % im->ygrid_scale.labfact == 0){               
                if (i==0 || im->symbol == ' ') {
                    if(scaledstep < 1){
                        if(im->extra_flags & ALTYGRID) {
-                           sprintf(graph_label,labfmt,scaledstep*i);
+                           sprintf(graph_label,im->ygrid_scale.labfmt,scaledstep*i);
                        }
                        else {
                            sprintf(graph_label,"%4.1f",scaledstep*i);
@@ -1470,23 +1564,25 @@ horizontal_grid(gfx_canvas_t *canvas, image_desc_t   *im)
                    }
                }
 
-              gfx_new_text ( canvas,
-                             x0-im->text_prop[TEXT_PROP_AXIS].size/1.5, y0,
+              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,
-                             x0-2,y0,
-                             x1+2,y0,
-                             MGRIDWIDTH, im->graph_col[GRC_MGRID] );          
+              gfx_new_dashed_line ( im->canvas,
+                             X0-2,Y0,
+                             X1+2,Y0,
+                             MGRIDWIDTH, im->graph_col[GRC_MGRID],
+                             im->grid_dash_on, im->grid_dash_off);            
               
            } else {            
-              gfx_new_line ( canvas,
-                             x0-1,y0,
-                             x1+1,y0,
-                             GRIDWIDTH, im->graph_col[GRC_GRID] );            
+              gfx_new_dashed_line ( im->canvas,
+                             X0-1,Y0,
+                             X1+1,Y0,
+                             GRIDWIDTH, im->graph_col[GRC_GRID],
+                             im->grid_dash_on, im->grid_dash_off);            
               
            }       
        }       
@@ -1496,13 +1592,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 */
@@ -1525,8 +1621,8 @@ horizontal_log_grid(gfx_canvas_t *canvas, image_desc_t   *im)
        if(pixperstep > 2 *  im->text_prop[TEXT_PROP_LEGEND].size){majoridx = i;}
     }
    
-   x0=im->xorigin;
-   x1=im->xorigin+im->xsize;
+   X0=im->xorigin;
+   X1=im->xorigin+im->xsize;
     /* paint minor grid */
     for (value = pow((double)10, log10(im->minval) 
                          - fmod(log10(im->minval),log10(yloglab[minoridx][0])));
@@ -1535,12 +1631,13 @@ horizontal_log_grid(gfx_canvas_t *canvas, image_desc_t   *im)
        if (value < im->minval) continue;
        i=0;    
        while(yloglab[minoridx][++i] > 0){          
-          y0 = ytr(im,value * yloglab[minoridx][i]);
-          if (y0 <= im->yorigin - im->ysize) break;
-          gfx_new_line ( canvas,
-                         x0-1,y0,
-                         x1+1,y0,
-                         GRIDWIDTH, im->graph_col[GRC_GRID] );
+          Y0 = ytr(im,value * yloglab[minoridx][i]);
+          if (Y0 <= im->yorigin - im->ysize) break;
+          gfx_new_dashed_line ( im->canvas,
+                         X0-1,Y0,
+                         X1+1,Y0,
+                         GRIDWIDTH, im->graph_col[GRC_GRID],
+                         im->grid_dash_on, im->grid_dash_off);
        }
     }
 
@@ -1552,16 +1649,17 @@ horizontal_log_grid(gfx_canvas_t *canvas, image_desc_t   *im)
        if (value < im->minval) continue;
        i=0;    
        while(yloglab[majoridx][++i] > 0){          
-          y0 = ytr(im,value * yloglab[majoridx][i]);    
-          if (y0 <= im->yorigin - im->ysize) break;
-          gfx_new_line ( canvas,
-                         x0-2,y0,
-                         x1+2,y0,
-                         MGRIDWIDTH, im->graph_col[GRC_MGRID] );
+          Y0 = ytr(im,value * yloglab[majoridx][i]);    
+          if (Y0 <= im->yorigin - im->ysize) break;
+          gfx_new_dashed_line ( im->canvas,
+                         X0-2,Y0,
+                         X1+2,Y0,
+                         MGRIDWIDTH, im->graph_col[GRC_MGRID],
+                         im->grid_dash_on, im->grid_dash_off);
           
           sprintf(graph_label,"%3.0e",value * yloglab[majoridx][i]);
-          gfx_new_text ( canvas,
-                         x0-im->text_prop[TEXT_PROP_AXIS].size/1.5, y0,
+          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,
@@ -1575,14 +1673,13 @@ 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 ? */
-    time_t ti, tilab;
+    time_t ti, tilab, timajor;
     long factor;
     char graph_label[100];
-    double x0,y0,y1; /* points for filled graph and more*/
+    double X0,Y0,Y1; /* points for filled graph and more*/
    
 
     /* the type of time grid is determined by finding
@@ -1605,21 +1702,31 @@ vertical_grid(
     }
     
     /* y coords are the same for every line ... */
-    y0 = im->yorigin;
-    y1 = im->yorigin-im->ysize;
+    Y0 = im->yorigin;
+    Y1 = im->yorigin-im->ysize;
    
 
     /* paint the minor grid */
     for(ti = find_first_time(im->start,
                            im->xlab_user.gridtm,
-                           im->xlab_user.gridst);
+                           im->xlab_user.gridst),
+        timajor = find_first_time(im->start,
+                           im->xlab_user.mgridtm,
+                           im->xlab_user.mgridst);
        ti < im->end; 
        ti = find_next_time(ti,im->xlab_user.gridtm,im->xlab_user.gridst)
        ){
        /* 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]);
+       while (timajor < ti) {
+           timajor = find_next_time(timajor,
+                   im->xlab_user.mgridtm, im->xlab_user.mgridst);
+       }
+       if (ti == timajor) continue; /* skip as falls on major grid line */
+       X0 = xtr(im,ti);       
+       gfx_new_dashed_line(im->canvas,X0,Y0+1, X0,Y1-1,GRIDWIDTH,
+          im->graph_col[GRC_GRID],
+          im->grid_dash_on, im->grid_dash_off);
        
     }
 
@@ -1632,8 +1739,10 @@ 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]);
+       X0 = xtr(im,ti);
+       gfx_new_dashed_line(im->canvas,X0,Y0+3, X0,Y1-2,MGRIDWIDTH,
+          im->graph_col[GRC_MGRID],
+          im->grid_dash_on, im->grid_dash_off);
        
     }
     /* paint the labels below the graph */
@@ -1644,14 +1753,16 @@ vertical_grid(
        ti = find_next_time(ti,im->xlab_user.labtm,im->xlab_user.labst)
        ){
         tilab= ti + im->xlab_user.precis/2; /* correct time for the label */
+       /* are we inside the graph ? */
+       if (ti < im->start || ti > im->end) continue;
 
 #if HAVE_STRFTIME
        strftime(graph_label,99,im->xlab_user.stst,localtime(&tilab));
 #else
 # error "your libc has no strftime I guess we'll abort the exercise here."
 #endif
-       gfx_new_text ( canvas,
-                     xtr(im,tilab), y0+im->text_prop[TEXT_PROP_AXIS].size/1.5,
+       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,
                      im->text_prop[TEXT_PROP_AXIS].size,
@@ -1665,33 +1776,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]);
    
    
@@ -1699,47 +1809,46 @@ axis_paint(
 }
 
 void
-grid_paint(
-    image_desc_t   *im,
-    gfx_canvas_t   *canvas
-          
-    )
+grid_paint(image_desc_t   *im)
 {   
     long i;
-    int boxH=8, boxV=8;
     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, 0,0, im->xgif, 0,im->graph_col[GRC_SHADEA]);
-    gfx_add_point( node , im->xgif - 2, 2 );
-    gfx_add_point( node , 2,2 );
-    gfx_add_point( node , 2,im->ygif-2 );
-    gfx_add_point( node , 0,im->ygif );
+    node = gfx_new_area (im->canvas, 0,im->yimg,
+                                 2,im->yimg-2,
+                                 2,2,im->graph_col[GRC_SHADEA]);
+    gfx_add_point( node , im->ximg - 2, 2 );
+    gfx_add_point( node , im->ximg, 0 );
+    gfx_add_point( node , 0,0 );
+/*    gfx_add_point( node , 0,im->yimg ); */
    
-    node =  gfx_new_area (canvas, 0,im->ygif, im->xgif,im->ygif, im->xgif,0,im->graph_col[GRC_SHADEB]);
-    gfx_add_point( node , im->xgif - 2, 2 );
-    gfx_add_point( node , im->xgif-2,im->ygif-2 );
-    gfx_add_point( node , 2,im->ygif-2 );
-    gfx_add_point( node , 0,im->ygif );
+    node =  gfx_new_area (im->canvas, 2,im->yimg-2,
+                                  im->ximg-2,im->yimg-2,
+                                  im->ximg - 2, 2,
+                                 im->graph_col[GRC_SHADEB]);
+    gfx_add_point( node ,   im->ximg,0);
+    gfx_add_point( node ,   im->ximg,im->yimg);
+    gfx_add_point( node ,   0,im->yimg);
+/*    gfx_add_point( node , 0,im->yimg ); */
    
    
     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 = draw_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->ximg/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,
@@ -1749,68 +1858,85 @@ grid_paint(
     }
 
     /* yaxis description */
-    gfx_new_text( 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);
+       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 {
+           /* horrible hack until we can actually print vertically */
+           {
+               int n;
+               int l=strlen(im->ylegend);
+               char s[2];
+               for (n=0;n<strlen(im->ylegend);n++) {
+                   s[0]=im->ylegend[n];
+                   s[1]='\0';
+                   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,
+                       GFX_H_CENTER, GFX_V_CENTER,
+                       s);
+               }
+           }
+       }
    
     /* graph title */
-    gfx_new_text( canvas,
-                 im->xgif/2, im->text_prop[TEXT_PROP_TITLE].size*1.5,
+    gfx_new_text( im->canvas,
+                 im->ximg/2, im->text_prop[TEXT_PROP_TITLE].size,
                  im->graph_col[GRC_FONT],
                  im->text_prop[TEXT_PROP_TITLE].font,
                  im->text_prop[TEXT_PROP_TITLE].size, im->tabwidth, 0.0,
                  GFX_H_CENTER, GFX_V_CENTER,
                  im->title);
 
-   /* graph labels */
-   if( !(im->extra_flags & NOLEGEND) ) {
+    /* graph labels */
+    if( !(im->extra_flags & NOLEGEND) ) {
       for(i=0;i<im->gdes_c;i++){
-        if(im->gdes[i].legend[0] =='\0')
-          continue;
+       if(im->gdes[i].legend[0] =='\0')
+           continue;
         
-        if(im->gdes[i].gf != GF_GPRINT && im->gdes[i].gf != GF_COMMENT){
-           x0 = im->gdes[i].leg_x;
-           y0 = im->gdes[i].leg_y+1.0;
-           x1 = x0+boxH;
-           x2 = x0+boxH;
-           x3 = x0;
-           y1 = y0;
-           y2 = y0+boxV;
-           y3 = y0+boxV;
-           node = gfx_new_area(canvas, x0,y0,x1,y1,x2,y2 ,im->gdes[i].col);
-           gfx_add_point ( node, x3, y3 );
-           gfx_add_point ( node, x0, y0 );
-           node = gfx_new_line(canvas, x0,y0,x1,y1 ,GRIDWIDTH, im->graph_col[GRC_FRAME]);
-           gfx_add_point ( node, x2, y2 );
-           gfx_add_point ( node, x3, y3 );
-           gfx_add_point ( node, x0, y0 );
-           
-           gfx_new_text ( canvas, x0+boxH+6,  (y0+y2) / 2.0,
-                          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_LEFT, GFX_V_CENTER,
-                          im->gdes[i].legend );
-           
-        } else {
-           x0 = im->gdes[i].leg_x;
-           y0 = im->gdes[i].leg_y;
-               
-           gfx_new_text ( canvas, x0,  (y0+y2) / 2.0,
-                          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_LEFT, GFX_V_BOTTOM,
-                          im->gdes[i].legend );
-           
-        }
-      }
-   }
-}
+       /* im->gdes[i].leg_y is the bottom of the legend */
+               X0 = im->gdes[i].leg_x;
+               Y0 = im->gdes[i].leg_y;
+               /* Box needed? */
+               if (       im->gdes[i].gf != GF_GPRINT
+                       && im->gdes[i].gf != GF_COMMENT) {
+                   int boxH, boxV;
+
+                   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(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(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_close_path(node);
+                   X0 += boxH / 1.25 * 2;
+               }
+               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,
+                                  im->tabwidth,0.0, GFX_H_LEFT, GFX_V_BOTTOM,
+                                  im->gdes[i].legend );
+             }
+          }
+       }
 
 
 /*****************************************************
@@ -1820,32 +1946,31 @@ grid_paint(
 int lazy_check(image_desc_t *im){
     FILE *fd = NULL;
        int size = 1;
-    struct stat  gifstat;
+    struct stat  imgstat;
     
     if (im->lazy == 0) return 0; /* no lazy option */
-    if (stat(im->graphfile,&gifstat) != 0) 
+    if (stat(im->graphfile,&imgstat) != 0) 
       return 0; /* can't stat */
     /* one pixel in the existing graph is more then what we would
        change here ... */
-    if (time(NULL) - gifstat.st_mtime > 
+    if (time(NULL) - imgstat.st_mtime > 
        (im->end - im->start) / im->xsize) 
       return 0;
     if ((fd = fopen(im->graphfile,"rb")) == NULL) 
       return 0; /* the file does not exist */
-    switch (im->imgformat) {
-    case IF_GIF:
-          size = GifSize(fd,&(im->xgif),&(im->ygif));
-          break;
+    switch (im->canvas->imgformat) {
     case IF_PNG:
-          size = PngSize(fd,&(im->xgif),&(im->ygif));
+          size = PngSize(fd,&(im->ximg),&(im->yimg));
           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)
 {
@@ -1875,7 +2000,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,
@@ -1890,6 +2015,154 @@ pie_part(gfx_canvas_t *canvas, gfx_color_t color,
     }
 }
 
+int
+graph_size_location(image_desc_t *im, int elements, int piechart )
+{
+    /* The actual size of the image to draw is determined from
+    ** several sources.  The size given on the command line is
+    ** the graph area but we need more as we have to draw labels
+    ** and other things outside the graph area
+    */
+
+    /* +-+-------------------------------------------+
+    ** |l|.................title.....................|
+    ** |e+--+-------------------------------+--------+
+    ** |b| b|                               |        |
+    ** |a| a|                               |  pie   |
+    ** |l| l|          main graph area      | chart  |
+    ** |.| .|                               |  area  |
+    ** |t| y|                               |        |
+    ** |r+--+-------------------------------+--------+
+    ** |e|  | x-axis labels                 |        |
+    ** |v+--+-------------------------------+--------+
+    ** | |..............legends......................|
+    ** +-+-------------------------------------------+
+    */
+    int Xvertical=0,   Yvertical=0,
+       Xtitle   =0,    Ytitle   =0,
+       Xylabel  =0,    Yylabel  =0,
+       Xmain    =0,    Ymain    =0,
+       Xpie     =0,    Ypie     =0,
+       Xxlabel  =0,    Yxlabel  =0,
+#if 0
+       Xlegend  =0,    Ylegend  =0,
+#endif
+       Xspacing =10,   Yspacing =10;
+
+    if (im->ylegend[0] != '\0') {
+       Xvertical = im->text_prop[TEXT_PROP_LEGEND].size *2;
+       Yvertical = im->text_prop[TEXT_PROP_LEGEND].size * (strlen(im->ylegend)+1);
+    }
+
+    if (im->title[0] != '\0') {
+       /* The title is placed "inbetween" two text lines so it
+       ** automatically has some vertical spacing.  The horizontal
+       ** spacing is added here, on each side.
+       */
+       Xtitle = gfx_get_text_width(im->canvas, 0,
+               im->text_prop[TEXT_PROP_TITLE].font,
+               im->text_prop[TEXT_PROP_TITLE].size,
+               im->tabwidth,
+               im->title) + 2*Xspacing;
+       Ytitle = im->text_prop[TEXT_PROP_TITLE].size*2;
+    }
+
+    if (elements) {
+       Xmain=im->xsize;
+       Ymain=im->ysize;
+       if (im->draw_x_grid) {
+           Xxlabel=Xmain;
+           Yxlabel=im->text_prop[TEXT_PROP_LEGEND].size *2;
+       }
+       if (im->draw_y_grid) {
+           Xylabel=im->text_prop[TEXT_PROP_LEGEND].size *6;
+           Yylabel=Ymain;
+       }
+    }
+
+    if (piechart) {
+       im->piesize=im->xsize<im->ysize?im->xsize:im->ysize;
+       Xpie=im->piesize;
+       Ypie=im->piesize;
+    }
+
+    /* Now calculate the total size.  Insert some spacing where
+       desired.  im->xorigin and im->yorigin need to correspond
+       with the lower left corner of the main graph area or, if
+       this one is not set, the imaginary box surrounding the
+       pie chart area. */
+
+    /* The legend width cannot yet be determined, as a result we
+    ** have problems adjusting the image to it.  For now, we just
+    ** forget about it at all; the legend will have to fit in the
+    ** size already allocated.
+    */
+    im->ximg = Xylabel + Xmain + Xpie + Xspacing;
+    if (Xmain) im->ximg += Xspacing;
+    if (Xpie) im->ximg += Xspacing;
+    im->xorigin = Xspacing + Xylabel;
+    if (Xtitle > im->ximg) im->ximg = Xtitle;
+    if (Xvertical) {
+       im->ximg += Xvertical;
+       im->xorigin += Xvertical;
+    }
+    xtr(im,0);
+
+    /* The vertical size is interesting... we need to compare
+    ** the sum of {Ytitle, Ymain, Yxlabel, Ylegend} with Yvertical
+    ** however we need to know {Ytitle+Ymain+Yxlabel} in order to
+    ** start even thinking about Ylegend.
+    **
+    ** Do it in three portions: First calculate the inner part,
+    ** then do the legend, then adjust the total height of the img.
+    */
+
+    /* reserve space for main and/or pie */
+    im->yimg = Ymain + Yxlabel;
+    if (im->yimg < Ypie) im->yimg = Ypie;
+    im->yorigin = im->yimg - Yxlabel;
+    /* reserve space for the title *or* some padding above the graph */
+    if (Ytitle) {
+       im->yimg += Ytitle;
+       im->yorigin += Ytitle;
+    } else {
+       im->yimg += Yspacing;
+       im->yorigin += Yspacing;
+    }
+    /* reserve space for padding below the graph */
+    im->yimg += Yspacing;
+    ytr(im,DNAN);
+
+    /* Determine where to place the legends onto the image.
+    ** Adjust im->yimg to match the space requirements.
+    */
+    if(leg_place(im)==-1)
+       return -1;
+
+    /* last of three steps: check total height of image */
+    if (im->yimg < Yvertical) im->yimg = Yvertical;
+
+#if 0
+    if (Xlegend > im->ximg) {
+       im->ximg = Xlegend;
+       /* reposition Pie */
+#endif
+
+    /* The pie is placed in the upper right hand corner,
+    ** just below the title (if any) and with sufficient
+    ** padding.
+    */
+    if (elements) {
+       im->pie_x = im->ximg - Xspacing - Xpie/2;
+        im->pie_y = im->yorigin-Ymain+Ypie/2;
+    } else {
+       im->pie_x = im->ximg/2;
+        im->pie_y = im->yorigin-Ypie/2;
+    }
+
+    return 0;
+}
+
 /* draw that picture thing ... */
 int
 graph_paint(image_desc_t *im, char ***calcpr)
@@ -1897,9 +2170,8 @@ graph_paint(image_desc_t *im, char ***calcpr)
   int i,ii;
   int lazy =     lazy_check(im);
   int piechart = 0;
-  double PieStart=0.0, PieSize=0.0, PieCenterX=0.0, PieCenterY=0.0;
+  double PieStart=0.0;
   FILE  *fo;
-  gfx_canvas_t *canvas;
   gfx_node_t *node;
   
   double areazero = 0.0;
@@ -1918,6 +2190,14 @@ graph_paint(image_desc_t *im, char ***calcpr)
   if(data_calc(im)==-1)
     return -1;
   
+  /* check if we need to draw a piechart */
+  for(i=0;i<im->gdes_c;i++){
+    if (im->gdes[i].gf == GF_PART) {
+      piechart=1;
+      break;
+    }
+  }
+
   /* calculate and PRINT and GPRINT definitions. We have to do it at
    * this point because it will affect the length of the legends
    * if there are no graph elements we stop here ... 
@@ -1925,7 +2205,10 @@ graph_paint(image_desc_t *im, char ***calcpr)
    */
   i=print_calc(im,calcpr);
   if(i<0) return -1;
-  if(i==0 || lazy) return 0;
+  if(((i==0)&&(piechart==0)) || lazy) return 0;
+
+  /* If there's only the pie chart to draw, signal this */
+  if (i==0) piechart=2;
   
   /* get actual drawing data and find min and max values*/
   if(data_proc(im)==-1)
@@ -1936,144 +2219,51 @@ graph_paint(image_desc_t *im, char ***calcpr)
   if(!im->rigid && ! im->logarithmic)
     expand_range(im);   /* make sure the upper and lower limit are
                            sensible values */
-  
-  /* init xtr and ytr */
-  /* determine the actual size of the gif to draw. The size given
-     on the cmdline is the graph area. But we need more as we have
-     draw labels and other things outside the graph area */
-  
-  
-  im->xorigin = 10 + 9 *  im->text_prop[TEXT_PROP_LEGEND].size;
-
-  xtr(im,0); 
-  
-  im->yorigin = 10 + im->ysize;
-
-  ytr(im,DNAN);
-  
-  if(im->title[0] != '\0')
-    im->yorigin += im->text_prop[TEXT_PROP_TITLE].size*3+4;
-  
-  im->xgif= 20 +im->xsize + im->xorigin;
-  im->ygif= im->yorigin+2* im->text_prop[TEXT_PROP_LEGEND].size;
-
-  /* check if we need to draw a piechart */
-  for(i=0;i<im->gdes_c;i++){
-    if (im->gdes[i].gf == GF_PART) {
-      piechart=1;
-      break;
-    }
-  }
-
-  if (piechart) {
-       /* allocate enough space for the piechart itself (PieSize), 20%
-       ** more for the background and an additional 50 pixels spacing.
-       */
-    if (im->xsize < im->ysize)
-       PieSize = im->xsize;
-    else
-       PieSize = im->ysize;
-    im->xgif += PieSize*1.2 + 50;
-
-    PieCenterX = im->xorigin + im->xsize + 50 + PieSize*0.6;
-    PieCenterY = im->yorigin - PieSize*0.5;
-  }
 
-  /* determine where to place the legends onto the graphics.
-     and set im->ygif to match space requirements for text */
-  if(leg_place(im)==-1)
+  if (!calc_horizontal_grid(im))
+    return -1;
+  if (im->gridfit)
+    apply_gridfit(im);
+
+/**************************************************************
+ *** Calculating sizes and locations became a bit confusing ***
+ *** so I moved this into a separate function.              ***
+ **************************************************************/
+  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,
+                      im->ximg, 0,
+                      im->ximg, im->yimg,
                       im->graph_col[GRC_BACK]);
 
-  gfx_add_point(node,0, im->ygif);
+  gfx_add_point(node,0, im->yimg);
 
-  node=gfx_new_area ( canvas,
+  if (piechart != 2) {
+    node=gfx_new_area ( im->canvas,
                       im->xorigin,             im->yorigin, 
                       im->xorigin + im->xsize, im->yorigin,
                       im->xorigin + im->xsize, im->yorigin-im->ysize,
                       im->graph_col[GRC_CANVAS]);
   
-  gfx_add_point(node,im->xorigin, im->yorigin - im->ysize);
+    gfx_add_point(node,im->xorigin, im->yorigin - im->ysize);
 
-#if 0
-/******************************************************************
- ** Just to play around.  If you see this, I forgot to remove it **
- ******************************************************************/
-  im->ygif+=100;
-  node=gfx_new_area(canvas,
-                       0,              im->ygif-100,
-                       im->xgif,       im->ygif-100,
-                       im->xgif,       im->ygif,
-                       im->graph_col[GRC_CANVAS]);
-  gfx_add_point(node,0,im->ygif);
-
-  /* Four areas:
-  ** top left:     current way, solid color
-  ** top right:    proper way,  solid color
-  ** bottom left:  current way, alpha=0x80, partially overlapping
-  ** bottom right: proper way,  alpha=0x80, partially overlapping
-  */
-  {
-    double x,y,x1,y1,x2,y2,x3,y3,x4,y4;
-
-    x=(im->xgif-40)/6;
-    y=     (100-40)/6;
-    x1=    20;   y1=im->ygif-100+20;
-    x2=3*x+20;   y2=im->ygif-100+20;
-    x3=  x+20;   y3=im->ygif-100+20+2*y;
-    x4=4*x+20;   y4=im->ygif-100+20+2*y;
-
-    node=gfx_new_area(canvas,
-                       x1,y1,
-                       x1+3*x,y1,
-                       x1+3*x,y1+3*y,
-                       0xFF0000FF);
-    gfx_add_point(node,x1,y1+3*y);
-    node=gfx_new_area(canvas,
-                       x2,y2,
-                       x2,y2+3*y,
-                       x2+3*x,y2+3*y,
-                       0xFFFF00FF);
-    gfx_add_point(node,x2+3*x,y2);
-    node=gfx_new_area(canvas,
-                       x3,y3,
-                       x3+2*x,y3,
-                       x3+2*x,y3+3*y,
-                       0x00FF007F);
-    gfx_add_point(node,x3,y3+3*y);
-    node=gfx_new_area(canvas,
-                       x4,y4,
-                       x4,y4+3*y,
-                       x4+2*x,y4+3*y,
-                       0x0000FF7F);
-    gfx_add_point(node,x4+2*x,y4);
+    if (im->minval > 0.0)
+      areazero = im->minval;
+    if (im->maxval < 0.0)
+      areazero = im->maxval;
+  
+    axis_paint(im);
   }
-                       
-#endif
 
   if (piechart) {
-    pie_part(canvas,im->graph_col[GRC_CANVAS],PieCenterX,PieCenterY,PieSize*0.6,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);
   }
 
-  if (im->minval > 0.0)
-    areazero = im->minval;
-  if (im->maxval < 0.0)
-    areazero = im->maxval;
-  
-  axis_paint(im,canvas);
-
-
   for(i=0;i<im->gdes_c;i++){
     switch(im->gdes[i].gf){
     case GF_CDEF:
@@ -2092,7 +2282,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,
@@ -2125,7 +2315,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,
@@ -2152,7 +2342,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]),
@@ -2198,8 +2388,8 @@ 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,
-               PieCenterX,PieCenterY,PieSize/2,
+       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);
        PieStart += im->gdes[i].yrule;
@@ -2207,7 +2397,12 @@ graph_paint(image_desc_t *im, char ***calcpr)
       break;
     } /* switch */
   }
-  grid_paint(im,canvas);
+  if (piechart==2) {
+    im->draw_x_grid=0;
+    im->draw_y_grid=0;
+  }
+  /* grid_paint also does the text */
+  grid_paint(im);
   
   /* the RULES are the last thing to paint ... */
   for(i=0;i<im->gdes_c;i++){    
@@ -2219,7 +2414,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); 
@@ -2230,7 +2425,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); 
@@ -2254,17 +2449,9 @@ graph_paint(image_desc_t *im, char ***calcpr)
       return (-1);
     }
   }
-  switch (im->imgformat) {
-  case IF_GIF:
-    break;
-  case IF_PNG:
-    gfx_render_png (canvas,im->xgif,im->ygif,im->zoom,0x0,fo);
-    break;
-  }
+  gfx_render (im->canvas,im->ximg,im->yimg,0x0,fo);
   if (strcmp(im->graphfile,"-") != 0)
     fclose(fo);
-   
-  gfx_destroy(canvas);
   return 0;
 }
 
@@ -2343,6 +2530,14 @@ rrd_graph(int argc, char **argv, char ***prdata, int *xsize, int *ysize)
 {
     image_desc_t   im;
 
+#ifdef HAVE_TZSET
+    tzset();
+#endif
+#ifdef HAVE_SETLOCALE
+    setlocale(LC_TIME,"");
+#endif
+            
+            
     rrd_graph_init(&im);
 
     rrd_graph_options(argc,argv,&im);
@@ -2370,8 +2565,8 @@ rrd_graph(int argc, char **argv, char ***prdata, int *xsize, int *ysize)
     ** Also, if needed, print a line with information about the image.
     */
 
-    *xsize=im.xgif;
-    *ysize=im.ygif;
+    *xsize=im.ximg;
+    *ysize=im.yimg;
     if (im.imginfo) {
        char *filename;
        if (!(*prdata)) {
@@ -2392,7 +2587,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.ximg),(long)(im.canvas->zoom*im.yimg));
     }
     im_free(&im);
     return 0;
@@ -2404,8 +2599,8 @@ rrd_graph_init(image_desc_t *im)
     int i;
 
     im->xlab_user.minsec = -1;
-    im->xgif=0;
-    im->ygif=0;
+    im->ximg=0;
+    im->yimg=0;
     im->xsize = 400;
     im->ysize = 100;
     im->step = 0;
@@ -2413,10 +2608,10 @@ 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;
+    im->gridfit = 1;
     im->imginfo = NULL;
     im->lazy = 0;
     im->logarithmic = 0;
@@ -2427,8 +2622,9 @@ 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_GIF; /* we default to GIF output */
+    im->canvas = gfx_new_canvas();
+    im->grid_dash_on = 1;
+    im->grid_dash_off = 1;
 
     for(i=0;i<DIM(graph_col);i++)
         im->graph_col[i]=graph_col[i];
@@ -2482,6 +2678,7 @@ rrd_graph_options(int argc, char *argv[],image_desc_t *im)
            {"alt-autoscale-max", no_argument,    0,   259 },
            {"units-exponent",required_argument, 0,  260},
            {"step",       required_argument, 0,   261},
+           {"no-gridfit", no_argument,       0,   262},
            {0,0,0,0}};
        int option_index = 0;
        int opt;
@@ -2513,6 +2710,9 @@ rrd_graph_options(int argc, char *argv[],image_desc_t *im)
        case 261:
            im->step =  atoi(optarg);
            break;
+       case 262:
+           im->gridfit = 0;
+           break;
        case 's':
            if ((parsetime_error = parsetime(optarg, &start_tv))) {
                rrd_set_error( "start time: %s", parsetime_error );
@@ -2616,7 +2816,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;
@@ -2625,7 +2825,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;
            }
@@ -2640,7 +2840,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){
@@ -2650,7 +2850,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':{
@@ -2695,8 +2895,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;
            }
@@ -3007,12 +3207,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);