new options to tune how fontsmoothing works:
authoroetiker <oetiker@a5681a0c-68f1-0310-ab6d-d61299d08faa>
Tue, 3 May 2005 17:24:50 +0000 (17:24 +0000)
committeroetiker <oetiker@a5681a0c-68f1-0310-ab6d-d61299d08faa>
Tue, 3 May 2005 17:24:50 +0000 (17:24 +0000)
-R/--font-render-mode {normal,light,mono} and -B/--font-smoothing-threshold size
-- John yffffffff4271ef37 at f4n.org

git-svn-id: svn://svn.oetiker.ch/rrdtool/branches/1.2/program@481 a5681a0c-68f1-0310-ab6d-d61299d08faa

doc/rrdgraph.pod
src/rrd_gfx.c
src/rrd_gfx.h
src/rrd_graph.c

index 865e256..b87d9d7 100644 (file)
@@ -279,6 +279,18 @@ variable C<RRD_DEFAULT_FONT> if you want to change this.
 
 Truetype fonts are only supported for PNG output. See below.
 
+[B<-R>|B<--font-render-mode> {I<normal>,I<light>,I<mono>}]
+
+This lets you customize the strength of the font smoothing,
+or disable it entirely using I<mono>. By default, I<normal>
+font smoothing is used.
+
+[B<-B>|B<--font-smoothing-threshold> I<size>]
+
+This specifies the largest font size which will be rendered
+bitmapped, that is, without any font smoothing. By default,
+no text is rendered bitmapped.
+
 [B<-a>|B<--imgformat> B<PNG>|B<SVG>|B<EPS>|B<PDF>]
 
 Image format for the generated graph. For the vector formats you can
index cdb92e1..3ad318a 100644 (file)
@@ -45,8 +45,8 @@ struct gfx_string_s {
 static void compute_string_bbox(gfx_string string);
 
 /* create a freetype glyph string */
-gfx_string gfx_string_create ( FT_Face face,
-                               const char *text, int rotation, double tabwidth);
+gfx_string gfx_string_create ( gfx_canvas_t *canvas, FT_Face face,
+                               const char *text, int rotation, double tabwidth, double size);
 
 /* create a freetype glyph string */
 static void gfx_string_destroy ( gfx_string string );
@@ -88,7 +88,9 @@ gfx_canvas_t *gfx_new_canvas (void) {
     canvas->imgformat = IF_PNG; /* we default to PNG output */
     canvas->interlaced = 0;
     canvas->zoom = 1.0;
-    return canvas;    
+    canvas->font_aa_threshold = -1.0;
+    canvas->aa_type = AA_NORMAL;
+    return canvas;
 }
 
 /* create a new line */
@@ -275,7 +277,7 @@ double gfx_get_text_width ( gfx_canvas_t *canvas,
                            double tabwidth, char* text, int rotation){
   switch (canvas->imgformat) {
   case IF_PNG: 
-    return gfx_get_text_width_libart (start, font, size, tabwidth, text, rotation);
+    return gfx_get_text_width_libart (canvas, start, font, size, tabwidth, text, rotation);
   case IF_SVG: /* fall through */ 
   case IF_EPS:
   case IF_PDF:
@@ -286,8 +288,8 @@ double gfx_get_text_width ( gfx_canvas_t *canvas,
 }
 
 double gfx_get_text_width_libart (
-                           double start, char* font, double size,
-                           double tabwidth, char* text, int rotation){
+                           gfx_canvas_t *canvas, double start, char* font, double size,
+                           double tabwidth, char* text, int rotation ){
 
   int           error;
   double        text_width=0;
@@ -301,7 +303,7 @@ double gfx_get_text_width_libart (
   error = FT_Set_Char_Size(face,  size*64,size*64,  100,100);
   if ( error ) return -1;
 
-  string = gfx_string_create( face, text, rotation,tabwidth);
+  string = gfx_string_create( canvas, face, text, rotation, tabwidth, size );
   text_width = string->width;
   gfx_string_destroy(string);
   FT_Done_FreeType(library);
@@ -358,8 +360,8 @@ static void compute_string_bbox(gfx_string string) {
 } 
 
 /* create a free type glyph string */
-gfx_string gfx_string_create(FT_Face face,const char *text,
-        int rotation, double tabwidth)
+gfx_string gfx_string_create(gfx_canvas_t *canvas, FT_Face face,const char *text,
+        int rotation, double tabwidth, double size )
 {
 
   FT_GlyphSlot  slot = face->glyph;  /* a small shortcut */
@@ -427,7 +429,10 @@ gfx_string gfx_string_create(FT_Face face,const char *text,
 
     /* load the glyph image (in its native format) */
     /* for now, we take a monochrome glyph bitmap */
-    error = FT_Load_Glyph (face, glyph->index, FT_LOAD_DEFAULT);
+    error = FT_Load_Glyph (face, glyph->index, size > canvas->font_aa_threshold ?
+                            canvas->aa_type == AA_NORMAL ? FT_LOAD_TARGET_NORMAL :
+                            canvas->aa_type == AA_LIGHT ? FT_LOAD_TARGET_LIGHT :
+                            FT_LOAD_TARGET_MONO : FT_LOAD_TARGET_MONO);
     if (error) {
       fprintf (stderr, "couldn't load glyph:  %c\n", letter);
       continue;
@@ -461,7 +466,10 @@ gfx_string gfx_string_create(FT_Face face,const char *text,
     }
 
     /* convert to a bitmap - destroy native image */
-    error = FT_Glyph_To_Bitmap (&glyph->image, FT_RENDER_MODE_NORMAL, 0, 1);
+    error = FT_Glyph_To_Bitmap (&glyph->image, size > canvas->font_aa_threshold ?
+                            canvas->aa_type == AA_NORMAL ? FT_RENDER_MODE_NORMAL :
+                            canvas->aa_type == AA_LIGHT ? FT_RENDER_MODE_LIGHT :
+                            FT_RENDER_MODE_MONO : FT_RENDER_MODE_MONO, 0, 1);
     if (error) {
       fprintf (stderr, "couldn't convert glyph to bitmap\n");
       continue;
@@ -582,7 +590,7 @@ int           gfx_render_png (gfx_canvas_t *canvas,
             pen_x = node->x * canvas->zoom;
             pen_y = node->y * canvas->zoom;
 
-            string = gfx_string_create (face, node->text, node->angle, node->tabwidth);
+            string = gfx_string_create (canvas, face, node->text, node->angle, node->tabwidth, node->size);
             switch(node->halign){
             case GFX_H_RIGHT:  vec.x = -string->bbox.xMax;
                                break;          
@@ -647,23 +655,46 @@ int           gfx_render_png (gfx_canvas_t *canvas,
                 }
                 art_free(letter);
 */
-
-                for (iy=0; iy < bit->bitmap.rows; iy++){                   
-                    long buf_y = iy+(pen_y+0.5)-bit->top;
-                    if (buf_y < 0 || buf_y >= (long)pys_height) continue;
-                    buf_y *= rowstride;
-                    for (ix=0;ix < bit->bitmap.width;ix++){
-                        long buf_x = ix + (pen_x + 0.5) + (double)bit->left ;
-                        art_u8 font_alpha;
-                        
-                        if (buf_x < 0 || buf_x >= (long)pys_width) continue;
-                        buf_x *=  bytes_per_pixel ;
-                        font_alpha =  *(bit->bitmap.buffer + iy * bit->bitmap.pitch + ix);
-                       if (font_alpha > 0){
-                               fcolor[3] =  (art_u8)((double)font_alpha / gr * falpha);
-                               art_rgba_rgba_composite(buffer + buf_y + buf_x ,fcolor,1);
+                switch ( bit->bitmap.pixel_mode ) {
+                    case FT_PIXEL_MODE_GRAY:
+                        for (iy=0; iy < bit->bitmap.rows; iy++){
+                            long buf_y = iy+(pen_y+0.5)-bit->top;
+                            if (buf_y < 0 || buf_y >= (long)pys_height) continue;
+                            buf_y *= rowstride;
+                            for (ix=0;ix < bit->bitmap.width;ix++){
+                                long buf_x = ix + (pen_x + 0.5) + (double)bit->left ;
+                                art_u8 font_alpha;
+
+                                if (buf_x < 0 || buf_x >= (long)pys_width) continue;
+                                buf_x *=  bytes_per_pixel ;
+                                font_alpha =  *(bit->bitmap.buffer + iy * bit->bitmap.pitch + ix);
+                    if (font_alpha > 0){
+                                    fcolor[3] =  (art_u8)((double)font_alpha / gr * falpha);
+                        art_rgba_rgba_composite(buffer + buf_y + buf_x ,fcolor,1);
+                                }
+                            }
                         }
-                    }
+                        break;
+
+                    case FT_PIXEL_MODE_MONO:
+                        for (iy=0; iy < bit->bitmap.rows; iy++){
+                            long buf_y = iy+(pen_y+0.5)-bit->top;
+                            if (buf_y < 0 || buf_y >= (long)pys_height) continue;
+                            buf_y *= rowstride;
+                            for (ix=0;ix < bit->bitmap.width;ix++){
+                                long buf_x = ix + (pen_x + 0.5) + (double)bit->left ;
+
+                                if (buf_x < 0 || buf_x >= (long)pys_width) continue;
+                                buf_x *=  bytes_per_pixel ;
+                                if ( (fcolor[3] = falpha * ((*(bit->bitmap.buffer + iy * bit->bitmap.pitch + ix/8) >> (7 - (ix % 8))) & 1)) > 0 )
+                                    art_rgba_rgba_composite(buffer + buf_y + buf_x ,fcolor,1);
+                            }
+                        }
+                        break;
+
+                        default:
+                            rrd_set_error("unknown freetype pixel mode: %d", bit->bitmap.pixel_mode);
+                            break;
                 }
 
 /*
index 4263d8a..e9c5c93 100644 (file)
@@ -16,6 +16,7 @@ enum gfx_if_en {IF_PNG=0,IF_SVG,IF_EPS,IF_PDF};
 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_aa_type_en {AA_NORMAL=0,AA_LIGHT,AA_NONE};
 typedef unsigned long gfx_color_t;
 
 typedef struct  gfx_node_t {
@@ -45,6 +46,8 @@ typedef struct gfx_canvas_t
     enum gfx_if_en imgformat;      /* image format */
     int            interlaced;     /* will the graph be interlaced? */
     double         zoom;           /* zoom for graph */
+    double         font_aa_threshold; /* no anti-aliasing for sizes <= */
+    enum gfx_aa_type_en aa_type;   /* anti-aliasing type (normal/light/none) */
 } gfx_canvas_t;
 
 gfx_canvas_t *gfx_new_canvas (void);
@@ -103,8 +106,9 @@ int           gfx_destroy    (gfx_canvas_t *canvas);
 int       gfx_render_png (gfx_canvas_t *canvas,
                               art_u32 width, art_u32 height,
                               gfx_color_t background, FILE *fo);
-double gfx_get_text_width_libart ( double start, char* font, double size,
-                           double tabwidth, char* text, int rotation);
+double gfx_get_text_width_libart ( gfx_canvas_t *canvas, double start, 
+                char* font, double size, double tabwidth, 
+                char* text, int rotation );
 
 /* SVG support */
 int       gfx_render_svg (gfx_canvas_t *canvas,
index 047d9c2..a5f87db 100644 (file)
@@ -2867,13 +2867,15 @@ rrd_graph_options(int argc, char *argv[],image_desc_t *im)
            {"units-length",required_argument, 0, 'L'},
            {"step",       required_argument, 0,    'S'},
             {"tabwidth",   required_argument, 0,    'T'},            
+           {"font-render-mode", required_argument, 0, 'R'},
+           {"font-smoothing-threshold", required_argument, 0, 'B'},
            {0,0,0,0}};
        int option_index = 0;
        int opt;
         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:zgjFYAMX:L:S:T:N",
+                        "s:e:x:y:v:w:h:iu:l:rb:oc:n:m:t:f:a:I:zgjFYAMX:L:S:T:NR:B:",
                          long_options, &option_index);
 
        if (opt == EOF)
@@ -3113,6 +3115,24 @@ rrd_graph_options(int argc, char *argv[],image_desc_t *im)
            im->title[150]='\0';
            break;
 
+       case 'R':
+               if ( strcmp( optarg, "normal" ) == 0 )
+                       im->canvas->aa_type = AA_NORMAL;
+               else if ( strcmp( optarg, "light" ) == 0 )
+                       im->canvas->aa_type = AA_LIGHT;
+               else if ( strcmp( optarg, "mono" ) == 0 )
+                       im->canvas->aa_type = AA_NONE;
+               else
+               {
+                       rrd_set_error("unknown font-render-mode '%s'", optarg );
+                       return;
+               }
+               break;
+
+       case 'B':
+           im->canvas->font_aa_threshold = atof(optarg);
+               break;
+
        case '?':
             if (optopt != 0)
                 rrd_set_error("unknown option '%c'", optopt);