/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2007 Jonas Hurrelmann * * A command-line tool to convert ttf file to bitmap fonts * * All files in this archive are subject to the GNU General Public License. * See the file COPYING in the source tree root for full license agreement. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/ #include #include FT_FREETYPE_H #include FT_GLYPH_H #include #ifdef WIN32 #ifdef _MSC_VER #define snprintf _snprintf #endif #else #include #include #endif #include FT_SFNT_NAMES_H #include FT_TRUETYPE_TABLES_H #include /* * Set the default values used to generate a BDF font. */ #ifndef DEFAULT_PLATFORM_ID #define DEFAULT_PLATFORM_ID 3 #endif #ifndef DEFAULT_ENCODING_ID #define DEFAULT_ENCODING_ID 1 #endif #define ABS(x) (((x) < 0) ? -(x) : (x)) #define VERSION "RB12" /* * nameID macros for getting strings from the OT font. */ enum { BDFOTF_COPYRIGHT_STRING = 0, BDFOTF_FAMILY_STRING, BDFOTF_SUBFAMILY_STRING, BDFOTF_UNIQUEID_STRING, BDFOTF_FULLNAME_STRING, BDFOTF_VENDOR_STRING, BDFOTF_POSTSCRIPT_STRING, BDFOTF_TRADEMARK_STRING, }; /* * String names for the string indexes. Used for error messages. */ static char *string_names[] = { "\"Copyright\"", "\"Family\"", "\"SubFamily\"", "\"Unique ID\"", "\"Full Name\"", "\"Vendor\"", "\"Postscript Name\"", "\"Trademark\"" }; /* * The default platform and encoding ID's. */ static int pid = DEFAULT_PLATFORM_ID; static int eid = DEFAULT_ENCODING_ID; /* * A flag indicating if a CMap was found or not. */ static FT_UShort nocmap; int pct = 0; /* display ttc table if it is not zero. */ FT_Long max_char = 65535; int pixel_size = 15; FT_Long start_char = 0; FT_Long limit_char; FT_Long firstchar = 0; FT_Long lastchar; FT_Long ttc_index = -1; int flg_all_ttc = 0; short antialias = 1; /* smooth fonts with gray levels */ int oflag = 0; char outfile[1024]; float between_chr = 0.0f; float between_row = 0.0f; int hv_resolution = 60; int dump_glyphs = 0; int digits_equally_wide = 1; /* Try to make digits equally wide */ int trimming = 0; int trim_dp = 0; /* trim descent percent */ int trim_da = 0; /* trim descnet actual */ int trim_ap = 0; /* trim ascent precent */ int trim_aa = 0; /* trim ascent actual */ struct font_header_struct { char header[4]; /* magic number and version bytes */ unsigned short maxwidth; /* max width in pixels */ unsigned short height; /* height in pixels */ unsigned short ascent; /* ascent (baseline) height */ unsigned short depth; /* depth 0=1-bit, 1=4-bit */ unsigned long firstchar; /* first character in font */ unsigned long defaultchar; /* default character in font */ unsigned long size; /* # characters in font */ unsigned long nbits; /* # bytes imagebits data in file */ /* = bits_size */ FT_Long noffset; /* # longs offset data in file */ FT_Long nwidth; /* # bytes width data in file */ }; struct font_struct { struct font_header_struct header; unsigned char *chars_data; unsigned short *offset; FT_Long *offset_long; unsigned char *width; }; struct ttc_table{ FT_Long ttc_count; char **ttf_name; }; /* exit the program with given message */ static void panic( const char* message) { fprintf( stderr, "%s\n", message ); exit( 1 ); } static void arg_panic( const char* message, const char* arg ) { fprintf( stderr, "%s: %s\n", message, arg ); exit( 1 ); } static int writebyte(FILE *fp, unsigned char c) { return putc(c, fp) != EOF; } static int writeshort(FILE *fp, unsigned short s) { putc(s, fp); return putc(s>>8, fp) != EOF; } static int writeint(FILE *fp, unsigned int l) { putc(l, fp); putc(l>>8, fp); putc(l>>16, fp); return putc(l>>24, fp) != EOF; } static int writestr(FILE *fp, char *str, int count) { return (int)fwrite(str, 1, count, fp) == count; } /* print usage information */ void usage(void) { char help[] = { "Usage: convttf [options] [input-files]\n" " convttf [options] [-o output-file] [single-input-file]\n\n" " Default output-file : -.fnt.\n" " When '-ta' or '-tc' is specified in command line,\n " " default output-file is: \n" " -.fnt.\n" "Options:\n" " -s N Start output at character encodings >= N\n" " -l N Limit output to character encodings <= N\n" " -p N Font size N in pixel (default N=15)\n" " -c N Character separation in pixel.Insert space between lines.\n" " -x Trim glyphs horizontally of nearly empty space\n" " (to improve spacing on V's W's, etc.)\n" " -X Set the horizontal and vertical resolution (default: 60)\n" " -TA N Trim vertical ascent (N percent)\n" " -TD N Trim vertical descent (N percent)\n" " -Ta N Trim vertical ascent (N pixels)\n" " -Td N Trim vertical descent (N pixels)\n" " -r N Row separation in pixel.Insert space between characters\n" " -d Debug: print converted glyph images\n" " -tt Display the True Type Collection tables available in the font\n" " -t N Index of true type collection. It must be start from 0.(default N=0).\n" " -ta Convert all fonts in ttc (ignores outfile option)\n" " -w Don't try to make digits (0-9) equally wide\n" }; fprintf(stderr, "%s", help); exit( 1 ); } /* remove directory prefix and file suffix from full path*/ char *basename(char *path) { char *p, *b; static char base[256]; /* remove prepended path and extension*/ b = path; for (p=path; *p; ++p) { #ifdef WIN32 if (*p == '/' || *p == '\\') #else if (*p == '/') #endif b = p + 1; } strcpy(base, b); for (p=base; *p; ++p) { if (*p == '.') { *p = 0; break; } } return base; } void setcharmap(FT_Face face) { FT_Long i; /* * Get the requested cmap. */ for (i = 0; i < face->num_charmaps; i++) { if (face->charmaps[i]->platform_id == pid && face->charmaps[i]->encoding_id == eid) break; } if (i == face->num_charmaps && pid == 3 && eid == 1) { /* * Make a special case when this fails with pid == 3 and eid == 1. * Change to eid == 0 and try again. This captures the two possible * cases for MS fonts. Some other method should be used to cycle * through all the alternatives later. */ for (i = 0; i < face->num_charmaps; i++) { if (face->charmaps[i]->platform_id == pid && face->charmaps[i]->encoding_id == 0) break; } if (i < face->num_charmaps) { pid = 3; eid = 1; FT_Set_Charmap(face, face->charmaps[i]); } else { /* * No CMAP was found. */ nocmap = 1; pid = eid = -1; } } else { FT_Set_Charmap(face, face->charmaps[i]); nocmap = 0; } } /* * quote in otf2bdf. * A generic routine to get a name from the OT name table. This routine * always looks for English language names and checks three possibilities: * 1. English names with the MS Unicode encoding ID. * 2. English names with the MS unknown encoding ID. * 3. English names with the Apple Unicode encoding ID. * * The particular name ID mut be provided (e.g. nameID = 0 for copyright * string, nameID = 6 for Postscript name, nameID = 1 for typeface name. * * If the `dash_to_space' flag is non-zero, all dashes (-) in the name will be * replaced with the character passed. * * Returns the number of bytes added. */ static int otf_get_english_string(FT_Face face, int nameID, int dash_to_space, char *name, int name_size) { int j, encid; FT_UInt i, nrec; FT_SfntName sfntName; unsigned char *s = NULL; unsigned short slen = 0; nrec = FT_Get_Sfnt_Name_Count(face); for (encid = 1, j = 0; j < 2; j++, encid--) { /* * Locate one of the MS English font names. */ for (i = 0; i < nrec; i++) { FT_Get_Sfnt_Name(face, i, &sfntName); if (sfntName.platform_id == 3 && sfntName.encoding_id == encid && sfntName.name_id == nameID && (sfntName.language_id == 0x0409 || sfntName.language_id == 0x0809 || sfntName.language_id == 0x0c09 || sfntName.language_id == 0x1009 || sfntName.language_id == 0x1409 || sfntName.language_id == 0x1809)) { s = sfntName.string; slen = sfntName.string_len; break; } } if (i < nrec) { if (slen >> 1 >= name_size) { fprintf(stderr, "warning: %s string longer than buffer." "Truncating to %d bytes.\n", string_names[nameID], name_size); slen = name_size << 1; } /* * Found one of the MS English font names. The name is by * definition encoded in Unicode, so copy every second byte into * the `name' parameter, assuming there is enough space. */ for (i = 1; i < slen; i += 2) { if (dash_to_space) *name++ = (s[i] != '-') ? s[i] : ' '; else if (s[i] == '\r' || s[i] == '\n') { if (s[i] == '\r' && i + 2 < slen && s[i + 2] == '\n') i += 2; *name++ = ' '; *name++ = ' '; } else *name++ = s[i]; } *name = 0; return (slen >> 1); } } /* * No MS English name found, attempt to find an Apple Unicode English * name. */ for (i = 0; i < nrec; i++) { FT_Get_Sfnt_Name(face, i, &sfntName); if (sfntName.platform_id == 0 && sfntName.language_id == 0 && sfntName.name_id == nameID) { s = sfntName.string; slen = sfntName.string_len; break; } } if (i < nrec) { if (slen >> 1 >= name_size) { fprintf(stderr, "warning: %s string longer than buffer." "Truncating to %d bytes.\n", string_names[nameID], name_size); slen = name_size << 1; } /* * Found the Apple Unicode English name. The name is by definition * encoded in Unicode, so copy every second byte into the `name' * parameter, assuming there is enough space. */ for (i = 1; i < slen; i += 2) { if (dash_to_space) *name++ = (s[i] != '-') ? s[i] : ' '; else if (s[i] == '\r' || s[i] == '\n') { if (s[i] == '\r' && i + 2 < slen && s[i + 2] == '\n') i += 2; *name++ = ' '; *name++ = ' '; } else *name++ = s[i]; } *name = 0; return (slen >> 1); } return 0; } int get_ttc_table(char *path, struct ttc_table *ttcname ) { FT_Error err; FT_Library library; FT_Face face; FT_Long i; char xlfd[BUFSIZ]; /* init number of ttf in ttc */ ttcname->ttc_count = 0; /* Initialize engine */ if ( ( err = FT_Init_FreeType( &library ) ) != 0 ) { panic( "Error while initializing engine" ); return err; } /* Load face */ err = FT_New_Face( library, path, (FT_Long) 0, &face ); if ( err ) { arg_panic( "Could not find/open font", path ); return err; } ttcname->ttc_count = face->num_faces; ttcname->ttf_name = malloc( sizeof(char*) * ttcname->ttc_count); for(i = 0; i < ttcname->ttc_count; i++) { err = FT_New_Face( library, path, i, &face ); if ( err == FT_Err_Cannot_Open_Stream ) arg_panic( "Could not find/open font", path ); otf_get_english_string(face, BDFOTF_POSTSCRIPT_STRING, 0, xlfd, sizeof(xlfd)); ttcname->ttf_name[i] = malloc(sizeof(char) * (strlen(xlfd) + 1 )); strcpy(ttcname->ttf_name[i], xlfd); } return 0; } void print_ttc_table(char* path) { struct ttc_table ttcname; FT_Long i; get_ttc_table(path, &ttcname); printf("ttc header count = %ld \n\n", ttcname.ttc_count); printf("Encoding tables available in the true type collection\n\n"); printf("INDEX\tPOSTSCRIPT NAME\n"); printf("-----------------------------------------------------\n"); for(i = 0; i < ttcname.ttc_count; i++) { printf("%ld\t%s\n", i, ttcname.ttf_name[i]); } for(i = 0; i < ttcname.ttc_count; i++) { free(ttcname.ttf_name[i]); } printf("\n\n"); free(ttcname.ttf_name); return; } FT_Long getcharindex(FT_Face face, FT_Long code) { FT_Long idx; if (nocmap) { if (code >= face->num_glyphs) idx = 0; else idx = code; } else idx = FT_Get_Char_Index( face, code); if ( idx <= 0 || idx > face->num_glyphs) return 0; else return idx; } void print_raw_glyph( FT_Face face) { int pixel,row,col,width; width = face->glyph->metrics.width >> 6; printf("\n---Raw-Glyph---\n"); for(row=0; row < face->glyph->metrics.height >> 6; row++) { printf("_"); for(col=0; col < width; col++) { pixel = *(face->glyph->bitmap.buffer+width*row+col)/26; if ( pixel ) printf("%d",pixel); else printf(" "); } printf("_\n"); } printf("----End-----\n"); } int glyph_width( FT_Face face, FT_Long code, FT_Long digit_width ) { int width; if (code >= '0' && code <= '9' && digit_width) { width = digit_width; } else { int pitch, h_adv; unsigned spacing = (unsigned)(between_chr * (1<<6));/* convert to fixed point */ pitch = ABS(face->glyph->bitmap.pitch); h_adv = face->glyph->metrics.horiAdvance >> 6; width = (face->glyph->metrics.width + spacing) >> 6; if(pitch == 0) pitch = h_adv; if(width < pitch) width = pitch; } return width; } FT_Long check_digit_width( FT_Face face ) { FT_Long code; FT_Long last_advance = -1; for (code='0'; code <= '9'; ++code) { FT_Glyph_Metrics* metrics; FT_Load_Char(face, code, FT_LOAD_RENDER | FT_LOAD_NO_BITMAP); metrics = &face->glyph->metrics; if ((last_advance != -1 && last_advance != metrics->horiAdvance) || metrics->horiBearingX < 0) { last_advance = 0; break; } last_advance = metrics->horiAdvance; } return last_advance >> 6; } void trim_glyph( FT_GlyphSlot glyph, int *empty_first_col, int *empty_last_col, int *width ) { int row; int stride = glyph->bitmap.pitch; int end = stride-1; int trim_left = 2, trim_right = 2; const unsigned char limit = 64u; const unsigned char *image = glyph->bitmap.buffer; if (*width < 2) return; /* nothing to do? */ for(row=0; row< glyph->metrics.height >> 6; row++) { const unsigned char *column = image+row*stride; if (*column++ < limit && trim_left) { if (*column >= limit/2) trim_left = 1; } else trim_left = 0; column = image+row*stride+end; if (*column-- < limit && trim_right) { if (*column >= limit/2) trim_right = 1; } else trim_right = 0; } (*width) -= trim_left + trim_right; if (*width < 0) *width = 0; *empty_first_col = trim_left; *empty_last_col = trim_right; } void convttf(char* path, char* destfile, FT_Long face_index) { FT_Error err; FT_Library library; FT_Face face; int w,h; int row,col; int empty_first_col, empty_last_col; FT_Long charindex; FT_Long idx = 0; FT_Long code; FT_Long digit_width = 0; float extra_space; FT_Long char_count; char use_long_offset; int done = 0; char char_name[1024]; int converted_char_count = 0; int failed_char_count = 0; int depth = 2; unsigned char bit_shift = 1u << depth; unsigned char pixel_per_byte = CHAR_BIT / bit_shift; struct font_struct export_font; char pad[] = {0,0,0,0}; int skip,i; FILE *file; /* Initialize engine */ if ( ( err = FT_Init_FreeType( &library ) ) != 0 ) panic( "Error while initializing engine" ); /* Load face */ err = FT_New_Face( library, path, (FT_Long) face_index, &face ); if ( err == FT_Err_Cannot_Open_Stream ) arg_panic( "Could not find/open font\n", path ); else if ( err ) arg_panic( "Error while opening font\n", path ); setcharmap( face ); /* Set font header data */ export_font.header.header[0] = 'R'; export_font.header.header[1] = 'B'; export_font.header.header[2] = '1'; export_font.header.header[3] = '2'; #if 0 export_font.header.height = 0; export_font.header.ascent = 0; #endif extra_space = (float)(between_row-trim_aa-trim_da); FT_Set_Char_Size( face, 0, pixel_size << 6, hv_resolution, hv_resolution ); export_font.header.ascent = ((face->size->metrics.ascender*(100-trim_ap)/100) >> 6) - trim_aa; export_font.header.height = (((face->size->metrics.ascender*(100-trim_ap)/100) - (face->size->metrics.descender*(100-trim_dp)/100)) >> 6) + extra_space; printf("\n"); printf("Please wait, converting %s:\n", path); /* "face->num_glyphs" is NG.; */ if ( limit_char == 0 ) limit_char = max_char; if ( limit_char > max_char ) limit_char = max_char; char_count = 0; export_font.header.maxwidth = 1; export_font.header.depth = 1; firstchar = limit_char; lastchar = start_char; if (digits_equally_wide) digit_width = check_digit_width(face); /* calculate memory usage */ for(code = start_char; code <= limit_char ; code++ ) { charindex = getcharindex( face, code); if ( !(charindex) ) continue; err = FT_Load_Glyph( face, charindex, (FT_LOAD_RENDER | FT_LOAD_NO_BITMAP) ); if ( err ) continue; w = glyph_width( face, code, digit_width ); if (w == 0) continue; empty_first_col = empty_last_col = 0; if(trimming) trim_glyph( face->glyph, &empty_first_col, &empty_last_col, &w); if (export_font.header.maxwidth < w) export_font.header.maxwidth = w; char_count++; idx += (w*export_font.header.height + pixel_per_byte - 1)/pixel_per_byte; if (code >= lastchar) lastchar = code; if (code <= firstchar) firstchar = code; } export_font.header.defaultchar = firstchar; export_font.header.firstchar = firstchar; export_font.header.size = lastchar - firstchar + 1; export_font.header.nbits = idx; export_font.header.noffset = export_font.header.size; export_font.header.nwidth = export_font.header.size; /* check if we need to use long offsets */ use_long_offset = (export_font.header.nbits >= 0xFFDB ); /* allocate memory */ export_font.offset = NULL; export_font.offset_long = NULL; if (use_long_offset) export_font.offset_long = malloc( sizeof(FT_Long)* export_font.header.noffset ); else export_font.offset = malloc( sizeof(unsigned short)* export_font.header.noffset ); export_font.width = malloc( sizeof(unsigned char) * export_font.header.nwidth ); export_font.chars_data = malloc( sizeof(unsigned char) * export_font.header.nbits ); /* for now we use the full height for each character */ h = export_font.header.height; idx = 0; for( code = firstchar; code <= lastchar; code++ ) { FT_GlyphSlot slot; FT_Bitmap* source; unsigned char* src; unsigned char* tmpbuf; int start_y; int glyph_height; int stride; unsigned char* buf; unsigned char* endbuf; /* insert empty pixels on the left */ int col_off; int numbits; unsigned int field; /* Get gylph index from the char and render it */ charindex = getcharindex( face, code); if ( !charindex ) { if ( use_long_offset ) export_font.offset_long[code - firstchar] = export_font.offset_long[0]; else export_font.offset[code - firstchar] = export_font.offset[0]; export_font.width[code - firstchar] = export_font.width[0]; continue; } err = FT_Load_Glyph( face, charindex , (FT_LOAD_RENDER | FT_LOAD_NO_BITMAP) ); if ( err ) { continue; } if FT_HAS_GLYPH_NAMES( face ) FT_Get_Glyph_Name( face, charindex, char_name, 16); else char_name[0] = '\0'; slot = face->glyph; source = &slot->bitmap; #if 0 print_raw_glyph( face ); #endif w = glyph_width( face, code, digit_width ); if (w == 0) continue; empty_first_col = empty_last_col = 0; if(trimming) trim_glyph( face->glyph, &empty_first_col, &empty_last_col, &w ); if ( use_long_offset ) export_font.offset_long[code - firstchar] = idx; else export_font.offset[code - firstchar] = idx; export_font.width[code - firstchar] = w; /* copy the glyph bitmap to a full sized glyph bitmap */ src = source->buffer; tmpbuf = malloc(sizeof(unsigned char) * w * h); memset(tmpbuf, 0xff, w*h); start_y = export_font.header.ascent - slot->bitmap_top; glyph_height = source->rows; stride = source->pitch; buf = tmpbuf; endbuf = tmpbuf + w*h; err = 0; /* insert empty pixels on the left */ col_off = w - stride; if (col_off > 1) col_off /= 2; if (col_off < 0) col_off = 0; for(row=0; row < glyph_height; row++) { if(row+start_y < 0 || row+start_y >= h) continue; for(col = empty_first_col; col < stride; col++) { unsigned char *tsrc, *dst; dst = buf + (w*(start_y+row)) + col + col_off; tsrc = src + stride*row + col; if (dst < endbuf && dst >= tmpbuf) *dst = 0xff - *tsrc; else { err = 1; printf("Error! row: %3d col: %3d\n", row, col); } } } if(err) print_raw_glyph(face); buf = tmpbuf; field = 0; numbits = pixel_per_byte; for(row=0; row < h; row++) { for(col=0; col < w; col++) { unsigned int src2 = *buf++; unsigned int cur_col = (src2 + 8) / 17; field |= (cur_col << (bit_shift*(pixel_per_byte-numbits))); if (--numbits == 0) { export_font.chars_data[idx++] = (unsigned char)field; numbits = pixel_per_byte; field = 0; } } } /* Pad last byte */ if (numbits != pixel_per_byte) { export_font.chars_data[idx++] = (unsigned char)field; } if( dump_glyphs ) { /* debug: dump char */ unsigned char bit_max = (1 << bit_shift) - 1; printf("\n---Converted Glyph Dump---\n"); if ( code > 32 && code < 255 ) { unsigned char current_data; unsigned char font_bits; row = h; if(use_long_offset) buf = &(export_font.chars_data[export_font.offset_long[ code - firstchar]]); else buf = &(export_font.chars_data[export_font.offset[ code - firstchar]]); numbits = pixel_per_byte; current_data = *buf; do { col = w; printf("-"); do { font_bits = current_data & bit_max; if (font_bits==bit_max) printf(" "); else { if(font_bits > bit_max/2) printf("."); else printf("@"); } if (--numbits == 0) { current_data = *(++buf); numbits = pixel_per_byte; } else { current_data >>= bit_shift; } } while (--col); printf("-\n"); } while (--row); } buf = NULL; printf("---End Glyph Dump---\n"); } free(tmpbuf); converted_char_count++; done = (100*(converted_char_count))/char_count; printf("Converted %s %d (%d%%)\e[K\r", char_name,converted_char_count,done); fflush(stdout); } file = fopen(destfile, "wb"); printf("Writing %s\n", destfile); /* font info */ writestr(file, VERSION, 4); writeshort(file, export_font.header.maxwidth); writeshort(file, export_font.header.height); writeshort(file, export_font.header.ascent); writeshort(file, export_font.header.depth); writeint(file, export_font.header.firstchar); writeint(file, export_font.header.defaultchar); writeint(file, export_font.header.size); writeint(file, export_font.header.nbits); writeint(file, export_font.header.noffset); writeint(file, export_font.header.nwidth); fwrite( (char*)export_font.chars_data, 1, export_font.header.nbits, file); free(export_font.chars_data); if ( use_long_offset ) { skip = ((export_font.header.nbits + 3) & ~3) - export_font.header.nbits; fwrite(pad, 1, skip, file); /* pad */ for(i = 0; i < export_font.header.noffset; i++) writeint(file, export_font.offset_long[i]); } else { skip = ((export_font.header.nbits + 1) & ~1) - export_font.header.nbits; fwrite(pad, 1, skip, file); /* pad */ for(i = 0; i < export_font.header.noffset; i++) writeshort(file, export_font.offset[i]); } for(i = 0; i < export_font.header.nwidth; i++) writebyte(file, export_font.width[i]); free(export_font.width); if ( use_long_offset ) free(export_font.offset_long); else free(export_font.offset); fclose(file); FT_Done_Face( face ); FT_Done_FreeType( library ); printf("done (converted %d glyphs, %d errors).\e[K\n\n", converted_char_count, failed_char_count); } void convttc(char* path) { struct ttc_table ttcname; FT_Long i; get_ttc_table(path, &ttcname); if (ttcname.ttc_count == 0) { printf("This file is a not true type font.\n"); return; } /* default */ if (!flg_all_ttc && ttc_index == -1) { if (!oflag) { /* generate filename */ snprintf(outfile, sizeof(outfile), "%d-%s.fnt", pixel_size, basename(path)); } convttf(path, outfile, (FT_Long) 0); } /* set face_index of ttc */ else if (!flg_all_ttc) { print_ttc_table(path); if ( !oflag ) { if (ttc_index >= 0 && ttc_index < ttcname.ttc_count) { if (strcmp(ttcname.ttf_name[ttc_index], "") != 0) { snprintf(outfile, sizeof(outfile), "%d-%s.fnt", pixel_size, ttcname.ttf_name[ttc_index]); } else { snprintf(outfile, sizeof(outfile), "%d-%s-%ld.fnt", pixel_size, basename(path), ttc_index); } } else { printf("illegal face index of ttc.\n"); } } convttf(path, outfile, ttc_index); } else { /* convert all fonts */ print_ttc_table(path); for(i = 0; i < ttcname.ttc_count; i++) { snprintf(outfile, sizeof(outfile), "%d-%s.fnt", pixel_size, ttcname.ttf_name[i]); convttf(path, outfile, i); } } for(i = 0; i < ttcname.ttc_count; i++) { free(ttcname.ttf_name[i]); } free(ttcname.ttf_name); } /* parse command line options*/ void getopts(int *pac, char ***pav) { char *p; char **av; int ac; ac = *pac; av = *pav; limit_char = max_char; start_char = 0; while (ac > 0 && av[0][0] == '-') { p = &av[0][1]; while( *p) switch(*p++) { case 'h':case 'H': usage(); break; case ' ': /* multiple -args on av[]*/ while( *p && *p == ' ') p++; if( *p++ != '-') /* next option must have dash*/ p = ""; break; /* proceed to next option*/ case 'o': /* set output file*/ oflag = 1; if (*p) { strcpy(outfile, p); while (*p && *p != ' ') p++; } else { av++; ac--; if (ac > 0) strcpy(outfile, av[0]); } break; case 'l': /* set encoding limit*/ if (*p) { limit_char = atoi(p); while (*p && *p != ' ') p++; } else { av++; ac--; if (ac > 0) limit_char = atoi(av[0]); } break; case 's': /* set encoding start*/ if (*p) { start_char = atol(p); while (*p && *p != ' ') p++; } else { av++; ac--; if (ac > 0) start_char = atol(av[0]); } break; case 'p': /* set pixel size*/ if (*p) { pixel_size = atoi(p); while (*p && *p != ' ') p++; } else { av++; ac--; if (ac > 0) pixel_size = atoi(av[0]); } break; case 'c': /* set spaece between characters */ { if (*p) { between_chr = atof(p); while (*p && *p != ' ') p++; } else { av++; ac--; if (ac > 0) between_chr = atof(av[0]); } break; } case 'd': dump_glyphs = 1; while (*p && *p != ' ') p++; break; case 'x': trimming = 1; while (*p && *p != ' ') p++; break; case 'X': if (*p) { hv_resolution = atoi(p); while (*p && *p != ' ') p++; } else { av++; ac--; if (ac > 0) hv_resolution = atoi(av[0]); } break; case 'r': if (*p) { between_row = atof(p); while (*p && *p != ' ') p++; } else { av++; ac--; if (ac > 0) between_row = atof(av[0]); } break; case 'T': if(*p == 'A') { if(*(++p)) { trim_ap = atoi(p); while (*p && *p != ' ') p++; } else { av++; ac--; if (ac > 0) trim_ap = atoi(av[0]); } break; } if(*p == 'D') { if(*(++p)) { trim_dp = atoi(p); while (*p && *p != ' ') p++; } else { av++; ac--; if (ac > 0) trim_dp = atoi(av[0]); } break; } if(*p == 'a') { if(*(++p)) { trim_aa = atoi(p); while (*p && *p != ' ') p++; } else { av++; ac--; if (ac > 0) trim_aa = atoi(av[0]); } break; } if(*p == 'd') { if(*(++p)) { trim_da = atoi(p); } else { av++; ac--; if (ac > 0) trim_da = atoi(av[0]); } break; } fprintf(stderr, "Unknown option ignored: %s\n", p-1); while (*p && *p != ' ') p++; break; case 't': /* display ttc table */ if (*p == 't') { pct = 1; while (*p && *p != ' ') p++; } else if (*p == 'a') { flg_all_ttc = 1; while (*p && *p != ' ') p++; } else if (*p) { ttc_index = atoi(p); while (*p && *p != ' ') p++; } else { av++; ac--; if (ac > 0) ttc_index = atoi(av[0]); } break; case 'w': /* Don't try to make digits equally wide */ digits_equally_wide = 0; while (*p && *p != ' ') p++; break; default: fprintf(stderr, "Unknown option ignored: %s\n", p-1); while (*p && *p != ' ') p++; } ++av; --ac; } *pac = ac; *pav = av; } int main(int ac, char **av) { int ret = 0; ++av; --ac; /* skip av[0]*/ getopts(&ac, &av); /* read command line options*/ if (ac < 1) { usage(); } if (oflag) { if (ac > 1) { usage(); } } if (limit_char < start_char) { usage(); exit(0); } while (pct && ac > 0) { print_ttc_table(av[0]); ++av; --ac; exit(0); } while (ac > 0) { convttc(av[0]); ++av; --ac; } exit(ret); } /* * Trie node structure. */ typedef struct { unsigned short key; /* Key value. */ unsigned short val; /* Data for the key. */ unsigned long sibs; /* Offset of siblings from trie beginning. */ unsigned long kids; /* Offset of children from trie beginning. */ } node_t; /* * The trie used for remapping codes. */ static node_t *nodes; static unsigned long nodes_used = 0; int otf2bdf_remap(unsigned short *code) { unsigned long i, n, t; unsigned short c, codes[2]; /* * If no mapping table was loaded, then simply return the code. */ if (nodes_used == 0) return 1; c = *code; codes[0] = (c >> 8) & 0xff; codes[1] = c & 0xff; for (i = n = 0; i < 2; i++) { t = nodes[n].kids; if (t == 0) return 0; for (; nodes[t].sibs && nodes[t].key != codes[i]; t = nodes[t].sibs); if (nodes[t].key != codes[i]) return 0; n = t; } *code = nodes[n].val; return 1; }