home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: SysTools
/
SysTools.zip
/
ft-beta.zip
/
freetype
/
test
/
ftstring.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-10-06
|
19KB
|
726 lines
/****************************************************************************/
/* */
/* The FreeType project -- a free and portable quality TrueType renderer. */
/* */
/* Copyright 1996, 1997 by */
/* D. Turner, R.Wilhelm, and W. Lemberg */
/* */
/* FTString : Making string text from individual glyph indormation */
/* This program makes use of FreeType's kerning extension */
/* */
/* 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 */
/* */
/* n : go to next (or last) .ttf file */
/* p : go to previous (or first) .ttf file */
/* */
/* h : toggle hinting */
/* */
/* ESC : exit */
/* */
/* */
/* NOTE: This is just a test program that is used to show off and */
/* debug the current engine. */
/* */
/****************************************************************************/
#ifdef ARM
#include "std.h"
#include "graflink.h"
#endif
#include "freetype.h"
#include "ftxkern.h"
#include "tterror.h" /* for Panic() and Message() only */
#include "ft_conf.h"
/* This is needed to have getopt() and getind() */
/* working on Solaris. We should be able to remove */
/* this line on other platforms... */
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
/* getopt() should be in either getopt.h, stdlib.h, or unistd.h */
/* The following is needed before the #include <unistd.h> */
/* with my school's Suns to have 'getopt' working - DavidT */
#if defined(__sun__)
#define __EXTENSIONS__
#endif
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#else
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#endif
#include "gmain.h"
#include "gevents.h"
#include "gdriver.h"
#ifdef ARM
#include "armsup.c" /* pull in our routines */
#endif
/* The SunOS header files do not provide external declarations for optarg() */
/* and optind(), so declare them here if necessary. A check to see if the */
/* GNU C library is being used on SunOS should be added at some point. If */
/* The GNU C library is being used, these declarations are not necessary. */
#if defined(__sun__) && !defined(SVR4) && !defined(__SVR4)
extern char* optarg;
extern int optind;
#endif
#define Pi 3.1415926535
#define MAXPTSIZE 500 /* dtp */
#define Center_X ( Bit.width / 2 ) /* dtp */
#define Center_Y ( Bit.rows / 2 ) /* dtp */
char Header[128];
TT_Face face;
TT_Instance instance;
TT_Glyph glyph;
TT_CharMap char_map;
TT_Glyph_Metrics metrics;
TT_Glyph_Outline outline;
TT_Face_Properties properties;
TT_Instance_Metrics imetrics;
int num_glyphs;
int ptsize;
int hinted;
TT_Raster_Map Bit;
TT_Raster_Map Small_Bit; /* used when font-smoothing is enabled */
int Rotation;
int Fail;
int Num;
unsigned char autorun;
int gray_render;
static void ClearData();
extern char* basename( char* );
char palette[5] = { 0, 1, 2, 3, 4 };
/* Or-ing the possible palette values gets us from 0 to 7 */
/* We must bound check these.. */
const char bounded_palette[8] = { 0, 1, 2, 3, 4, 4, 4, 4 };
short glyph_code[128];
int num_codes;
static void Set_Raster_Area()
{
Bit.rows = vio_Height; /* The whole window */
Bit.width = vio_Width & -4;
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 */
}
}
static int Init_Engine()
{
Set_Raster_Area(); /* set up maximum raster size */
Bit.bitmap = (void*)malloc( (int)Bit.size );
if ( !Bit.bitmap )
Panic( "ERROR: Not enough memory to allocate bitmap!\n" );
ClearData();
return 0;
}
static void ClearData()
{
memset( Bit.bitmap, 0, Bit.size );
}
static void ClearSmall()
{
memset( Small_Bit.bitmap, 0, Small_Bit.size );
}
static void CharToUnicode( char* source )
{
int i, n;
short platform, encoding;
/* First, look for a Unicode charmap */
n = TT_Get_CharMap_Count( face );
for ( i = 0; i < n; i++ )
{
TT_Get_CharMap_ID( face, i, &platform, &encoding );
if ( (platform == 3 && encoding == 1 ) ||
(platform == 0 && encoding == 0 ) )
{
TT_Get_CharMap( face, i, &char_map );
i = n+1;
}
}
if ( i == n )
Panic( "Sorry, but this font doesn't contain any Unicode mapping table\n" );
for ( n = 0; n < 128 && source[n]; n++ )
glyph_code[n] = TT_Char_Index( char_map, (short)source[n] );
num_codes = n;
}
static void ConvData()
{
unsigned char* p;
int i;
if ( gray_render )
{
p = Bit.bitmap;
for ( i = 0; i < Bit.size; i++ )
{
*p = gray_palette[(int)bounded_palette[*p]];
p++;
}
}
}
static TT_Error Reset_Scale( int pointSize )
{
TT_Error error;
if ( (error = TT_Set_Instance_PointSize( instance, pointSize )) )
{
RestoreScreen();
Message( "error = %d\n", error );
Panic( "could not reset instance\n" );
}
TT_Get_Instance_Metrics( instance, &imetrics );
/* now re-allocates the small bitmap */
if ( gray_render )
{
Small_Bit.rows = imetrics.y_ppem + 32;
Small_Bit.width = imetrics.x_ppem + 32;
Small_Bit.cols = (Small_Bit.width+3) & -4; /* pad */
Small_Bit.flow = TT_Flow_Up;
Small_Bit.size = Small_Bit.rows * Small_Bit.cols;
if ( Small_Bit.bitmap )
free( Small_Bit.bitmap );
Small_Bit.bitmap = malloc( (int)Small_Bit.size );
ClearSmall();
}
return TT_Err_Ok;
}
static TT_Error LoadTrueTypeChar( int idx, int hint )
{
int flags;
flags = TTLOAD_SCALE_GLYPH;
if ( hint )
flags |= TTLOAD_HINT_GLYPH;
return TT_Load_Glyph( instance, glyph, idx, flags );
}
static TT_Error ConvertRaster( int x_offset, int y_offset )
{
if ( !gray_render )
return TT_Get_Glyph_Bitmap( glyph, &Bit, x_offset*64, y_offset*64 );
else
{
TT_Error error;
TT_F26Dot6 x, y, xmin, ymin, xmax, ymax;
int ioff, iread;
char *off, *read, *_off, *_read;
/* grid-fit the bounding box */
xmin = metrics.xMin & -64;
ymin = metrics.yMin & -64;
xmax = (metrics.xMax + 63) & -64;
ymax = (metrics.yMax + 63) & -64;
/* now render the glyph in the small pixmap */
ClearSmall();
error = TT_Get_Glyph_Pixmap( glyph, &Small_Bit, -xmin, -ymin );
if ( error )
return error;
/* Blit-or the resulting small pixmap into the biggest one */
xmin = xmin/64 + x_offset;
ymin = ymin/64 + y_offset;
xmax = xmax/64 + x_offset;
ymax = ymax/64 + y_offset;
/* take care of comparing xmin and ymin with signed values ! */
/* this was the cause of strange misplacements */
if ( xmin >= (int)Bit.width ||
ymin >= (int)Bit.rows ||
xmax < 0 ||
ymax < 0 )
return TT_Err_Ok;
/* in exotic glyphs, the bounding box maybe larger than the size */
/* of the small pixmap.. take care of that here */
if ( xmax-xmin+1 > Small_Bit.width )
xmax = xmin + Small_Bit.width-1;
if ( ymax-ymin+1 > Small_Bit.rows )
ymax = ymin + Small_Bit.rows-1;
/* this got rid of the 'invalid grayshade error' which */
/* were caused by pixmap overruns.. */
iread = 0;
if ( ymin < 0 )
{
iread -= ymin * Small_Bit.cols;
ioff = 0;
ymin = 0;
}
else
ioff = ymin * Bit.cols;
if ( ymax >= Bit.rows )
ymax = Bit.rows - 1;
if ( xmin < 0 )
{
iread -= xmin;
xmin = 0;
}
else
ioff += xmin;
if ( xmax >= Bit.width )
xmax = Bit.width - 1;
_read = (char*)Small_Bit.bitmap + iread;
_off = (char*)Bit.bitmap + ioff;
for ( y = ymin; y <= ymax; y++ )
{
read = _read;
off = _off;
for ( x = xmin; x <= xmax; x++ )
{
*off |= *read;
off++;
read++;
}
_read += Small_Bit.cols;
_off += Bit.cols;
}
return TT_Err_Ok;
}
}
static TT_Error Render_All()
{
TT_F26Dot6 x, y, z, minx, miny, maxx, maxy;
int i;
TT_Error error;
/* On the first pass, we compute the compound bounding box */
x = y = 0;
minx = miny = maxx = maxy = 0;
for ( i=0; i < num_codes; i++ )
{
if ( !(error = LoadTrueTypeChar( glyph_code[i], hinted )) )
{
TT_Get_Glyph_Metrics( glyph, &metrics );
z = x + metrics.xMin;
if ( minx > z )
minx = z;
z = x + metrics.yMax;
if ( maxx < z )
maxx = z;
z = y + metrics.yMin;
if ( miny > z )
miny = z;
z = y + metrics.yMax;
if ( maxy < z )
maxy = z;
x += metrics.advanceWidth & -64;
}
else
Fail++;
}
/* We now center the bbox inside the target bitmap */
minx = ( minx & -64 ) >> 6;
miny = ( miny & -64 ) >> 6;
maxx = ( (maxx+63) & -64 ) >> 6;
maxy = ( (maxy+63) & -64 ) >> 6;
maxx -= minx;
maxy -= miny;
minx = (Bit.width - maxx)/2;
miny = (Bit.rows + miny)/2;
maxx += minx;
maxy += maxy;
/* On the second pass, we render each glyph to its centered position */
/* This is slow, because we reload each glyph to render it ! */
x = minx;
y = miny;
for ( i = 0; i < num_codes; i++ )
{
if ( !(error = LoadTrueTypeChar( glyph_code[i], hinted )) )
{
TT_Get_Glyph_Metrics( glyph, &metrics );
ConvertRaster( x, y );
x += metrics.advanceWidth/64;
}
}
return TT_Err_Ok;
}
static int Process_Event( TEvent* event )
{
switch ( event->what )
{
case event_Quit: /* ESC or q */
return 0;
case event_Keyboard:
if ( event->info == 'n' ) /* Next file */
return 'n';
if ( event->info == 'p' ) /* Previous file */
return 'p';
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 ) ptsize = MAXPTSIZE;
break;
case event_Change_Glyph:
Num += event->info;
if ( Num < 0 ) Num = 0;
if ( Num >= num_glyphs ) Num = num_glyphs - 1;
break;
}
return 1;
}
static void usage( char* execname )
{
Message( "\n" );
Message( "String: simple String Test Display - part of the FreeType project\n" );
Message( "-----------------------------------------------------------------\n" );
Message( "\n" );
Message( "Usage: %s [options below] ppem fontname[.ttf|.ttc] string\n",
execname );
Message( "\n" );
Message( " -g gray-level rendering (default: none)\n" );
Message( "\n" );
exit( 1 );
}
int main( int argc, char** argv )
{
int i, old_ptsize, orig_ptsize, file;
int XisSetup = 0;
char filename[128 + 4];
char alt_filename[128 + 4];
char* execname;
int option;
TT_Error error;
TEvent event;
execname = argv[0];
while ( 1 )
{
option = getopt( argc, argv, "gf:r:" );
if ( option == -1 )
break;
switch ( option )
{
case 'g':
gray_render = 1;
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 */
if ( (error = TT_Init_FreeType()) )
Panic( "ERROR: While initializing engine, code = %d\n", error );
NewFile:
ptsize = orig_ptsize;
hinted = 1;
i = strlen( argv[file] );
while ( i > 0 && argv[file][i] != '\\' && argv[file][i] != '/' )
{
if ( argv[file][i] == '.' )
i = 0;
i--;
}
filename[128] = '\0';
alt_filename[128] = '\0';
strncpy( filename, argv[file], 128 );
strncpy( alt_filename, argv[file], 128 );
if ( i >= 0 )
{
strncpy( filename + strlen( filename ), ".ttf", 4 );
strncpy( alt_filename + strlen( alt_filename ), ".ttc", 4 );
}
/* Load face */
error = TT_Open_Face( filename, &face );
if ( error == TT_Err_Could_Not_Open_File )
{
strcpy( filename, alt_filename );
error = TT_Open_Face( alt_filename, &face );
}
if ( error )
Panic( "ERROR: could not find/open %s\n", filename );
/* get face properties and allocate preload arrays */
TT_Get_Face_Properties( face, &properties );
num_glyphs = properties.num_Glyphs;
/* create glyph */
error = TT_New_Glyph( face, &glyph );
if ( error )
Panic( "ERROR: could not create glyph container\n" );
/* create instance */
error = TT_New_Instance( face, &instance );
if ( error )
Panic( "ERROR: could not create instance for %s\n", filename );
error = TT_Set_Instance_Resolution( instance, 96, 96 );
if ( error )
Panic( "ERROR: could not set device resolutions" );
if ( !XisSetup )
{
XisSetup = 1;
if ( gray_render )
{
if ( !SetGraphScreen( Graphics_Mode_Gray ) )
Panic( "ERROR: could not set up grayscale graphics mode\n" );
TT_Set_Raster_Gray_Palette( palette );
}
else
{
if ( !SetGraphScreen( Graphics_Mode_Mono ) )
Panic( "ERROR: could not set up mono graphics mode\n" );
}
}
Init_Engine();
Reset_Scale( ptsize );
old_ptsize = ptsize;
Fail = 0;
Num = 0;
CharToUnicode( ( argv[2] ? argv[2] :
"The quick brown fox jumps over the lazy dog" ) );
for ( ;; )
{
int key;
Render_All();
ConvData();
sprintf( Header, "%s: Glyph: %4d ptsize: %4d hinting: %s",
basename( filename ), Num, ptsize,
hinted ? "on" : "off" );
#ifndef X11
#ifndef OS2
Print_XY( 0, 0, Header );
#endif
#endif
Display_Bitmap_On_Screen( Bit.bitmap, Bit.rows, Bit.cols );
ClearData();
Get_Event( &event );
if ( !( key = Process_Event( &event ) ) ) goto Fin;
if ( key == 'n' )
{
TT_Close_Face( face );
if ( file < argc - 1 )
file++;
goto NewFile;
}
if ( key == 'p' )
{
TT_Close_Face( face );
if ( file > 1 )
file--;
goto NewFile;
}
if ( ptsize != old_ptsize )
{
if ( Reset_Scale( ptsize ) )
Panic( "ERROR: could not resize font\n" );
old_ptsize = ptsize;
}
}
Fin:
RestoreScreen();
TT_Done_FreeType();
Message( "execution completed succesfully\n" );
Message( "fails = %d\n", Fail );
return 0;
}
/* End */