/****************************************************************************/ /* */ /* The FreeType project - a free and portable quality TrueType renderer. */ /* */ /* Copyright 1996-1999 by */ /* D. Turner, R.Wilhelm, and W. Lemberg */ /* */ /* ftzoom : A simple glyph viewer. Now supports graylevel rendering */ /* with the '-g' option. */ /* */ /* Use `-p ' together with `-e ' to */ /* select a cmap. */ /* */ /* Keys: */ /* */ /* x : fine counter_clockwise rotation */ /* c : fine clockwise rotation */ /* */ /* v : fast counter_clockwise rotation */ /* b : fast clockwise rotation */ /* */ /* + : fast scale up */ /* - : fast scale down */ /* u : fine scale down */ /* j : fine scale up */ /* */ /* l : go to next glyph */ /* k : go to previous glyph */ /* */ /* o : go to tenth next glyph */ /* i : go to tenth previous glyph */ /* */ /* 0 : go to hundredth next glyph */ /* 9 : go to hundredth previous glyph */ /* */ /* ) : go to 1000th next glyph */ /* ( : go to 1000th previous glyph */ /* */ /* } : go to 10000th next glyph */ /* { : go to 10000th previous glyph */ /* */ /* q : */ /* ESC : exit */ /* */ /* */ /* NOTE 1: This is just a test program that is used to show off and */ /* debug the current engine. In no way does it show the final */ /* high-level interface that client applications will use. */ /* */ /* NOTE 2: The `post' engine is used to display the PS glyph names. */ /* Use the `-n' switch if you don't want that. */ /* */ /****************************************************************************/ #include #include #include #include #include "common.h" /* for Panic() only */ #include "freetype.h" #include "ftxpost.h" #include "gdriver.h" #include "gevents.h" #include "gmain.h" #ifdef DEBUG_LEVEL_TRACE #include "ttdebug.h" #endif #define Pi 3.1415926535 #define MAXPTSIZE 5000 /* dtp */ char Header[128]; TT_Engine engine; TT_Face face; TT_Instance instance; TT_Glyph glyph; TT_CharMap char_map; TT_Glyph_Metrics metrics; TT_Outline outline; TT_Face_Properties properties; TT_Instance_Metrics imetrics; int num_glyphs; int xcenter_upem; int ycenter_upem; int units_per_em; int ptsize; int old_ptsize; int rotation; int old_rotation; TT_Matrix matrix; TT_Matrix zoom_matrix; int apply_matrix; int xcenter; int ycenter; int xoffset; int yoffset; TT_Raster_Map Bit; int Fail; int Num; int Code; int gray_render = 0; int hinted = 1; int use_cmap = 0; int zoom_factor = 1; int grid = 0; int use_post = 1; char palette[5] = { 0, 1, 2, 3, 4 }; static void ClearData( void ) { if ( gray_render ) memset( Bit.bitmap, gray_palette[0], Bit.size ); else memset( Bit.bitmap, 0, Bit.size ); } void Init_Raster_Area( void ) { Bit.rows = vio_Height; /* The whole window */ Bit.width = vio_Width; Bit.flow = TT_Flow_Up; if ( gray_render ) { Bit.cols = Bit.width; Bit.size = Bit.rows * Bit.width; } else { Bit.cols = ( Bit.width + 7 ) / 8; /* convert to # of bytes */ Bit.size = Bit.rows * Bit.cols; /* number of bytes in buffer */ } Bit.bitmap = (void*)malloc( (int)Bit.size ); if ( !Bit.bitmap ) Panic( "Not enough memory to allocate bitmap!\n" ); ClearData(); } static TT_Error Reset_PtSize( int pointSize ) { TT_Error error; if ( (error = TT_Set_Instance_PointSize( instance, pointSize )) ) { RestoreScreen(); printf( "Error = 0x%x.\n", (int)error ); Panic( "Could not reset instance.\n" ); } TT_Get_Instance_Metrics( instance, &imetrics ); xcenter = imetrics.x_ppem * xcenter_upem / units_per_em / 4; ycenter = imetrics.y_ppem * ycenter_upem / units_per_em / 4; xoffset = vio_Width/2 - xcenter; yoffset = vio_Height/2 - ycenter; return TT_Err_Ok; } static TT_Error Reset_Rotation( int rotation ) { if ( rotation ) { float angle; TT_Set_Instance_Transform_Flags( instance, 1, 0 ); angle = rotation * Pi / 512; matrix.xx = (TT_Fixed)(cos( angle ) * (1L<<16)); matrix.xy = (TT_Fixed)(sin( angle ) * (1L<<16)); matrix.yx = -matrix.xy; matrix.yy = matrix.xx; apply_matrix = 1; } else apply_matrix = 0; if ( zoom_factor != 1 ) { zoom_matrix.xx = zoom_matrix.yy = zoom_factor * (1L<<16); zoom_matrix.xy = zoom_matrix.yx = 0; } return TT_Err_Ok; } static TT_Error LoadTrueTypeChar( int idx, int hint ) { TT_Error error; int flags; flags = TTLOAD_SCALE_GLYPH; if ( hint ) flags |= TTLOAD_HINT_GLYPH; error = TT_Load_Glyph( instance, glyph, idx, flags ); if ( error ) return error; if ( apply_matrix || zoom_factor != 1 ) { TT_Get_Glyph_Outline( glyph, &outline ); TT_Translate_Outline( &outline, -xcenter*64L, -ycenter*64L ); if ( apply_matrix ) TT_Transform_Outline( &outline, &matrix ); if ( zoom_factor != 1 ) TT_Transform_Outline( &outline, &zoom_matrix ); TT_Translate_Outline( &outline, xcenter*64L, ycenter*64L ); } return error; } static TT_Error ConvertRaster( void ) { if ( gray_render ) return TT_Get_Glyph_Pixmap( glyph, &Bit, xoffset*64L, yoffset*64L ); else return TT_Get_Glyph_Bitmap( glyph, &Bit, xoffset*64L, yoffset*64L ); } static void DrawGrid( void ) { char *bmap, mask; int x, y, shift, toggle; bmap = (char *)Bit.bitmap; for ( y = 0; y < Bit.rows; ++y ) { if ( ( y - xoffset ) % zoom_factor == 0 ) { if ( gray_render ) for ( x = y & 1; x < Bit.cols; x += 2 ) bmap[x] = 4 - bmap[x]; else { mask = y & 1 ? 0x55 : 0xAA; for ( x = 0; x < Bit.cols; ++x ) bmap[x] ^= mask; } } else { toggle = y & 1; if ( gray_render ) { for ( x = xoffset % zoom_factor; x < Bit.cols; x += zoom_factor ) if ( ( x & 1 ) == toggle ) bmap[x] = 4 - bmap[x]; } else { /* tricky business */ shift = xoffset % zoom_factor; for ( x = 0; x < Bit.cols; ++x ) { for ( mask = 0; shift < 8; shift += zoom_factor ) if ( ( shift & 1 ) == toggle ) mask |= 0x80 >> shift; bmap[x] ^= mask; shift -= 8; } } } bmap += Bit.cols; } } static int Process_Event( TEvent* event ) { switch ( event->what ) { case event_Quit: /* ESC or q */ return 0; case event_Keyboard: if ( event->info == 'h' ) /* Toggle hinting */ hinted = !hinted; break; case event_Rotate_Glyph: rotation = ( rotation + event->info ) & 1023; break; case event_Scale_Glyph: ptsize += event->info; if ( ptsize < 1 ) ptsize = 1; if ( ptsize > MAXPTSIZE / zoom_factor ) ptsize = MAXPTSIZE / zoom_factor; break; case event_Change_Glyph: if ( use_cmap ) { if ( event->info < 0 ) { if ( Code > -event->info ) Code += event->info; else Code = 0; for ( ; Code >= 0; Code-- ) { Num = TT_Char_Index( char_map, Code ); if ( Num > 0 ) break; } } else { if ( Code < 65536 - event->info - 1 ) Code += event->info; else Code = 65536 - 1; for ( ; Code < 65536; Code++ ) { Num = TT_Char_Index( char_map, Code ); if ( Num > 0 ) break; } } } else { if ( event->info < 0 ) { if ( Num > -event->info ) Num += event->info; else Num = 0; } else { if ( Num < num_glyphs - event->info - 1 ) Num += event->info; else Num = num_glyphs - 1; } } break; } return 1; } void usage( char* execname ) { printf( "\n" ); printf( "ftzoom: simple TrueType glyph viewer -- part of the FreeType project\n" ); printf( "--------------------------------------------------------------------\n" ); printf( "\n" ); printf( "Usage: %s [options below] fontname[.ttf|.ttc]\n", execname ); printf( "\n" ); printf( " -g gray-level rendering (default: none)\n" ); printf( " -r R use resolution R dpi (default: 96)\n" ); printf( " -z Z Z:1 magnification (default: 1:1)\n" ); printf( " -p id platform id (default: none)\n" ); printf( " -e id encoding id (default: none)\n" ); printf( " -n don't use the `post' table\n" ); printf( " If either -p or -e is not set, no cmap will be used.\n" ); printf( "\n" ); exit( EXIT_FAILURE ); } /* stack check dtp */ int main( int argc, char** argv ) { int i; int platform = -1, encoding = -1; char filename[128 + 4]; char alt_filename[128 + 4]; char* execname; int option; int res = 96; TT_Error error; TT_Post post; TEvent event; execname = argv[0]; gray_render = 0; #ifdef DEBUG_LEVEL_TRACE set_tt_trace_levels( trace_raster, 7 ); set_tt_trace_levels( trace_gload, 7 ); #endif while ( 1 ) { option = ft_getopt( argc, argv, "e:gnp:r:z:" ); if ( option == -1 ) break; switch ( option ) { case 'e': encoding = atoi( ft_optarg ); break; case 'g': gray_render = 1; break; case 'n': use_post = 0; break; case 'p': platform = atoi( ft_optarg ); break; case 'r': res = atoi( ft_optarg ); if ( res < 1 ) usage( execname ); break; case 'z': zoom_factor = atoi( ft_optarg ); if ( zoom_factor < 1 || zoom_factor > 16 ) usage( execname ); if ( zoom_factor > 4 ) grid = 1; break; default: usage( execname ); break; } } if ( ft_optind == argc ) usage( execname ); i = strlen( argv[ft_optind] ); while ( i > 0 && argv[ft_optind][i] != '\\' && argv[ft_optind][i] != '/' ) { if ( argv[ft_optind][i] == '.' ) i = 0; i--; } filename[128] = '\0'; alt_filename[128] = '\0'; strncpy( filename, argv[ft_optind], 128 ); strncpy( alt_filename, argv[ft_optind], 128 ); if ( i >= 0 ) { strncpy( filename + strlen( filename ), ".ttf", 4 ); strncpy( alt_filename + strlen( alt_filename ), ".ttc", 4 ); } if ( platform >= 0 || encoding >= 0 ) use_cmap = 1; /* Initialization */ TT_Init_FreeType( &engine ); /* Initialization of the post extension */ if ( use_post ) TT_Init_Post_Extension( engine ); /* Load face */ error = TT_Open_Face( engine, filename, &face ); if ( error == TT_Err_Could_Not_Open_File ) { strcpy( filename, alt_filename ); error = TT_Open_Face( engine, alt_filename, &face ); } if ( error == TT_Err_Could_Not_Open_File ) Panic( "Could not find/open %s.\n", filename ); else if ( error ) Panic( "Error while opening %s, error code = 0x%x.\n", filename, error ); /* get face properties and allocate preload arrays */ TT_Get_Face_Properties( face, &properties ); num_glyphs = properties.num_Glyphs; xcenter_upem = (properties.header->xMax - properties.header->xMin) / 2; ycenter_upem = (properties.header->yMax - properties.header->yMin) / 2; units_per_em = properties.header->Units_Per_EM; /* load full post table */ if ( use_post ) { error = TT_Load_PS_Names( face, &post ); if ( error ) Panic( "Could not load PS names.\n" ); } /* create glyph */ error = TT_New_Glyph( face, &glyph ); if ( error ) Panic( "Could not create glyph container.\n" ); /* create instance */ error = TT_New_Instance( face, &instance ); if ( error ) Panic( "Could not create instance for %s.\n", filename ); error = TT_Set_Instance_Resolutions( instance, res, res ); if ( error ) Panic( "Could not set device resolutions." ); if ( gray_render ) { if ( !SetGraphScreen( Graphics_Mode_Gray ) ) Panic( "Could not set up grayscale graphics mode.\n" ); TT_Set_Raster_Gray_Palette( engine, gray_palette ); } else { if ( !SetGraphScreen( Graphics_Mode_Mono ) ) Panic( "Could not set up mono graphics mode.\n" ); } Init_Raster_Area(); old_ptsize = ptsize = 150 / zoom_factor; old_rotation = rotation = 0; Reset_PtSize ( ptsize ); Reset_Rotation( rotation ); if ( use_cmap ) { unsigned short num_cmap; unsigned short cmap_plat; unsigned short cmap_enc; num_cmap = properties.num_CharMaps; for ( i = 0; i < num_cmap; i++ ) { error = TT_Get_CharMap_ID( face, i, &cmap_plat, &cmap_enc ); if ( error ) Panic( "Cannot query cmap, error = 0x%x.\n", error ); if ( cmap_plat == platform && cmap_enc == encoding ) break; } if ( i == num_cmap ) Panic( "Invalid platform and/or encoding ID.\n" ); error = TT_Get_CharMap( face, i, &char_map ); if ( error ) Panic( "Cannot load cmap, error = 0x%x.\n", error ); num_glyphs = (1L << 16) - 1; } Code = 0; Num = 0; Fail = 0; for ( ;; ) { char *glyphname; glyphname = NULL; ClearData(); if ( ptsize != old_ptsize ) { Reset_PtSize( ptsize ); old_ptsize = ptsize; } if ( rotation != old_rotation ) { Reset_Rotation( rotation ); old_rotation = rotation; } if ( (error = LoadTrueTypeChar( Num, hinted )) == TT_Err_Ok ) { ConvertRaster(); if ( grid ) DrawGrid(); if ( use_post ) (void)TT_Get_PS_Name(face, Num, &glyphname); if ( use_cmap ) sprintf( Header, "\"%s\": index = %3d, code = 0x%x, hinting = %s", use_post ? glyphname : "", Num, Code, hinted ? "ON" : "OFF" ); else sprintf( Header, "\"%s\": index = %3d, hinting = %s", use_post ? glyphname : "", Num, hinted ? "ON" : "OFF" ); } else { Fail++; sprintf( Header, "\"%s\": index = %3d, hinting = %s (ERROR 0x%lx)", glyphname ? glyphname : "", Num, hinted ? "ON" : "OFF", error ); } Display_Bitmap_On_Screen( Bit.bitmap, Bit.rows, Bit.cols ); #ifndef X11 #ifndef OS2 Print_XY( 0, 0, Header ); #endif #endif Get_Event( &event ); if ( !Process_Event( &event ) ) goto End; } End: RestoreScreen(); TT_Done_FreeType( engine ); printf( "Fails = %d.\n", Fail ); exit( EXIT_SUCCESS ); /* for safety reasons */ return 0; /* never reached */ } /* End */