From 423b8ed6a9020e284c84683f6facbed8c3734db2 Mon Sep 17 00:00:00 2001 From: oetiker Date: Tue, 3 May 2005 17:24:50 +0000 Subject: [PATCH] new options to tune how fontsmoothing works: -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 | 12 ++++++++ src/rrd_gfx.c | 87 ++++++++++++++++++++++++++++++++++++++------------------ src/rrd_gfx.h | 8 ++++-- src/rrd_graph.c | 22 +++++++++++++- 4 files changed, 98 insertions(+), 31 deletions(-) diff --git a/doc/rrdgraph.pod b/doc/rrdgraph.pod index 865e256..b87d9d7 100644 --- a/doc/rrdgraph.pod +++ b/doc/rrdgraph.pod @@ -279,6 +279,18 @@ variable C if you want to change this. Truetype fonts are only supported for PNG output. See below. +[B<-R>|B<--font-render-mode> {I,I,I}] + +This lets you customize the strength of the font smoothing, +or disable it entirely using I. By default, I +font smoothing is used. + +[B<-B>|B<--font-smoothing-threshold> I] + +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|B|B|B] Image format for the generated graph. For the vector formats you can diff --git a/src/rrd_gfx.c b/src/rrd_gfx.c index cdb92e1..3ad318a 100644 --- a/src/rrd_gfx.c +++ b/src/rrd_gfx.c @@ -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; } /* diff --git a/src/rrd_gfx.h b/src/rrd_gfx.h index 4263d8a..e9c5c93 100644 --- a/src/rrd_gfx.h +++ b/src/rrd_gfx.h @@ -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, diff --git a/src/rrd_graph.c b/src/rrd_graph.c index 047d9c2..a5f87db 100644 --- a/src/rrd_graph.c +++ b/src/rrd_graph.c @@ -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); -- 2.11.0