/*************************************************************************** * __________ __ ___. * 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. * ****************************************************************************/ #define BITMAP_WORDS(x) (((x)+15)/16) /* image size in words*/ #include #include #include #include FT_FREETYPE_H #include FT_GLYPH_H #include #ifdef WIN32 #include #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 log_level_nolog 0 #define log_level_warnning 1 #define log_level_header 2 #define log_level_description1 3 #define log_level_description2 4 #ifndef log_level #define log_level log_level_nolog #endif #define MIN(a,b) ((a)<(b) ? (a) : (b)) #define MAX(a,b) ((a)>(b) ? (a) : (b)) /* * 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; #define MAX_CHAR 65535 int pct = 0; /* display ttc table if it is not zero. */ int pixel_size = 15; unsigned long start_char = 0; unsigned long limit_char; unsigned long firstchar = 0; unsigned long lastchar; FT_Long ttc_index = -1; int flg_all_ttc = 0; const int depth = 1; short antialias = 1; /* smooth fonts with gray levels */ int oflag = 0; char outfile[1024]; int between_chr = 0; int between_row = 1; 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 char_index_entry { unsigned code; unsigned charindex; unsigned offset; }; 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 ); } /* 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-filename : \n" " 'input-files name removed extension'_'font-size'.fnt.\n" " but default output-filename become \n " " 'internal postscript-name of input-file'_'font-size'.fnt.\n" " if '-ta' or '-tc' options are described.\n" "Options:\n" " -s N Start output at character encodings >= N\n" " -l N Limit output to character encodings <= N\n" " -p N Character height N in pixel (default N=15)\n" " -c N Character separation in pixel.Insert space between lines. (default N=1)\n" " -r N Row separation in pixel.Insert space between characters\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\n" " \"-o output-file\" specified is ignored when \"-ta\" is specified.\n" }; fprintf(stderr, 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) { if (*p == '/') 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; unsigned short slen; 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 error; 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 ( ( error = FT_Init_FreeType( &library ) ) != 0 ) { panic( "Error while initializing engine" ); return error; } /* Load face */ error = FT_New_Face( library, path, (FT_Long) 0, &face ); if ( error == FT_Err_Cannot_Open_Stream ) { panic( "Could not find/open font resource" ); return error; } ttcname->ttc_count = face->num_faces; ttcname->ttf_name = malloc( sizeof(char*) * ttcname->ttc_count); for(i = 0; i < ttcname->ttc_count; i++) { error = FT_New_Face( library, path, i, &face ); if ( error == FT_Err_Cannot_Open_Stream ) panic( "Could not find/open font resource\n" ); 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; } int calculate_output_glyph_data(FT_GlyphSlot glyph, int *start_x) { int ow, ow1, osx; ow = glyph->bitmap.pitch; if (ow == 0) ow = glyph->metrics.horiAdvance >> 6; ow1 = glyph->metrics.width >> 6; ow = MAX(ow, ow1); if (!ow) return 0; osx = glyph->metrics.horiBearingX >> 6; osx = MAX(osx, 0); ow += osx + between_chr; if (!start_x) return ow; osx += between_chr >> 1; *start_x = osx; return ow; } void convttf(char* path, FT_Long face_index) { FT_Error error; FT_Library library; FT_Face face; int w, h; int row,col; FT_Long charindex; FT_Long index = 0; FT_Long code; FT_Long min_start_y; FT_Long max_end_y; FT_Long glyph_index[MAX_CHAR] = {0}; FT_Size_RequestRec req = { FT_SIZE_REQUEST_TYPE_REAL_DIM, 0, ((pixel_size - between_row) << 10) - 1, 0, 0 }; char char_name[16]; int empty_glyphs[256] = {0}; unsigned char bit_shift = 1 << depth; unsigned char pixel_per_byte = 8 >> depth; int glyph_buffer_size = 0; unsigned char *glyph_buffer = NULL; int got_default = 0; int default_char; #if log_level > log_level_nolog FILE *pTmplog; char logfile[256]; strcpy(logfile, basename(path)); char log_suf[20]; sprintf(log_suf, "_%d.log", pixel_size); strcat(logfile, log_suf); if ((pTmplog = fopen(logfile, "w")) == 0) { fprintf(stderr, "unable to open temporary file '%s'.\n", logfile); return; } else { printf("log_file is %s\n\n", logfile); } #endif /* Initialize engine */ if ( ( error = FT_Init_FreeType( &library ) ) != 0 ) panic( "Error while initializing engine" ); /* Load face */ error = FT_New_Face( library, path, (FT_Long) face_index, &face ); if ( error == FT_Err_Cannot_Open_Stream ) panic( "Could not find/open font resource" ); else if ( error ) panic( "Error while opening font resource" ); setcharmap( face ); /* create size */ error = FT_Request_Size( face, &req ); if ( error ) panic( "Could not reset instance" ); printf("Please wait, converting %s to %s:\n",path,outfile); if ( limit_char == 0 ) limit_char = MAX_CHAR; /* "face->num_glyphs" is NG.; */ if ( limit_char > MAX_CHAR ) limit_char = MAX_CHAR; FT_Long char_count = 0; /* Set font header data */ struct font_header_struct export_font; export_font.header[0] = 'R'; export_font.header[1] = 'B'; export_font.header[2] = '1'; export_font.header[3] = '2'; export_font.maxwidth = 0; h = min_start_y = ((face->size->metrics.ascender - face->size->metrics.descender + 63) >> 6); max_end_y = 0; /* + between_row; */ export_font.ascent = (face->size->metrics.ascender + 63) >> 6; export_font.depth = depth; firstchar = limit_char; lastchar = limit_char; default_char = limit_char; #if log_level >= log_level_header fprintf(pTmplog, "limit_char=%ld\n", limit_char); fprintf(pTmplog, "face->size->metrics.ascender>>6=%ld\n", face->size->metrics.ascender>>6); fprintf(pTmplog, "face->size->metrics.descender>>6=%ld\n", face->size->metrics.descender>>6); fprintf(pTmplog, "pixel_per_byte=%d\n", pixel_per_byte); #endif /* decide common height, first_char and last_char, char_count */ FT_Long tmp_count = 0; printf("calculating height...\n"); fflush(stdout); error = FT_Load_Glyph( face, 0, (FT_LOAD_NO_BITMAP) ); if (!error) { FT_Long glyph_height = face->glyph->metrics.height >> 6; FT_Long start_y = export_font.ascent - face->glyph->bitmap_top; FT_Long end_y = start_y + glyph_height; if (glyph_height) { if (end_y > max_end_y) max_end_y = end_y; if (start_y < min_start_y) min_start_y = start_y; } got_default = 1; } for(code = start_char; code <= limit_char ; code++ ) { switch(code) { /* combining diacritical marks */ case 0x0300: code = 0x36f; continue; /* combining diacritical marks supplement */ case 0x1dc0: code = 0x1dff; continue; /* combining diacritical marks for symbols */ case 0x20d0: code = 0x20ff; continue; /* high surrogates */ case 0xd800: code = 0xdbff; continue; /* low surrogates */ case 0xdc00: code = 0xdfff; continue; /* combining half marks */ case 0xfe20: code = 0xfe2f; continue; } /* Is there glyph of this code in this ttf? */ charindex = getcharindex( face, code); if ( !(charindex) ) goto check_default; printf("\t%3d%% \e[K\r", (int) (tmp_count++ * 100 / face->num_glyphs) ); fflush(stdout); error = FT_Load_Glyph( face, charindex, (FT_LOAD_RENDER | FT_LOAD_NO_BITMAP) ); if ( error ) goto check_default; /* Is this glyph available? */ if (!(w = calculate_output_glyph_data(face->glyph, NULL))) goto check_default; /* count this font */ glyph_index[code] = charindex; /* decide height */ FT_Long glyph_height = face->glyph->metrics.height >> 6; FT_Long start_y = export_font.ascent - face->glyph->bitmap_top; FT_Long end_y = start_y + glyph_height; #if log_level >= log_level_description1 fprintf(pTmplog, "code=%ld\n", code); fflush(pTmplog); #endif #if log_level >= log_level_description2 fprintf(pTmplog, "\t glyph_height =%ld \n", (face->glyph->metrics.height) >> 6); fprintf(pTmplog, "\t horiBearingY =%ld \n", (face->glyph->metrics.horiBearingY >>6) ); fprintf(pTmplog, "\t vertBearingY =%ld \n", (face->glyph->metrics.vertBearingY >>6)); fprintf(pTmplog, "\t vertAdvance =%ld \n", (face->glyph->metrics.vertAdvance >>6)); fprintf(pTmplog, "\t start_y =%ld \n", start_y); fprintf(pTmplog, "\t height =%ld \n", (face->glyph->metrics.height >> 6)); fprintf(pTmplog, "\t end_y =%ld \n", end_y); if (face->glyph->bitmap_top != (face->glyph->metrics.horiBearingY >>6)) fprintf(pTmplog, "\t bitmap_top =%d \n", face->glyph->bitmap_top); if (face->glyph->bitmap.rows != glyph_height) fprintf(pTmplog, "\t bitmap.rows =%d \n", face->glyph->bitmap.rows); fflush(pTmplog); #endif if (code < firstchar) firstchar = code; lastchar = code; if (end_y > max_end_y) max_end_y = end_y; if (start_y < min_start_y) min_start_y = start_y; continue; check_default: if (firstchar < limit_char && default_char == limit_char) default_char = code; } min_start_y = MAX(min_start_y, 0); max_end_y = MIN(max_end_y, h); h = (max_end_y - min_start_y); req.type = FT_SIZE_REQUEST_TYPE_SCALES; req.height = req.width = face->size->metrics.x_scale * (pixel_size - between_row) / h; min_start_y = min_start_y * (pixel_size - between_row) / h; h = export_font.height = pixel_size; if (default_char == limit_char) default_char = --firstchar; error = FT_Request_Size( face, &req ); if ( error ) panic( "Could not reset instance" ); export_font.ascent = face->size->metrics.ascender >> 6; export_font.height = h; int extra_top = between_row >> 1; /* about half of between_row */ printf("\t done.\t\n"); printf("\t%ld glyphs are encoded in this source file according to a source font property.\n", face->num_glyphs); printf("\t%ld characters can be converted.\n", char_count); printf("\tfirst character = %ld\n", firstchar); printf("\tlast character = %ld\n", lastchar); printf("\tdefault character = %d\n", default_char); printf("\tline height = %d\n\n", h); fflush(stdout); #if log_level >= log_level_header fprintf(pTmplog, "requested size=%.2f\n", req.height / 64.0); fprintf(pTmplog, "max_end_y=%ld\n", max_end_y); fprintf(pTmplog, "min_start_y=%ld\n", min_start_y); fprintf(pTmplog, "ascender - descender = %ld \n", (face->size->metrics.ascender - face->size->metrics.descender)>>6); fprintf(pTmplog, "h = %ld \n", (FT_Long) h); fflush(pTmplog); #endif export_font.size = lastchar - firstchar + 1; export_font.noffset = export_font.size; export_font.nwidth = export_font.size; export_font.defaultchar = default_char; export_font.firstchar = firstchar; uint32_t offsets[export_font.size]; uint8_t widths[export_font.size]; memset(offsets, 0, sizeof(offsets)); memset(widths, 0, sizeof(widths)); index = 0; fprintf(stderr,"converting font...\n"); fflush(stdout); for( code = firstchar; code <= lastchar; code++) { printf("\t%3d%% \e[K\r", (int) ((code - firstchar + 1) * 100 / export_font.size) ); fflush(stdout); offsets[code - firstchar] = offsets[default_char]; widths[code - firstchar] = widths[default_char]; if (!(charindex = glyph_index[code]) && (!got_default || code != default_char)) continue; error = FT_Load_Glyph( face, charindex, FT_LOAD_RENDER|FT_LOAD_NO_BITMAP ); if (error) continue; if FT_HAS_GLYPH_NAMES(face) FT_Get_Glyph_Name(face, charindex, char_name, 16); else char_name[0] = '\0'; FT_Bitmap *source = &face->glyph->bitmap; int start_x; if (!(w = calculate_output_glyph_data(face->glyph, &start_x))) continue; export_font.maxwidth = MAX(w, export_font.maxwidth); unsigned char* src = source->buffer; unsigned char tmpbuf[w * h]; memset(tmpbuf, 0xff, w * h); FT_Long start_y = export_font.ascent - face->glyph->bitmap_top; FT_Long glyph_height = face->glyph->metrics.height >> 6; FT_Long glyph_width = face->glyph->metrics.width >> 6; unsigned char *buf = tmpbuf; int offset = extra_top + (start_y - min_start_y); row = 0; if (offset > 0) buf += w * offset; else src += -offset * glyph_width; int max_col = MIN(glyph_width, w - start_x); int max_row = MIN(h - MAX(offset, 0), glyph_height + MIN(offset, 0)); unsigned char *endbuf = buf + w * max_row; if (glyph_height) { for(; buf < endbuf ; buf += w, src += glyph_width) for(col=0; col < max_col; col++) buf[col + start_x]= 0xff - src[col]; } else { if (!empty_glyphs[w]) { int glyph_size = (w * h + 1) / 2; empty_glyphs[w] = index; if (glyph_buffer_size < index + glyph_size) if (!(glyph_buffer = realloc(glyph_buffer, glyph_buffer_size += (glyph_size * 2 + 1023) & ~1023))) panic("Failed to allocate memory for glyphs"); memset(&glyph_buffer[index], 0xff, glyph_size); index += glyph_size; } offsets[code - firstchar] = empty_glyphs[w]; widths[code - firstchar] = w; continue; } offsets[code - firstchar] = index; widths[code - firstchar] = w; int i; int field = 0; buf = tmpbuf; int glyph_size = (w * h + 1) / 2; if (glyph_buffer_size < index + glyph_size) if (!(glyph_buffer = realloc(glyph_buffer, glyph_buffer_size += (glyph_size * 2 + 1023) & ~1023))) panic("Failed to allocate memory for glyphs"); for (i = 0; i < w * h; i++) { int subcol = i % pixel_per_byte; unsigned char pixel = (*buf++) >> (8 - bit_shift); field |= pixel << (bit_shift * subcol); if (i % pixel_per_byte == pixel_per_byte - 1) { glyph_buffer[index++] = field; field = 0; } } if (i % pixel_per_byte) glyph_buffer[index++] = field; } printf("\t done.\t\n"); export_font.nbits = index; int n; FILE *file = fopen(outfile, "w"); n = fwrite(&export_font, 1, sizeof(struct font_header_struct), file); /* This prevents valgrind from triggering on the write from uninitialized memory */ memset(glyph_buffer + index, 0, glyph_buffer_size - index); n = fwrite(glyph_buffer, 1, (index + 3) & ~3, file); int offsets_size = export_font.noffset * 4; if ( index < 0xFFDB ) { uint16_t * short_offsets = (uint16_t *)offsets; int i; for (i = 0; i < export_font.noffset; i++) short_offsets[i] = offsets[i]; offsets_size /= 2; } n = fwrite(offsets, 1, offsets_size, file); n = fwrite(widths, 1, export_font.nwidth, file); fclose(file); #if log_level > log_level_nolog fclose(pTmplog); #endif } void convttc(char* path) { struct ttc_table ttcname; FT_Long i; char ext_str[20]; get_ttc_table(path, &ttcname); if (ttcname.ttc_count == 0) { printf("This file is a not true type font.\n"); return; } /* defalut */ if (!flg_all_ttc && ttc_index == -1) { if (!oflag) { strcpy(outfile, basename(path)); sprintf(ext_str, "_%d.fnt", pixel_size); strcat(outfile, ext_str); } convttf(path, (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) { strcpy(outfile, ttcname.ttf_name[ttc_index]); sprintf(ext_str, "_%d.fnt", pixel_size); } else { strcpy(outfile, basename(path)); sprintf(ext_str, "%ld_%d.fnt", ttc_index,pixel_size); } strcat(outfile, ext_str); } else { printf("illegal face index of ttc.\n"); } } convttf(path, ttc_index); } else { /* convert all fonts */ print_ttc_table(path); for(i = 0; i < ttcname.ttc_count; i++) { strcpy(outfile, ttcname.ttf_name[i]); sprintf(ext_str, "_%d.fnt", pixel_size); strcat(outfile, ext_str); convttf(path, 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':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':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':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':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':case 'C': /* set spaece between characters */ if (*p) { between_chr = atoi(p); while (*p && *p != ' ') p++; } else { av++; ac--; if (ac > 0) between_chr = atoi(av[0]); } break; case 'r':case 'R': /* set spaece between rows */ if (*p) { between_row = atoi(p); while (*p && *p != ' ') p++; } else { av++; ac--; if (ac > 0) between_row = atoi(av[0]); } break; case 't':case 'T': /* display ttc table */ if (*p == 't' || *p == 'T') { pct = 1; while (*p && *p != ' ') p++; } else if (*p == 'a' || *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; default: fprintf(stderr, "Unknown option ignored: %c\r\n", *(p-1)); } ++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; }