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 );
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 */
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:
}
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;
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);
}
/* 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 */
/* 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;
}
/* 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;
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;
}
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;
}
/*
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 {
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);
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,
{"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)
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);