ref: 0c8cde2e05561fd02b729f11c11a3589babfed54
dir: /demos/src/ftstring.c/
/****************************************************************************/ /* */ /* The FreeType project -- a free and portable quality TrueType renderer. */ /* */ /* Copyright 1996-1999 by */ /* D. Turner, R.Wilhelm, and W. Lemberg */ /* */ /* */ /* FTString.c - simple text string display */ /* */ /****************************************************************************/ #include <freetype/freetype.h> #include <freetype/ftglyph.h> #include "common.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdarg.h> #include <math.h> #include "graph.h" #include "grfont.h" #include <freetype/ftgrays.h> #define DIM_X 500 #define DIM_Y 400 #define CENTER_X (bit.width/2) #define CENTER_Y (bit.rows/2) #define MAXPTSIZE 500 /* dtp */ static char Header[128]; static char* new_header = 0; static char* Text = "The quick brown fox jumps over the lazy dog"; static FT_Library library; /* the FreeType library */ static FT_Face face; /* the font face */ static FT_Error error; /* error returned by FreeType ? */ static grSurface* surface; /* current display surface */ static grBitmap bit; /* current display bitmap */ static int ptsize; /* current point size */ static int Num; static int Rotation = 0; static int Fail; static int hinted = 1; /* is glyph hinting active ? */ static int antialias = 1; /* is anti-aliasing active ? */ static int use_sbits = 1; /* do we use embedded bitmaps ? */ static int kerning = 1; static int res = 72; /* default resolution in dpi */ static grColor fore_color = { 255 }; static int graph_init = 0; static int render_mode = 1; static int use_grays = 0; /* the standard raster's interface */ static FT_Raster_Funcs std_raster; static FT_Matrix trans_matrix; static int transform = 0; static FT_Vector string_center; typedef struct TGlyph_ { FT_UInt glyph_index; /* glyph index in face */ FT_Vector pos; /* position of glyph origin */ FT_Glyph image; /* glyph image */ } TGlyph, *PGlyph; #define FLOOR(x) ((x) & -64) #define CEIL(x) (((x)+63) & -64) #define TRUNC(x) ((x) >> 6) /****************************************************************************/ /****************************************************************************/ /****************************************************************************/ /**** ****/ /**** U T I L I T Y F U N C T I O N S ****/ /**** ****/ /**** ****/ /****************************************************************************/ /****************************************************************************/ /****************************************************************************/ #define DEBUGxxx #ifdef DEBUG #define LOG(x) LogMessage##x #else #define LOG(x) /* rien */ #endif #ifdef DEBUG static void LogMessage( const char* fmt, ... ) { va_list ap; va_start( ap, fmt ); vfprintf( stderr, fmt, ap ); va_end( ap ); } #endif /* PanicZ */ static void PanicZ( const char* message ) { fprintf( stderr, "%s\n error = 0x%04x\n", message, error ); exit(1); } /****************************************************************************/ /****************************************************************************/ /****************************************************************************/ /**** ****/ /**** D I S P L A Y M A N A G E M E N T ****/ /**** ****/ /**** ****/ /****************************************************************************/ /****************************************************************************/ /****************************************************************************/ #define MAX_GLYPHS 512 /*********************************************************************** * * The following arrays are used to store the glyph set that makes * up a string of text.. * */ static TGlyph glyphs[ MAX_GLYPHS ]; static int num_glyphs; /************************************************************** * * Initialise the display surface * */ static int init_display( void ) { grInitDevices(); bit.mode = gr_pixel_mode_gray; bit.width = DIM_X; bit.rows = DIM_Y; bit.grays = 256; surface = grNewSurface( 0, &bit ); if (!surface) PanicZ( "could not allocate display surface\n" ); graph_init = 1; return 0; } /************************************************************** * * Clears the display surface * */ static void clear_display( void ) { long size = (long)bit.pitch * bit.rows; if (size < 0) size = -size; memset( bit.buffer, 0, size ); } static FT_Error reset_scale( int pointSize ) { FT_Error error; error = FT_Set_Char_Size( face, pointSize << 6, pointSize << 6, res, res ); return FT_Err_Ok; } /************************************************************** * * Compute the dimension of a string of glyphs in pixels * */ static void compute_bbox( FT_BBox* abbox ) { PGlyph glyph = glyphs; FT_BBox bbox; int n; bbox.xMin = 32000; bbox.xMax = -32000; bbox.yMin = 32000; bbox.yMax = -32000; for ( n = 0; n < num_glyphs; n++, glyph++ ) { FT_BBox cbox; FT_Pos x, y; if (!glyph->image) continue; x = glyph->pos.x >> 6; y = glyph->pos.y >> 6; FT_Glyph_Get_Box( glyph->image, &cbox ); cbox.xMin += x; cbox.yMin += y; cbox.xMax += x; cbox.yMax += y; if (cbox.xMin < bbox.xMin) bbox.xMin = cbox.xMin; if (cbox.xMax > bbox.xMax) bbox.xMax = cbox.xMax; if (cbox.yMin < bbox.yMin) bbox.yMin = cbox.yMin; if (cbox.yMax > bbox.yMax) bbox.yMax = cbox.yMax; } *abbox = bbox; } /************************************************************** * * Layout a string of glyphs * */ static void layout_glyphs( void ) { PGlyph glyph = glyphs; FT_Error error; int n; FT_Vector origin; FT_Pos origin_x = 0; FT_UInt load_flags; FT_UInt num_grays; FT_UInt prev_index = 0; load_flags = FT_LOAD_DEFAULT; if( !hinted ) load_flags |= FT_LOAD_NO_HINTING; num_grays = 256; if (!antialias) num_grays = 0; for ( n = 0; n < num_glyphs; n++, glyph++ ) { /* compute glyph origin */ if (kerning) { if (prev_index) { FT_Vector kern; FT_Get_Kerning( face, prev_index, glyph->glyph_index, &kern ); kern.x = FT_MulFix( kern.x, face->size->metrics.x_scale ); if (hinted) kern.x = (kern.x+32) & -64; origin_x += kern.x; } prev_index = glyph->glyph_index; } origin.x = origin_x; origin.y = 0; if (transform) FT_Vector_Transform( &origin, &trans_matrix ); /* clear existing image if there is one */ if (glyph->image) FT_Done_Glyph(glyph->image); /* load the glyph image */ /* for now, we take a monochrome glyph bitmap */ error = FT_Get_Glyph_Bitmap( face, glyph->glyph_index, load_flags, num_grays, &origin, (FT_BitmapGlyph*)&glyph->image ); if (error) continue; glyph->pos = origin; origin_x += glyph->image->advance; } string_center.x = origin_x / 2; string_center.y = 0; if (transform) FT_Vector_Transform( &string_center, &trans_matrix ); } /************************************************************** * * Renders a given glyph vector set * */ static void render_string( FT_Pos x, FT_Pos y ) { PGlyph glyph = glyphs; grBitmap bit3; int n; for ( n = 0; n < num_glyphs; n++, glyph++ ) { if (!glyph->image) continue; switch (glyph->image->glyph_type) { case ft_glyph_type_bitmap: { /* this is a bitmap, we simply blit it to our target surface */ FT_BitmapGlyph bitm = (FT_BitmapGlyph)glyph->image; FT_Bitmap* source = &bitm->bitmap; FT_Pos x_top, y_top; bit3.rows = source->rows; bit3.width = source->width; bit3.pitch = source->pitch; bit3.buffer = source->buffer; switch (source->pixel_mode) { case ft_pixel_mode_mono: bit3.mode = gr_pixel_mode_mono; break; case ft_pixel_mode_grays: bit3.mode = gr_pixel_mode_gray; bit3.grays = source->num_grays; break; default: continue; } /* now render the bitmap into the display surface */ x_top = x + (glyph->pos.x >> 6) + bitm->left; y_top = y - (glyph->pos.y >> 6) - bitm->top; grBlitGlyphToBitmap( &bit, &bit3, x_top, y_top, fore_color ); } break; #if 0 case ft_glyph_type_outline: { /* in the case of outlines, we directly render it into the */ /* target surface with the smooth renderer.. */ FT_OutlineGlyph out = (FT_OutlineGlyph)glyph->image; FT_Outline_Translate( (x+pen_pos[n]) << 6, (y+ error = FT_Outline_Render( } break; #endif default: ; } } } /************************************************************** * * Convert a string of text into a glyph vector * * XXX: For now, we perform a trivial conversion * */ static void prepare_text( const unsigned char* string ) { const unsigned char* p = (const unsigned char*)string; PGlyph glyph = glyphs; FT_UInt glyph_index; num_glyphs = 0; while (*p) { glyph_index = FT_Get_Char_Index( face, (FT_ULong)*p ); glyph->glyph_index = glyph_index; glyph++; num_glyphs++; if (num_glyphs >= MAX_GLYPHS) break; p++; } } static void reset_transform( void ) { double angle = Rotation*3.14159/64.0; FT_Fixed cosinus = (FT_Fixed)(cos(angle)*65536.0); FT_Fixed sinus = (FT_Fixed)(sin(angle)*65536.0); transform = (angle != 0); trans_matrix.xx = cosinus; trans_matrix.xy = -sinus; trans_matrix.yx = sinus; trans_matrix.yy = cosinus; FT_Set_Transform(face,&trans_matrix, 0); } /****************************************************************************/ /****************************************************************************/ /****************************************************************************/ /**** ****/ /**** E V E N T H A N D L I N G ****/ /**** ****/ /**** ****/ /****************************************************************************/ /****************************************************************************/ /****************************************************************************/ static void Help( ) { grEvent dummy_event; clear_display(); grGotoxy( 0, 0 ); grSetMargin( 2, 1 ); grGotobitmap( &bit ); grWriteln("FreeType String Viewer - part of the FreeType test suite" ); grLn(); grWriteln("This program is used to display a string of text using" ); grWriteln("the new convenience API of the FreeType 2 library."); grLn(); grWriteln("Use the following keys :"); grLn(); grWriteln(" F1 or ? : display this help screen" ); grWriteln(" a : toggle anti-aliasing" ); grWriteln(" h : toggle outline hinting" ); grWriteln(" k : toggle kerning" ); grWriteln(" g : toggle between 'smooth' and 'standard' anti-aliaser" ); grLn(); grWriteln(" Up : increase pointsize by 1 unit" ); grWriteln(" Down : decrease pointsize by 1 unit" ); grWriteln(" Page Up : increase pointsize by 10 units" ); grWriteln(" Page Down : decrease pointsize by 10 units" ); grLn(); grWriteln(" Right : rotate counter-clockwise" ); grWriteln(" Left : rotate clockwise" ); grWriteln(" F7 : big rotate counter-clockwise"); grWriteln(" F8 : big rotate clockwise"); grLn(); grWriteln("press any key to exit this help screen"); grRefreshSurface( surface ); grListenSurface( surface, gr_event_key, &dummy_event ); } static void reset_raster( void ) { FT_Error error; error = 1; if ( use_grays && antialias ) error = FT_Set_Raster( library, &ft_grays_raster ); if (error) (void)FT_Set_Raster( library, &std_raster ); } static int Process_Event( grEvent* event ) { int i; switch ( event->key ) { case grKeyEsc: /* ESC or q */ case grKEY('q'): return 0; case grKEY('k'): kerning = !kerning; new_header = ( kerning ? "kerning is now active" : "kerning is now ignored" ); return 1; case grKEY('a'): antialias = !antialias; new_header = ( antialias ? "anti-aliasing is now on" : "anti-aliasing is now off" ); reset_raster(); return 1; case grKEY('b'): use_sbits = !use_sbits; new_header = ( use_sbits ? "embedded bitmaps are now used when available" : "embedded bitmaps are now ignored" ); return 1; case grKEY('n'): case grKEY('p'): return (int)event->key; case grKEY('g'): use_grays = !use_grays; new_header = ( use_grays ? "now using the smooth anti-aliaser" : "now using the standard anti-aliaser" ); reset_raster(); break; case grKEY('h'): hinted = !hinted; new_header = ( hinted ? "glyph hinting is now active" : "glyph hinting is now ignored" ); break; case grKEY(' '): render_mode ^= 1; new_header = ( render_mode ? "rendering all glyphs in font" : "rendering test text string" ); break; case grKeyF1: case grKEY('?'): Help(); return 1; #if 0 case grKeyF3: i = 16; goto Do_Rotate; case grKeyF4: i = -16; goto Do_Rotate; case grKeyF5: i = 1; goto Do_Rotate; case grKeyF6: i = -1; goto Do_Rotate; #endif case grKeyPageUp: i = 10; goto Do_Scale; case grKeyPageDown: i = -10; goto Do_Scale; case grKeyUp: i = 1; goto Do_Scale; case grKeyDown: i = -1; goto Do_Scale; case grKeyLeft: i = -1; goto Do_Rotate; case grKeyRight: i = 1; goto Do_Rotate; case grKeyF7: i = -10; goto Do_Rotate; case grKeyF8: i = 10; goto Do_Rotate; default: ; } return 1; Do_Rotate: Rotation = (Rotation + i) & 127; return 1; Do_Scale: ptsize += i; if (ptsize < 1) ptsize = 1; if (ptsize > MAXPTSIZE) ptsize = MAXPTSIZE; return 1; #if 0 Do_Glyph: Num += i; if (Num < 0) Num = 0; if (Num >= num_glyphs) Num = num_glyphs-1; return 1; #endif } /****************************************************************************/ /****************************************************************************/ /****************************************************************************/ /**** ****/ /**** M A I N P R O G R A M ****/ /**** ****/ /**** ****/ /****************************************************************************/ /****************************************************************************/ /****************************************************************************/ static void usage( char* execname ) { fprintf( stderr, "\n" ); fprintf( stderr, "ftview: simple string viewer -- part of the FreeType project\n" ); fprintf( stderr, "------------------------------------------------------------\n" ); fprintf( stderr, "\n" ); fprintf( stderr, "Usage: %s [options below] ppem fontname[.ttf|.ttc] ...\n", execname ); fprintf( stderr, "\n" ); fprintf( stderr, " -r R use resolution R dpi (default: 72 dpi)\n" ); fprintf( stderr, " -m message message to display\n" ); fprintf( stderr, "\n" ); exit( 1 ); } int main( int argc, char** argv ) { int i, old_ptsize, orig_ptsize, file; int first_glyph = 0; int XisSetup = 0; char filename[128 + 4]; char alt_filename[128 + 4]; char* execname; int option; int file_loaded; FT_Error error; grEvent event; execname = ft_basename( argv[0] ); while ( 1 ) { option = getopt( argc, argv, "m:r:" ); if ( option == -1 ) break; switch ( option ) { case 'r': res = atoi( optarg ); if ( res < 1 ) usage( execname ); break; case 'm': if (argc < 3) usage( execname ); Text = optarg; break; default: usage( execname ); break; } } argc -= optind; argv += optind; if ( argc <= 1 ) usage( execname ); if ( sscanf( argv[0], "%d", &orig_ptsize ) != 1 ) orig_ptsize = 64; file = 1; /* Initialize engine */ error = FT_Init_FreeType( &library ); if (error) PanicZ( "Could not initialise FreeType library" ); /* retrieve the standard raster's interface */ (void)FT_Get_Raster( library, ft_glyph_format_outline, &std_raster ); NewFile: ptsize = orig_ptsize; hinted = 1; file_loaded = 0; #ifndef macintosh i = strlen( argv[file] ); while ( i > 0 && argv[file][i] != '\\' && argv[file][i] != '/' ) { if ( argv[file][i] == '.' ) i = 0; i--; } #endif filename[128] = '\0'; alt_filename[128] = '\0'; strncpy( filename, argv[file], 128 ); strncpy( alt_filename, argv[file], 128 ); #ifndef macintosh if ( i >= 0 ) { strncpy( filename + strlen( filename ), ".ttf", 4 ); strncpy( alt_filename + strlen( alt_filename ), ".ttc", 4 ); } #endif /* Load face */ error = FT_New_Face( library, filename, 0, &face ); if (error) goto Display_Font; /* prepare the text to be rendered */ prepare_text( (unsigned char*)Text ); file_loaded++; error = reset_scale( ptsize ); if (error) goto Display_Font; Display_Font: /* initialise graphics if needed */ if ( !XisSetup ) { XisSetup = 1; init_display(); } grSetTitle( surface, "FreeType String Viewer - press F1 for help" ); old_ptsize = ptsize; if ( file_loaded >= 1 ) { Fail = 0; Num = first_glyph; if ( Num >= num_glyphs ) Num = num_glyphs-1; if ( Num < 0 ) Num = 0; } for ( ;; ) { int key; clear_display(); if ( file_loaded >= 1 ) { /* layout & render string */ { FT_BBox bbox; reset_transform(); layout_glyphs(); compute_bbox( &bbox ); render_string( (bit.width-(string_center.x >> 5))/2, (bit.rows +(string_center.y >> 5))/2 ); } sprintf( Header, "%s %s (file %s)", face->family_name, face->style_name, ft_basename( filename ) ); if (!new_header) new_header = Header; grWriteCellString( &bit, 0, 0, new_header, fore_color ); new_header = 0; sprintf( Header, "at %d points, rotation = %d", ptsize, Rotation ); } else { sprintf( Header, "%s : is not a font file or could not be opened", ft_basename(filename) ); } grWriteCellString( &bit, 0, 8, Header, fore_color ); grRefreshSurface( surface ); grListenSurface( surface, 0, &event ); if ( !( key = Process_Event( &event ) ) ) goto Fin; if ( key == 'n' ) { if (file_loaded >= 1) FT_Done_Face( face ); if ( file < argc - 1 ) file++; goto NewFile; } if ( key == 'p' ) { if (file_loaded >= 1) FT_Done_Face( face ); if ( file > 1 ) file--; goto NewFile; } if ( ptsize != old_ptsize ) { if ( reset_scale( ptsize ) ) PanicZ( "Could not resize font." ); old_ptsize = ptsize; } } Fin: #if 0 grDoneSurface(surface); grDone(); #endif printf( "Execution completed successfully.\n" ); printf( "Fails = %d\n", Fail ); exit( 0 ); /* for safety reasons */ return 0; /* never reached */ } /* End */