switch for rrd_graph to specify the outer-size of the graph and not just the
[rrdtool.git] / src / rrd_graph.c
index 5154210..2aba6f9 100644 (file)
@@ -164,7 +164,7 @@ gfx_color_t graph_col[] =   /* default colors */
 
 /* initialize with xtr(im,0); */
 int xtr(
-    image_desc_t * im,
+    image_desc_t *im,
     time_t mytime)
 {
     static double pixie;
@@ -178,7 +178,7 @@ int xtr(
 
 /* translate data values into y coordinates */
 double ytr(
-    image_desc_t * im,
+    image_desc_t *im,
     double value)
 {
     static double pixie;
@@ -306,7 +306,7 @@ enum text_prop_en text_prop_conv(
 #undef conv_if
 
 int im_free(
-    image_desc_t * im)
+    image_desc_t *im)
 {
     unsigned long i, ii;
 
@@ -332,7 +332,7 @@ int im_free(
 
 /* find SI magnitude symbol for the given number*/
 void auto_scale(
-    image_desc_t * im,  /* image description */
+    image_desc_t *im,   /* image description */
     double *value,
     char **symb_ptr,
     double *magfact)
@@ -391,7 +391,7 @@ static const int si_symbcenter = 6;
 
 /* find SI magnitude symbol for the numbers on the y-axis*/
 void si_unit(
-    image_desc_t * im   /* image description */
+    image_desc_t *im    /* image description */
     )
 {
 
@@ -426,7 +426,7 @@ void si_unit(
 /*  move min and max values around to become sensible */
 
 void expand_range(
-    image_desc_t * im)
+    image_desc_t *im)
 {
     double    sensiblevalues[] = { 1000.0, 900.0, 800.0, 750.0, 700.0,
         600.0, 500.0, 400.0, 300.0, 250.0,
@@ -521,7 +521,7 @@ void expand_range(
 }
 
 void apply_gridfit(
-    image_desc_t * im)
+    image_desc_t *im)
 {
     if (isnan(im->minval) || isnan(im->maxval))
         return;
@@ -604,7 +604,7 @@ void reduce_data(
     time_t *end,        /* ... by the application will be   ... */
     unsigned long *step,    /* ... adjusted to represent reality    */
     unsigned long *ds_cnt,  /* number of data sources in file */
-    rrd_value_t ** data)
+    rrd_value_t **data)
 {                       /* two dimensional array containing the data */
     int       i, reduce_factor = ceil((double) (*step) / (double) cur_step);
     unsigned long col, dst_row, row_cnt, start_offset, end_offset, skiprows =
@@ -772,7 +772,7 @@ void reduce_data(
    relevant rrds ... */
 
 int data_fetch(
-    image_desc_t * im)
+    image_desc_t *im)
 {
     int       i, ii;
     int       skip;
@@ -867,7 +867,7 @@ long find_var_wrapper(
 
 /* find gdes containing var*/
 long find_var(
-    image_desc_t * im,
+    image_desc_t *im,
     char *key)
 {
     long      ii;
@@ -904,7 +904,7 @@ long lcd(
 
 /* run the rpn calculator on all the VDEF and CDEF arguments */
 int data_calc(
-    image_desc_t * im)
+    image_desc_t *im)
 {
 
     int       gdi;
@@ -1102,7 +1102,7 @@ int data_calc(
 
 /* massage data so, that we get one value for each x coordinate in the graph */
 int data_proc(
-    image_desc_t * im)
+    image_desc_t *im)
 {
     long      i, ii;
     double    pixstep = (double) (im->end - im->start)
@@ -1261,49 +1261,58 @@ time_t find_first_time(
     struct tm tm;
 
     localtime_r(&start, &tm);
+
     switch (baseint) {
     case TMT_SECOND:
-        tm.tm_sec -= tm.tm_sec % basestep;
+        tm.       tm_sec -= tm.tm_sec % basestep;
+
         break;
     case TMT_MINUTE:
-        tm.tm_sec = 0;
-        tm.tm_min -= tm.tm_min % basestep;
+        tm.       tm_sec = 0;
+        tm.       tm_min -= tm.tm_min % basestep;
+
         break;
     case TMT_HOUR:
-        tm.tm_sec = 0;
-        tm.tm_min = 0;
-        tm.tm_hour -= tm.tm_hour % basestep;
+        tm.       tm_sec = 0;
+        tm.       tm_min = 0;
+        tm.       tm_hour -= tm.tm_hour % basestep;
+
         break;
     case TMT_DAY:
         /* we do NOT look at the basestep for this ... */
-        tm.tm_sec = 0;
-        tm.tm_min = 0;
-        tm.tm_hour = 0;
+        tm.       tm_sec = 0;
+        tm.       tm_min = 0;
+        tm.       tm_hour = 0;
+
         break;
     case TMT_WEEK:
         /* we do NOT look at the basestep for this ... */
-        tm.tm_sec = 0;
-        tm.tm_min = 0;
-        tm.tm_hour = 0;
-        tm.tm_mday -= tm.tm_wday - 1;   /* -1 because we want the monday */
+        tm.       tm_sec = 0;
+        tm.       tm_min = 0;
+        tm.       tm_hour = 0;
+        tm.       tm_mday -= tm.tm_wday - 1;    /* -1 because we want the monday */
+
         if (tm.tm_wday == 0)
-            tm.tm_mday -= 7;    /* we want the *previous* monday */
+            tm.       tm_mday -= 7; /* we want the *previous* monday */
+
         break;
     case TMT_MONTH:
-        tm.tm_sec = 0;
-        tm.tm_min = 0;
-        tm.tm_hour = 0;
-        tm.tm_mday = 1;
-        tm.tm_mon -= tm.tm_mon % basestep;
+        tm.       tm_sec = 0;
+        tm.       tm_min = 0;
+        tm.       tm_hour = 0;
+        tm.       tm_mday = 1;
+        tm.       tm_mon -= tm.tm_mon % basestep;
+
         break;
 
     case TMT_YEAR:
-        tm.tm_sec = 0;
-        tm.tm_min = 0;
-        tm.tm_hour = 0;
-        tm.tm_mday = 1;
-        tm.tm_mon = 0;
-        tm.tm_year -= (tm.tm_year + 1900) % basestep;
+        tm.       tm_sec = 0;
+        tm.       tm_min = 0;
+        tm.       tm_hour = 0;
+        tm.       tm_mday = 1;
+        tm.       tm_mon = 0;
+        tm.       tm_year -= (
+    tm.tm_year + 1900) %basestep;
 
     }
     return mktime(&tm);
@@ -1320,28 +1329,35 @@ time_t find_next_time(
     time_t    madetime;
 
     localtime_r(&current, &tm);
+
     do {
         switch (baseint) {
         case TMT_SECOND:
-            tm.tm_sec += basestep;
+            tm.       tm_sec += basestep;
+
             break;
         case TMT_MINUTE:
-            tm.tm_min += basestep;
+            tm.       tm_min += basestep;
+
             break;
         case TMT_HOUR:
-            tm.tm_hour += basestep;
+            tm.       tm_hour += basestep;
+
             break;
         case TMT_DAY:
-            tm.tm_mday += basestep;
+            tm.       tm_mday += basestep;
+
             break;
         case TMT_WEEK:
-            tm.tm_mday += 7 * basestep;
+            tm.       tm_mday += 7 * basestep;
+
             break;
         case TMT_MONTH:
-            tm.tm_mon += basestep;
+            tm.       tm_mon += basestep;
+
             break;
         case TMT_YEAR:
-            tm.tm_year += basestep;
+            tm.       tm_year += basestep;
         }
         madetime = mktime(&tm);
     } while (madetime == -1);   /* this is necessary to skip impssible times
@@ -1354,7 +1370,7 @@ time_t find_next_time(
 /* calculate values required for PRINT and GPRINT functions */
 
 int print_calc(
-    image_desc_t * im,
+    image_desc_t *im,
     char ***prdata)
 {
     long      i, ii, validsteps;
@@ -1536,7 +1552,8 @@ int print_calc(
 
 /* place legends with color spots */
 int leg_place(
-    image_desc_t * im)
+    image_desc_t *im,
+    int *gY)
 {
     /* graph labels */
     int       interleg = im->text_prop[TEXT_PROP_LEGEND].size * 2.0;
@@ -1557,10 +1574,13 @@ int leg_place(
             return -1;
         }
 
+        if (im->extra_flags & FULL_SIZE_MODE)
+            leg_y = leg_y_prev = leg_y - (int) (im->text_prop[TEXT_PROP_LEGEND].size*1.8);
+
         for (i = 0; i < im->gdes_c; i++) {
             fill_last = fill;
 
-            /* hid legends for rules which are not displayed */
+            /* hide legends for rules which are not displayed */
 
             if (!(im->extra_flags & FORCE_RULES_LEGEND)) {
                 if (im->gdes[i].gf == GF_HRULE &&
@@ -1679,20 +1699,34 @@ int leg_place(
                         + glue;
                 }
                 leg_y_prev = leg_y;
-                /* only add y space if there was text on the line */
-                if (leg_x > border || prt_fctn == 's')
-                    leg_y += im->text_prop[TEXT_PROP_LEGEND].size * 1.8;
-                if (prt_fctn == 's')
-                    leg_y -= im->text_prop[TEXT_PROP_LEGEND].size;
+                if (im->extra_flags & FULL_SIZE_MODE) {
+                    /* only add y space if there was text on the line */
+                    if (leg_x > border || prt_fctn == 's')
+                       leg_y -= im->text_prop[TEXT_PROP_LEGEND].size * 1.8;
+                    if (prt_fctn == 's')
+                       leg_y += im->text_prop[TEXT_PROP_LEGEND].size;
+                } else {
+                    if (leg_x > border || prt_fctn == 's')
+                       leg_y += im->text_prop[TEXT_PROP_LEGEND].size * 1.8;
+                    if (prt_fctn == 's')
+                       leg_y -= im->text_prop[TEXT_PROP_LEGEND].size;
+                }
                 fill = 0;
                 leg_c = 0;
                 mark = ii;
             }
         }
-        im->yimg = leg_y_prev;
-        /* if we did place some legends we have to add vertical space */
-        if (leg_y != im->yimg) {
-            im->yimg += im->text_prop[TEXT_PROP_LEGEND].size * 1.8;
+
+        if (im->extra_flags & FULL_SIZE_MODE) {
+           if (leg_y != leg_y_prev) {
+              *gY = leg_y - im->text_prop[TEXT_PROP_LEGEND].size*1.8;
+              im->yorigin = leg_y - im->text_prop[TEXT_PROP_LEGEND].size*1.8;
+           }
+        } else {
+           im->yimg = leg_y_prev;
+           /* if we did place some legends we have to add vertical space */
+           if (leg_y != im->yimg)
+              im->yimg += im->text_prop[TEXT_PROP_LEGEND].size * 1.8;
         }
         free(legspace);
     }
@@ -1708,7 +1742,7 @@ int leg_place(
 
 
 int calc_horizontal_grid(
-    image_desc_t * im)
+    image_desc_t *im)
 {
     double    range;
     double    scaledrange;
@@ -1804,7 +1838,7 @@ int calc_horizontal_grid(
 }
 
 int draw_horizontal_grid(
-    image_desc_t * im)
+    image_desc_t *im)
 {
     int       i;
     double    scaledstep;
@@ -1946,7 +1980,7 @@ static int AlmostEqual2sComplement(
 
 /* logaritmic horizontal grid */
 int horizontal_log_grid(
-    image_desc_t * im)
+    image_desc_t *im)
 {
     double    yloglab[][10] = {
         {1.0, 10., 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
@@ -2174,7 +2208,7 @@ int horizontal_log_grid(
 
 
 void vertical_grid(
-    image_desc_t * im)
+    image_desc_t *im)
 {
     int       xlab_sel; /* which sort of label and grid ? */
     time_t    ti, tilab, timajor;
@@ -2291,7 +2325,7 @@ void vertical_grid(
 
 
 void axis_paint(
-    image_desc_t * im)
+    image_desc_t *im)
 {
     /* draw x and y axis */
     /* gfx_new_line ( im->canvas, im->xorigin+im->xsize,im->yorigin,
@@ -2321,7 +2355,7 @@ void axis_paint(
 }
 
 void grid_paint(
-    image_desc_t * im)
+    image_desc_t *im)
 {
     long      i;
     int       res = 0;
@@ -2458,7 +2492,7 @@ void grid_paint(
  *****************************************************/
 
 int lazy_check(
-    image_desc_t * im)
+    image_desc_t *im)
 {
     FILE     *fd = NULL;
     int       size = 1;
@@ -2487,7 +2521,7 @@ int lazy_check(
 
 #ifdef WITH_PIECHART
 void pie_part(
-    image_desc_t * im,
+    image_desc_t *im,
     gfx_color_t color,
     double PieCenterX,
     double PieCenterY,
@@ -2539,7 +2573,7 @@ void pie_part(
 #endif
 
 int graph_size_location(
-    image_desc_t * im,
+    image_desc_t *im,
     int elements
 #ifdef WITH_PIECHART
     ,
@@ -2553,22 +2587,6 @@ int graph_size_location(
      ** 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......................|
-     ** +-+-------------------------------------------+
-     ** |                 watermark                   |
-     ** +---------------------------------------------+
-     */
     int       Xvertical = 0, Ytitle = 0, Xylabel = 0, Xmain = 0, Ymain = 0,
 #ifdef WITH_PIECHART
         Xpie = 0, Ypie = 0,
@@ -2588,123 +2606,245 @@ int graph_size_location(
         return 0;
     }
 
-    if (im->ylegend[0] != '\0') {
-        Xvertical = im->text_prop[TEXT_PROP_UNIT].size * 2;
+    /** +---+--------------------------------------------+
+     ** | y |...............graph title..................|
+     ** |   +---+-------------------------------+--------+
+     ** | a | y |                               |        |
+     ** | x |   |                               |        |
+     ** | i | a |                               |  pie   |
+     ** | s | x |       main graph area         | chart  |
+     ** |   | i |                               |  area  |
+     ** | t | s |                               |        |
+     ** | i |   |                               |        |
+     ** | t | l |                               |        |
+     ** | l | b +-------------------------------+--------+
+     ** | e | l |       x axis labels           |        |
+     ** +---+---+-------------------------------+--------+
+     ** |....................legends.....................|
+     ** +------------------------------------------------+
+     ** |                   watermark                    |
+     ** +------------------------------------------------+
+     */
+    
+    if (im->ylegend[0] != '\0' ) {
+         Xvertical = im->text_prop[TEXT_PROP_UNIT].size *2;
     }
 
-
     if (im->title[0] != '\0') {
-        /* The title is placed "inbetween" two text lines so it
+         /* The title is placed "inbetween" two text lines so it
          ** automatically has some vertical spacing.  The horizontal
          ** spacing is added here, on each side.
          */
-        /* don't care for the with of the title
-           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, 0) + 2*Xspacing; */
-        Ytitle = im->text_prop[TEXT_PROP_TITLE].size * 2.6 + 10;
+         /* if necessary, reduce the font size of the title until it fits the image width */
+         Ytitle = im->text_prop[TEXT_PROP_TITLE].size*2.6+10;
     }
 
     if (elements) {
-        Xmain = im->xsize;
-        Ymain = im->ysize;
-        if (im->draw_x_grid) {
-            Yxlabel = im->text_prop[TEXT_PROP_AXIS].size * 2.5;
-        }
-        if (im->draw_y_grid || im->forceleftspace) {
-            Xylabel = gfx_get_text_width(im->canvas, 0,
-                                         im->text_prop[TEXT_PROP_AXIS].font,
-                                         im->text_prop[TEXT_PROP_AXIS].size,
-                                         im->tabwidth,
-                                         "0", 0) * im->unitslength;
-        }
+         if (im->draw_x_grid) {
+               Yxlabel=im->text_prop[TEXT_PROP_AXIS].size *2.5;
+         }
+         if (im->draw_y_grid || im->forceleftspace ) {
+               Xylabel=gfx_get_text_width(im->canvas, 0,
+                            im->text_prop[TEXT_PROP_AXIS].font,
+                            im->text_prop[TEXT_PROP_AXIS].size,
+                            im->tabwidth,
+                            "0", 0) * im->unitslength;
+         }
     }
+
+    if (im->extra_flags & FULL_SIZE_MODE) {
+        /* The actual size of the image to draw has been determined by the user.
+        ** The graph area is the space remaining after accounting for the legend,
+        ** the watermark, the pie chart, the axis labels, and the title.
+        */
+        im->xorigin =0;
+        im->ximg = im->xsize;
+        im->yimg = im->ysize;
+        im->yorigin = im->ysize;
+        Xmain=im->ximg;
+        Ymain=im->yimg;
+
+        im->yorigin += Ytitle;
+
 #ifdef WITH_PIECHART
-    if (piechart) {
-        im->piesize = im->xsize < im->ysize ? im->xsize : im->ysize;
-        Xpie = im->piesize;
-        Ypie = im->piesize;
-    }
+        if (piechart) {
+            im->piesize=im->xsize<im->ysize?im->xsize:im->ysize;
+            Xpie=im->piesize;
+            Ypie=im->piesize;
+        }
 #endif
 
-    /* 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. */
+        /* 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 + 2 * Xspacing;
+        /* Initial size calculation for the main graph area */
+        Xmain = im->ximg - (Xylabel + 2 * Xspacing);
+        if (Xmain) Xmain -= Xspacing; /* put space between main graph area and right edge */
 
 #ifdef WITH_PIECHART
-    im->ximg += Xpie;
+        Xmain -= Xpie; /* remove pie width from main graph area */
+        if (Xpie) Xmain -= Xspacing; /* put space between pie and main graph area */
 #endif
 
-    if (Xmain)
-        im->ximg += Xspacing;
+        im->xorigin = Xspacing + Xylabel;
+
+        /* the length of the title should not influence with width of the graph
+           if (Xtitle > im->ximg) im->ximg = Xtitle; */
+
+        if (Xvertical) { /* unit description */
+            Xmain -= Xvertical;
+            im->xorigin += Xvertical;
+        }
+        im->xsize = Xmain;
+        xtr(im,0);
+
+        /* The vertical size of the image is known in advance.  The main graph area
+        ** (Ymain) and im->yorigin must be set according to the space requirements
+        ** of the legend and the axis labels.
+        */
+
+        /* Determine where to place the legends onto the image.
+        ** Set Ymain and adjust im->yorigin to match the space requirements.
+        */
+        if (leg_place(im,&Ymain)==-1)
+            return -1;
+
 #ifdef WITH_PIECHART
-    if (Xpie)
-        im->ximg += Xspacing;
+        /* if (im->yimg < Ypie) im->yimg = Ypie; * not sure what do about this */
 #endif
 
-    im->xorigin = Xspacing + Xylabel;
+        /* remove title space *or* some padding above the graph from the main graph area */
+        if (Ytitle) {
+            Ymain -= Ytitle;
+        } else {
+            Ymain -= 1.5*Yspacing;
+        }
 
-    /* the length of the title should not influence with width of the graph
-       if (Xtitle > im->ximg) im->ximg = Xtitle; */
+        /* watermark doesn't seem to effect the vertical size of the main graph area, oh well! */
+        if (im->watermark[0] != '\0') {
+            Ymain -= Ywatermark;
+        }
 
-    if (Xvertical) {    /* unit description */
-        im->ximg += Xvertical;
-        im->xorigin += Xvertical;
-    }
-    xtr(im, 0);
+        im->ysize = Ymain;
 
-    /* The vertical size is interesting... we need to compare
-     ** the sum of {Ytitle, Ymain, Yxlabel, Ylegend, Ywatermark} with 
-     ** Yvertical however we need to know {Ytitle+Ymain+Yxlabel}
-     ** in order to start even thinking about Ylegend or Ywatermark.
-     **
-     ** Do it in three portions: First calculate the inner part,
-     ** then do the legend, then adjust the total height of the img,
-     ** adding space for a watermark if one exists;
-     */
+    } else /* dimension options -width and -height refer to the dimensions of the main graph area */
+    {
+        /* 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.
+        */
+
+        if (im->ylegend[0] != '\0' ) {
+               Xvertical = im->text_prop[TEXT_PROP_UNIT].size *2;
+        }
+
+
+        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.
+            */
+            /* don't care for the with of the title
+                    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, 0) + 2*Xspacing; */
+            Ytitle = im->text_prop[TEXT_PROP_TITLE].size*2.6+10;
+        }
+
+        if (elements) {
+            Xmain=im->xsize;
+            Ymain=im->ysize;
+        }
+
+#ifdef WITH_PIECHART
+        if (piechart) {
+            im->piesize=im->xsize<im->ysize?im->xsize:im->ysize;
+            Xpie=im->piesize;
+            Ypie=im->piesize;
+        }
+#endif
 
-    /* reserve space for main and/or pie */
+        /* 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. */
 
-    im->yimg = Ymain + Yxlabel;
+        /* 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 + 2 * Xspacing;
 
 #ifdef WITH_PIECHART
-    if (im->yimg < Ypie)
-        im->yimg = Ypie;
+        im->ximg  += Xpie;
 #endif
 
-    im->yorigin = im->yimg - Yxlabel;
+        if (Xmain) im->ximg += Xspacing;
+#ifdef WITH_PIECHART
+        if (Xpie) im->ximg += Xspacing;
+#endif
 
-    /* reserve space for the title *or* some padding above the graph */
-    if (Ytitle) {
-        im->yimg += Ytitle;
-        im->yorigin += Ytitle;
-    } else {
-        im->yimg += 1.5 * Yspacing;
-        im->yorigin += 1.5 * Yspacing;
-    }
-    /* reserve space for padding below the graph */
-    im->yimg += Yspacing;
+        im->xorigin = Xspacing + Xylabel;
 
-    /* Determine where to place the legends onto the image.
-     ** Adjust im->yimg to match the space requirements.
-     */
-    if (leg_place(im) == -1)
-        return -1;
+        /* the length of the title should not influence with width of the graph
+           if (Xtitle > im->ximg) im->ximg = Xtitle; */
 
-    if (im->watermark[0] != '\0') {
-        im->yimg += Ywatermark;
+        if (Xvertical) { /* unit description */
+            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, Ywatermark} with 
+        ** Yvertical however we need to know {Ytitle+Ymain+Yxlabel}
+        ** in order to start even thinking about Ylegend or Ywatermark.
+        **
+        ** Do it in three portions: First calculate the inner part,
+        ** then do the legend, then adjust the total height of the img,
+        ** adding space for a watermark if one exists;
+        */
+
+        /* reserve space for main and/or pie */
+
+        im->yimg = Ymain + Yxlabel;
+    
+#ifdef WITH_PIECHART
+        if (im->yimg < Ypie) im->yimg = Ypie;
+#endif
+
+        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 += 1.5*Yspacing;
+            im->yorigin += 1.5*Yspacing;
+        }
+        /* reserve space for padding below the graph */
+        im->yimg += Yspacing;
+     
+        /* Determine where to place the legends onto the image.
+        ** Adjust im->yimg to match the space requirements.
+        */
+        if(leg_place(im,0)==-1)
+            return -1;
+        
+        if (im->watermark[0] != '\0') {
+            im->yimg += Ywatermark;
+        }
     }
+
 #if 0
     if (Xlegend > im->ximg) {
         im->ximg = Xlegend;
@@ -2714,19 +2854,19 @@ int graph_size_location(
 
 #ifdef WITH_PIECHART
     /* The pie is placed in the upper right hand corner,
-     ** just below the title (if any) and with sufficient
-     ** padding.
-     */
+    ** 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;
+        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;
+        im->pie_x = im->ximg/2;
+        im->pie_y = im->yorigin-Ypie/2;
     }
 #endif
 
-    ytr(im, DNAN);
+    ytr(im,DNAN);
     return 0;
 }
 
@@ -2737,7 +2877,7 @@ int graph_size_location(
 
 /* draw that picture thing ... */
 int graph_paint(
-    image_desc_t * im,
+    image_desc_t *im,
     char ***calcpr)
 {
     int       i, ii;
@@ -2797,6 +2937,17 @@ int graph_paint(
         piechart = 2;
 #endif
 
+/**************************************************************
+ *** Calculating sizes and locations became a bit confusing ***
+ *** so I moved this into a separate function.              ***
+ **************************************************************/
+    if (graph_size_location(im, i
+#ifdef WITH_PIECHART
+                            , piechart
+#endif
+        ) == -1)
+        return -1;
+
     /* get actual drawing data and find min and max values */
     if (data_proc(im) == -1)
         return -1;
@@ -2815,18 +2966,6 @@ int graph_paint(
     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
-#ifdef WITH_PIECHART
-                            , piechart
-#endif
-        ) == -1)
-        return -1;
-
     /* the actual graph is created by going through the individual
        graph elements and then drawing them */
 
@@ -3190,7 +3329,7 @@ int graph_paint(
  *****************************************************/
 
 int gdes_alloc(
-    image_desc_t * im)
+    image_desc_t *im)
 {
 
     im->gdes_c++;
@@ -3344,7 +3483,7 @@ int rrd_graph(
 }
 
 void rrd_graph_init(
-    image_desc_t * im)
+    image_desc_t *im)
 {
     unsigned int i;
 
@@ -3439,7 +3578,7 @@ void rrd_graph_init(
 void rrd_graph_options(
     int argc,
     char *argv[],
-    image_desc_t * im)
+    image_desc_t *im)
 {
     int       stroff;
     char     *parsetime_error = NULL;
@@ -3468,6 +3607,7 @@ void rrd_graph_options(
             {"vertical-label", required_argument, 0, 'v'},
             {"width", required_argument, 0, 'w'},
             {"height", required_argument, 0, 'h'},
+            {"full-size-mode",  no_argument, 0, 'D'},
             {"interlaced", no_argument, 0, 'i'},
             {"upper-limit", required_argument, 0, 'u'},
             {"lower-limit", required_argument, 0, 'l'},
@@ -3507,7 +3647,7 @@ void rrd_graph_options(
         int       col_start, col_end;
 
         opt = getopt_long(argc, argv,
-                          "s:e:x:y:v:w:h:iu:l:rb:oc:n:m:t:f:a:I:zgjFYAMEX:L:S:T:NR:B:W:",
+                          "s:e:x:y:v:w:h:D:iu:l:rb:oc:n:m:t:f:a:I:zgjFYAMEX:L:S:T:NR:B:W:",
                           long_options, &option_index);
 
         if (opt == EOF)
@@ -3669,6 +3809,9 @@ void rrd_graph_options(
             }
             im->ysize = long_tmp;
             break;
+        case 'D':
+            im->extra_flags |= FULL_SIZE_MODE;
+            break;
         case 'i':
             im->canvas->interlaced = 1;
             break;
@@ -3841,7 +3984,7 @@ void rrd_graph_options(
 }
 
 int rrd_graph_color(
-    image_desc_t * im,
+    image_desc_t *im,
     char *var,
     char *err,
     int optional)