www.pudn.com > ilib > IFontBDF.c
/* ** Routines for reading in a BDF (font) file. ** BDF files can be obtained as part of the X Windows System ** at ftp://ftp.x.org/ ** ** Copyright 1999 Craig Knudsen ** ** 12-Apr-1999 Craig Knudsen cknudsen@radix.net ** Added support for high ascii characters. ** (This has disabled usage of the escape sequences like ** "\033agrave".) ** 17-May-1996 Craig Knudsen cknudsen@radix.net ** Created */ #include#include #include #include #include #include #include #include "Ilib.h" #include "IlibP.h" #include "IFontBDF.h" #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE 1 #endif /* ** Define the BDF translations into standard ASCII. ** Note we will still handle non-ASCII characters. ** Use "\033agrave;" to get the agrave symbol. */ typedef struct { char *name; unsigned char value; } char_translation; char_translation translation[] = { { "space", ' ' }, { "exclam", '!' }, { "quotedbl", '\"' }, { "numbersign", '#' }, { "dollar", '$' }, { "percent", '%' }, { "ampersand", '&' }, { "quoteright", '\'' }, { "parenleft", '(' }, { "parenright", ')' }, { "asterisk", '*' }, { "plus", '+' }, { "comma", ',' }, { "minus", '-' }, { "period", '.' }, { "slash", '/' }, { "zero", '0' }, { "one", '1' }, { "two", '2' }, { "three", '3' }, { "four", '4' }, { "five", '5' }, { "six", '6' }, { "seven", '7' }, { "eight", '8' }, { "nine", '9' }, { "colon", ':' }, { "semicolon", ';' }, { "less", '<' }, { "equal", '=' }, { "greater", '>' }, { "question", '?' }, { "at", '@' }, { "bracketleft", '[' }, { "backslash", '\\' }, { "bracketright", ']' }, { "asciicircum", '^' }, { "underscore", '_' }, { "quoteleft", '`' }, { "braceleft", '{' }, { "bar", '|' }, { "braceright", '}' }, { "asciitilde", '~' }, { NULL, '\0' }, }; static char *trans_table[256]; typedef struct { char *name; /* translated name ("A", "B", "\033agrave;") */ unsigned int *data; /* character definition */ unsigned int width; /* character width */ unsigned int height; /* height (size of lines array) */ unsigned int actual_width; /* width with padding on left and right */ int xoffset; /* pixels to move to the right before drawing */ int yoffset; /* pixels to move to up before drawing */ } Char; typedef struct { char *name; /* font name */ char *family; /* font family ("Times") */ char *face_name; /* face name ("Times Roman") */ char *width_name; /* face name ("Normal") */ char *weight; /* font weight ("R") */ int proportional; /* yes or no? (fixed/proportional font) */ int pixel_size; int font_ascent; int font_descent; Char *chars[256]; /* list of chars */ Char **other_chars; /* non ASCII chars */ unsigned int num_other_chars; /* size of above array */ } Font; static Font **fonts = NULL; static int num_fonts = 0; IError IFontBDFReadFile ( name, path ) char *name; char *path; { struct stat buf; FILE *fp; char text[256]; IError ret; char **lines; int num_lines = 0, loop; if ( stat ( path, &buf ) == 0 ) { fp = fopen ( path, "r" ); if ( !fp ) return ( INoSuchFile ); lines = malloc ( 1 ); while ( fgets ( text, 256, fp ) ) { lines = realloc ( lines, ( num_lines + 1 ) * sizeof ( char * ) ); if ( text[strlen(text)-1] == '\012' ) text[strlen(text)-1] = '\0'; if ( text[strlen(text)-1] == '\015' ) text[strlen(text)-1] = '\0'; lines[num_lines] = (char *) malloc ( strlen ( text ) + 1 ); strcpy ( lines[num_lines++], text ); } fclose ( fp ); lines = realloc ( lines, ( num_lines + 1 ) * sizeof ( char * ) ); lines[num_lines++] = NULL; ret = IFontBDFReadData ( name, lines ); for ( loop = 0; lines[loop]; loop++ ) free ( lines[loop] ); free ( lines ); return ( ret ); } else { fprintf ( stderr, "Cannot find font file: %s\n", path ); return ( INoSuchFile ); } } IError IFontBDFReadData ( name, lines ) char *name; char **lines; { char ch[256], *text; int temp; int in_bitmap = 0, hexval; int loop, which_char, which_bit; int num_ret; char c; Font *font; Char *character; int xpos, ypos; static int first = 1; int line_no = 0; /* Initialize a few things the first time this is called */ if ( first ) { first = 0; memset ( trans_table, '\0', sizeof ( trans_table ) ); for ( loop = 0; translation[loop].name; loop++ ) { trans_table[translation[loop].value] = translation[loop].name; } } font = (Font *) malloc ( sizeof ( Font ) ); memset ( font, '\0', sizeof ( Font ) ); font->name = (char *) malloc ( strlen ( name ) + 1 ); strcpy ( font->name, name ); memset ( font->chars, '\0', sizeof ( font->chars ) ); font->other_chars = malloc ( 4 ); while ( lines[line_no] ) { text = lines[line_no]; if ( strncmp ( text, "STARTCHAR", 9 ) == 0 ) { strcpy ( ch, text + 10 ); for ( loop = 0; translation[loop].name; loop++ ) { if ( strcmp ( translation[loop].name, ch ) == 0 ) { ch[0] = translation[loop].value; ch[1] = '\0'; break; } } in_bitmap = 0; character = (Char *) malloc ( sizeof ( Char ) ); memset ( character, '\0', sizeof ( Char ) ); num_ret = 1; character->name = (char *) malloc ( strlen ( ch ) + 1 ); strcpy ( character->name, ch ); } else if ( strncmp ( text, "ENCODING", 8 ) == 0 ) { temp = atoi ( text + 9 ); if ( temp > 0 && temp < 256 && character != NULL ) { sprintf ( ch, "%c", temp ); strcpy ( character->name, ch ); } } else if ( strncmp ( text, "PIXEL_SIZE", 10 ) == 0 ) { font->pixel_size = atoi ( text + 11 ); } else if ( strncmp ( text, "FONT_ASCENT", 11 ) == 0 ) { font->font_ascent = atoi ( text + 12 ); } else if ( strncmp ( text, "FONT_DESCENT", 12 ) == 0 ) { font->font_descent = atoi ( text + 13 ); } else if ( strncmp ( text, "SPACING", 7 ) == 0 ) { if ( strncmp ( text + 8, "\"P\"", 3 ) == 0 ) font->proportional = TRUE; else font->proportional = FALSE; } else if ( strncmp ( text, "FACE_NAME", 9 ) == 0 ) { font->face_name = (char *) malloc ( strlen ( text + 10 ) + 1 ); strcpy ( font->face_name, text + 10 ); } else if ( strncmp ( text, "SETWIDTH_NAME", 13 ) == 0 ) { font->width_name = (char *) malloc ( strlen ( text + 14 ) + 1 ); strcpy ( font->width_name, text + 14 ); } else if ( strncmp ( text, "BBX", 3 ) == 0 ) { sscanf ( text, "BBX %d %d %d %d", &character->width, &character->height, &character->xoffset, &character->yoffset ); /* use the width and height to allocate space for the data */ character->data = (unsigned int *) calloc ( character->height * character->width, sizeof ( int ) ); } else if ( strncmp ( text, "DWIDTH", 6 ) == 0 ) { sscanf ( text, "DWIDTH %d %d", &character->actual_width, &temp ); } else if ( strcmp ( text, "BITMAP" ) == 0 ) { /* if ( character->width <= 0 || character->height <= 0 ) { fprintf ( stderr, "BBX line not found. (line %d)\n", line_no + 1 ); return ( IFontError ); } */ in_bitmap = 1; xpos = ypos = 0; } else if ( strcmp ( text, "ENDCHAR" ) == 0 ) { if ( in_bitmap ) { in_bitmap = 0; if ( ! character ) { return ( IFontError ); } if ( strlen ( character->name ) == 1 ) font->chars[(unsigned char)character->name[0]] = character; else { font->other_chars = (Char **) realloc ( font->other_chars, ( font->num_other_chars + 1 ) * sizeof ( Char * ) ); font->other_chars[font->num_other_chars++] = character; } } /* for ( loop = 0; loop < character->width * character->height; loop++ ) { if ( character->data[loop] ) printf ( "+" ); else printf ( "-" ); } printf ( "\n-------------------\n" ); */ } else if ( in_bitmap ) { xpos = 0; for ( loop = 0; loop < character->width; loop++ ) { which_char = loop / 4; c = text[which_char]; if ( isdigit ( c ) ) hexval = (int) ( c - '0' ); else hexval = (int) ( c - 'A' ) + 10; which_bit = 3 - ( loop % 4 ); if ( hexval & ( 1 << which_bit ) ) { character->data[ypos * character->width + xpos] = 1; /*printf ( "X" );*/ } else { character->data[ypos * character->width + xpos] = 0; /*printf ( " " );*/ } xpos++; } ypos++; /*printf ( "\n" );*/ } line_no++; } /* Now add this font to the tree of loaded fonts */ if ( ! fonts ) fonts = (Font **) malloc ( sizeof ( Font * ) ); else fonts = (Font **) realloc ( fonts, ( num_fonts + 1 ) * sizeof ( Font * ) ); fonts[num_fonts++] = font; /* return success */ return ( INoError ); } Font *_IGetFont ( name ) char *name; { int loop; if ( num_fonts ) { for ( loop = 0; loop < num_fonts; loop++ ) { if ( fonts[loop] ) { if ( strcmp ( fonts[loop]->name, name ) == 0 ) return ( (Font *)fonts[loop] ); } } } return ( NULL ); } static void free_character ( ch ) Char *ch; { free ( ch->name ); free ( ch->data ); free ( ch ); } IError IFontBDFFree ( name ) char *name; { Font *font; unsigned int loop; font = _IGetFont ( name ); if ( ! font ) return ( INoSuchFont ); for ( loop = 0; loop < 256; loop++ ) { if ( font->chars[loop] ) free_character ( font->chars[loop] ); } for ( loop = 0; loop < font->num_other_chars; loop++ ) { free_character ( font->other_chars[loop] ); } free ( font->other_chars ); if ( font->name ) free ( font->name ); if ( font->family ) free ( font->family ); if ( font->face_name ) free ( font->face_name ); if ( font->width_name ) free ( font->width_name ); if ( font->weight ) free ( font->weight ); free ( font ); return ( INoError ); } IError _IFontBDFGetSize ( name, height_return ) char *name; unsigned int *height_return; { Font *font; font = _IGetFont ( name ); if ( ! font ) return ( INoSuchFont ); *height_return = font->pixel_size; return ( INoError ); } IError IFontBDFGetChar ( name, ch, bitdata, width, height, actual_width, size, xoffset, yoffset ) char *name; char *ch; unsigned int **bitdata; unsigned int *height; unsigned int *width; unsigned int *actual_width; unsigned int *size; int *xoffset; int *yoffset; { Font *font; Char *character = NULL; unsigned int loop; static char *last_name = NULL; static Font *last_font = NULL; if ( ! ch || ! strlen ( ch ) ) return ( IInvalidArgument ); if ( last_name == name ) { font = last_font; } else { font = _IGetFont ( name ); if ( ! font ) return ( INoSuchFont ); last_name = name; last_font = font; } /* we got the font. now get the character */ if ( strlen ( ch ) == 1 ) { character = font->chars[(unsigned char)ch[0]]; } /* if more than a single char, must not be in the ascii list */ else { for ( loop = 0, character = NULL; loop < font->num_other_chars; loop++ ) { if ( strcmp ( ch, font->other_chars[loop]->name ) == 0 ) { character = font->other_chars[loop]; break; } } if ( ! character ) character = font->chars[' ']; } /* if still not there, use space */ if ( ! character ) { /* This should not happen if font is defined correctly */ return ( IFontError ); } *height = character->height; *width = character->width; *actual_width = character->actual_width; *size = font->pixel_size; *xoffset = character->xoffset; *yoffset = character->yoffset; *bitdata = character->data; return ( INoError ); }