From 76f70114f9c73e0ba3571276d7b5121449f418f9 Mon Sep 17 00:00:00 2001 From: Thomas Martitz Date: Sat, 29 Aug 2009 13:00:01 +0200 Subject: [PATCH] Integrate convttf into tools/. --- tools/Makefile | 9 +- tools/convbdf.c | 1 + tools/convttf.c | 1131 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ tools/root.make | 3 +- tools/tools.make | 13 +- 5 files changed, 1150 insertions(+), 7 deletions(-) create mode 100644 tools/convttf.c diff --git a/tools/Makefile b/tools/Makefile index 43f53e256..564293b1f 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -13,10 +13,11 @@ LDFLAGS := -g CLEANALL := scramble descramble iriver sh2d bmp2rb rdf2binary convbdf \ generate_rocklatin mkboot ipod_fw codepages uclpack mi4 gigabeat \ - lngdump telechips gigabeats creative hmac-sha1 mktccboot mknkboot rbspeexenc mkzenboot + lngdump telechips gigabeats creative hmac-sha1 mktccboot mknkboot rbspeexenc \ + mkzenboot convttf all: scramble descramble sh2d rdf2binary mkboot mktccboot mknkboot mkzenboot \ - convbdf codepages uclpack rbspeexenc voicefont + convbdf codepages uclpack rbspeexenc voicefont convttf scramble: scramble.o iriver.o mi4.o gigabeat.o gigabeats.o telechips.o iaudio_bl_flash.o creative.o hmac-sha1.o descramble: descramble.o iriver.o gigabeat.o @@ -95,6 +96,10 @@ voicefont: voicefont.c usb_benchmark: usb_benchmark.c $(SILENT)$(CC) $(CFLAGS) -lusb $+ -o $@ +convttf: convttf.c + $(call PRINTS,CC $(@F)) + $(SILENT)$(CC) $(CFLAGS) -std=gnu89 -O -Wall -g $+ -o $@ \ + `freetype-config --libs` `freetype-config --cflags` clean: @echo "Cleaning tools" $(SILENT)rm -f $(CLEANALL) $(shell for f in $(CLEANALL) ; do echo $$f.exe $$f.o $$f.obj ; done) *.ajf *~ diff --git a/tools/convbdf.c b/tools/convbdf.c index fd82fb5a7..e23aa08e5 100644 --- a/tools/convbdf.c +++ b/tools/convbdf.c @@ -1389,6 +1389,7 @@ int gen_c_source(struct font* pf, char *path) " %d, /* ascent */\n" " %d, /* firstchar */\n" " %d, /* size */\n" + " 0, /* depth */\n" " _font_bits, /* bits */\n" " %s /* offset */\n" " %s\n" diff --git a/tools/convttf.c b/tools/convttf.c new file mode 100644 index 000000000..fdc45ed39 --- /dev/null +++ b/tools/convttf.c @@ -0,0 +1,1131 @@ +/*************************************************************************** + * __________ __ ___. + * 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 */ + + FT_Long noffset; /* # longs offset data in file */ + FT_Long nwidth; /* # bytes width data in file */ +}; + +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), + 0, + 0 + }; + char char_name[16]; + int empty_glyphs[256] = {0}; + 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; + 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); + +#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; + char_count++; + + /* 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 % 2; + unsigned char pixel = ((unsigned)(*buf++) + 8) / 17; + field |= pixel << (subcol << 2); + if (i % 2) + { + glyph_buffer[index++] = field; + field = 0; + } + } + + if (i % 2) + 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; + + 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) + { + printf("path: %s\n", path); + sprintf(outfile, "%d-%s.fnt", pixel_size, basename(path)); + } + 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) + { + sprintf(outfile, "%d-%s.fnt", pixel_size, + ttcname.ttf_name[ttc_index]); + } + else + { + sprintf(outfile, "%d-%s-%ld.fnt", + pixel_size,basename(path),ttc_index); + } + } + 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++) + { + convttf(path, i); + sprintf(outfile, "%d-%s.fnt", pixel_size, ttcname.ttf_name[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; +} diff --git a/tools/root.make b/tools/root.make index 5ba321c95..0d2dcd2fc 100644 --- a/tools/root.make +++ b/tools/root.make @@ -20,7 +20,8 @@ PPCFLAGS = $(filter-out -Dmain=SDL_main,$(CFLAGS)) # cygwin sdl-config fix TOOLS = $(TOOLSDIR)/rdf2binary $(TOOLSDIR)/convbdf \ $(TOOLSDIR)/codepages $(TOOLSDIR)/scramble $(TOOLSDIR)/bmp2rb \ - $(TOOLSDIR)/uclpack $(TOOLSDIR)/mktccboot $(TOOLSDIR)/mkboot + $(TOOLSDIR)/uclpack $(TOOLSDIR)/mktccboot $(TOOLSDIR)/mkboot \ + $(TOOLSDIR)/convttf ifeq (,$(PREFIX)) diff --git a/tools/tools.make b/tools/tools.make index e0337748c..d17212756 100644 --- a/tools/tools.make +++ b/tools/tools.make @@ -1,9 +1,9 @@ -# __________ __ ___. +# __________ __ ___. # Open \______ \ ____ ____ | | _\_ |__ _______ ___ -# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / -# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < # Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ -# \/ \/ \/ \/ \/ +# \/ \/ \/ \/ \/ # $Id$ # @@ -34,6 +34,11 @@ $(TOOLSDIR)/uclpack: $(TOOLSDIR)/ucl/uclpack.c $(wildcard $(TOOLSDIR)/ucl/src/*. $(call PRINTS,CC $(@F))$(HOSTCC) $(TOOLSCFLAGS) -I$(TOOLSDIR)/ucl \ -I$(TOOLSDIR)/ucl/include -o $@ $^ +$(TOOLSDIR)/convttf: $(TOOLSDIR)/convttf.c + $(call PRINTS,CC $(@F)) + $(SILENT)$(HOSTCC) $(TOOLSFLAGS) -std=gnu89 -O -Wall -g $+ -o $@ \ + `freetype-config --libs` `freetype-config --cflags` + # implicit rule for simple tools $(TOOLSDIR)/%: $(TOOLSDIR)/%.c $(call PRINTS,CC $(subst $(ROOTDIR)/,,$@)) -- 2.11.4.GIT