2 * sfnttofnt. Bitmap only ttf to Window fnt file converter
4 * Copyright 2004 Huw Davies
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "wine/port.h"
32 #ifdef HAVE_FT2BUILD_H
35 #include FT_FREETYPE_H
36 #include FT_SFNT_NAMES_H
37 #include FT_TRUETYPE_TABLES_H
38 #include FT_TRUETYPE_TAGS_H
40 #include "wine/unicode.h"
41 #include "wine/wingdi16.h"
67 CHAR caretSlopeNumerator;
68 CHAR caretSlopeDenominator;
79 ULONG indexSubTableArrayOffset;
81 ULONG numberOfIndexSubTables;
83 sbitLineMetrics_t hori;
84 sbitLineMetrics_t vert;
85 USHORT startGlyphIndex;
93 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
94 #define GET_BE_DWORD(ptr) ((DWORD)MAKELONG( GET_BE_WORD(&((WORD *)(ptr))[1]), \
95 GET_BE_WORD(&((WORD *)(ptr))[0]) ))
99 static const char *output_name;
101 static void usage(char **argv)
103 fprintf(stderr, "%s foo.ttf ppem enc dpi def_char avg_width\n", argv[0]);
108 #define __attribute__(X)
111 /* atexit handler to cleanup files */
112 static void cleanup(void)
114 if (output_name) unlink( output_name );
117 static void exit_on_signal( int sig )
119 exit(1); /* this will call the atexit functions */
122 static void error(const char *s, ...) __attribute__((format (printf, 1, 2)));
124 static void error(const char *s, ...)
128 fprintf(stderr, "Error: ");
129 vfprintf(stderr, s, ap);
134 static int lookup_charset(int enc)
136 /* FIXME: make winelib app and use TranslateCharsetInfo */
141 return RUSSIAN_CHARSET;
145 return GREEK_CHARSET;
147 return TURKISH_CHARSET;
149 return HEBREW_CHARSET;
151 return ARABIC_CHARSET;
153 return BALTIC_CHARSET;
155 return VIETNAMESE_CHARSET;
175 return SHIFTJIS_CHARSET;
177 return GB2312_CHARSET;
179 return HANGUL_CHARSET;
181 return CHINESEBIG5_CHARSET;
183 fprintf(stderr, "Unknown encoding %d - using OEM_CHARSET\n", enc);
188 static int get_char(const union cptable *cptable, int enc, int index)
190 /* Korean has the Won sign in place of '\\' */
191 if(enc == 949 && index == '\\')
194 return cptable->sbcs.cp2uni[index];
197 static void fill_fontinfo(FT_Face face, int enc, FILE *fp, int dpi, unsigned char def_char, int avg_width)
199 int ascent = 0, il, ppem, descent = 0, width_bytes = 0, space_size, max_width = 0;
202 BYTE left_byte, right_byte, byte;
204 CHAR_TABLE_ENTRY *dfCharTable;
205 int i, x, y, x_off, x_end, first_char;
208 const union cptable *cptable;
209 FT_SfntName sfntname;
212 #ifdef HAVE_FT_LOAD_SFNT_TABLE
215 bitmapSizeTable_t *size_table;
219 cptable = wine_cp_get_table(enc);
221 error("Can't find codepage %d\n", enc);
223 if(cptable->info.char_size != 1) {
224 /* for double byte charsets we actually want to use cp1252 */
225 cptable = wine_cp_get_table(1252);
227 error("Can't find codepage 1252\n");
230 ppem = face->size->metrics.y_ppem;
232 #ifdef HAVE_FT_LOAD_SFNT_TABLE
234 if(FT_Load_Sfnt_Table(face, TTAG_EBLC, 0, NULL, &needed))
235 error("Can't find EBLC table\n");
237 eblc = malloc(needed);
238 FT_Load_Sfnt_Table(face, TTAG_EBLC, 0, (FT_Byte *)eblc, &needed);
240 num_sizes = GET_BE_DWORD(&eblc->numSizes);
242 size_table = (bitmapSizeTable_t *)(eblc + 1);
243 for(i = 0; i < num_sizes; i++)
245 if(size_table->hori.ascender - size_table->hori.descender == ppem)
247 ascent = size_table->hori.ascender;
248 descent = -size_table->hori.descender;
257 /* Versions of fontforge prior to early 2006 have incorrect
258 ascender values in the eblc table, so we won't find the
259 correct bitmapSizeTable. In this case use the height of
260 the Aring glyph instead. */
263 if(FT_Load_Char(face, 0xc5, FT_LOAD_DEFAULT))
264 error("Can't find Aring\n");
265 ascent = face->glyph->metrics.horiBearingY >> 6;
266 descent = ppem - ascent;
269 start = sizeof(FNT_HEADER) + sizeof(FONTINFO16);
271 if(FT_Load_Char(face, 'M', FT_LOAD_DEFAULT))
272 error("Can't find M\n");
273 il = ascent - (face->glyph->metrics.height >> 6);
275 /* Hack: Courier has no internal leading, nor do any Chinese fonts */
276 if(!strcmp(face->family_name, "Courier") || enc == 936 || enc == 950)
279 first_char = FT_Get_First_Char(face, &gi);
280 if(first_char == 0xd) /* fontforge's first glyph is 0xd, we'll catch this and skip it */
281 first_char = 32; /* FT_Get_Next_Char for some reason returns too high
282 number in this case */
284 dfCharTable = malloc((255 + 3) * sizeof(*dfCharTable));
285 memset(dfCharTable, 0, (255 + 3) * sizeof(*dfCharTable));
287 memset(&fi, 0, sizeof(fi));
288 fi.dfFirstChar = first_char;
289 fi.dfLastChar = 0xff;
290 start += ((unsigned char)fi.dfLastChar - (unsigned char)fi.dfFirstChar + 3 ) * sizeof(*dfCharTable);
292 num_names = FT_Get_Sfnt_Name_Count(face);
293 for(i = 0; i <num_names; i++) {
294 FT_Get_Sfnt_Name(face, i, &sfntname);
295 if(sfntname.platform_id == 1 && sfntname.encoding_id == 0 &&
296 sfntname.language_id == 0 && sfntname.name_id == 0) {
297 size_t len = min( sfntname.string_len, sizeof(hdr.dfCopyright)-1 );
298 memcpy(hdr.dfCopyright, sfntname.string, len);
299 hdr.dfCopyright[len] = 0;
303 os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
304 for(i = first_char; i < 0x100; i++) {
305 int c = get_char(cptable, enc, i);
306 gi = FT_Get_Char_Index(face, c);
308 fprintf(stderr, "Missing glyph for char %04x\n", cptable->sbcs.cp2uni[i]);
309 if(FT_Load_Char(face, c, FT_LOAD_DEFAULT)) {
310 fprintf(stderr, "error loading char %d - bad news!\n", i);
313 dfCharTable[i].width = face->glyph->metrics.horiAdvance >> 6;
314 dfCharTable[i].offset = start + (width_bytes * ppem);
315 width_bytes += ((face->glyph->metrics.horiAdvance >> 6) + 7) >> 3;
316 if(max_width < (face->glyph->metrics.horiAdvance >> 6))
317 max_width = face->glyph->metrics.horiAdvance >> 6;
320 space_size = (ppem + 3) / 4;
321 dfCharTable[i].width = space_size;
322 dfCharTable[i].offset = start + (width_bytes * ppem);
323 width_bytes += (space_size + 7) >> 3;
325 dfCharTable[++i].width = 0;
326 dfCharTable[i].offset = start + (width_bytes * ppem);
329 fi.dfPoints = ((ppem - il) * 72 + dpi/2) / dpi;
332 fi.dfAscent = ascent;
333 fi.dfInternalLeading = il;
334 fi.dfExternalLeading = 0;
335 fi.dfItalic = (face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
338 fi.dfWeight = os2->usWeightClass;
339 fi.dfCharSet = lookup_charset(enc);
340 fi.dfPixWidth = (face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) ?
342 fi.dfPixHeight = ppem;
343 fi.dfPitchAndFamily = FT_IS_FIXED_WIDTH(face) ? 0 : TMPF_FIXED_PITCH;
344 switch(os2->panose[PAN_FAMILYTYPE_INDEX]) {
345 case PAN_FAMILY_SCRIPT:
346 fi.dfPitchAndFamily |= FF_SCRIPT;
348 case PAN_FAMILY_DECORATIVE:
349 case PAN_FAMILY_PICTORIAL:
350 fi.dfPitchAndFamily |= FF_DECORATIVE;
352 case PAN_FAMILY_TEXT_DISPLAY:
353 if(fi.dfPitchAndFamily == 0) /* fixed */
354 fi.dfPitchAndFamily = FF_MODERN;
356 switch(os2->panose[PAN_SERIFSTYLE_INDEX]) {
357 case PAN_SERIF_NORMAL_SANS:
358 case PAN_SERIF_OBTUSE_SANS:
359 case PAN_SERIF_PERP_SANS:
360 fi.dfPitchAndFamily |= FF_SWISS;
363 fi.dfPitchAndFamily |= FF_ROMAN;
368 fi.dfPitchAndFamily |= FF_DONTCARE;
371 fi.dfAvgWidth = avg_width;
372 fi.dfMaxWidth = max_width;
373 fi.dfDefaultChar = def_char - fi.dfFirstChar;
374 fi.dfBreakChar = ' ' - fi.dfFirstChar;
375 fi.dfWidthBytes = (width_bytes + 1) & ~1;
377 fi.dfFace = start + fi.dfWidthBytes * ppem;
378 fi.dfBitsOffset = start;
379 fi.dfFlags = 0x10; /* DFF_1COLOR */
380 fi.dfFlags |= FT_IS_FIXED_WIDTH(face) ? 1 : 2; /* DFF_FIXED : DFF_PROPORTIONAL */
382 hdr.dfVersion = 0x300;
383 hdr.dfSize = start + fi.dfWidthBytes * ppem + strlen(face->family_name) + 1;
384 fwrite(&hdr, sizeof(hdr), 1, fp);
385 fwrite(&fi, sizeof(fi), 1, fp);
386 fwrite(dfCharTable + fi.dfFirstChar, sizeof(*dfCharTable), ((unsigned char)fi.dfLastChar - (unsigned char)fi.dfFirstChar) + 3, fp);
388 for(i = first_char; i < 0x100; i++) {
389 int c = get_char(cptable, enc, i);
390 if(FT_Load_Char(face, c, FT_LOAD_DEFAULT)) {
393 assert(dfCharTable[i].width == face->glyph->metrics.horiAdvance >> 6);
395 for(x = 0; x < ((dfCharTable[i].width + 7) / 8); x++) {
396 for(y = 0; y < ppem; y++) {
397 if(y < ascent - face->glyph->bitmap_top ||
398 y >= face->glyph->bitmap.rows + ascent - face->glyph->bitmap_top) {
402 x_off = face->glyph->bitmap_left / 8;
403 x_end = (face->glyph->bitmap_left + face->glyph->bitmap.width - 1) / 8;
404 if(x < x_off || x > x_end) {
411 left_byte = face->glyph->bitmap.buffer[(y - (ascent - face->glyph->bitmap_top)) * face->glyph->bitmap.pitch + x - x_off - 1];
413 /* On the last non-trival output byte (x == x_end) have we got one or two input bytes */
414 if(x == x_end && (face->glyph->bitmap_left % 8 != 0) && ((face->glyph->bitmap.width % 8 == 0) || (x != (((face->glyph->bitmap.width) & ~0x7) + face->glyph->bitmap_left) / 8)))
417 right_byte = face->glyph->bitmap.buffer[(y - (ascent - face->glyph->bitmap_top)) * face->glyph->bitmap.pitch + x - x_off];
419 byte = (left_byte << (8 - (face->glyph->bitmap_left & 7))) & 0xff;
420 byte |= ((right_byte >> (face->glyph->bitmap_left & 7)) & 0xff);
425 for(x = 0; x < (space_size + 7) / 8; x++) {
426 for(y = 0; y < ppem; y++)
430 if(width_bytes & 1) {
431 for(y = 0; y < ppem; y++)
434 fprintf(fp, "%s", face->family_name);
440 int main(int argc, char **argv)
446 unsigned int def_char;
456 ppem = atoi(argv[2]);
459 def_char = atoi(argv[5]);
460 avg_width = atoi(argv[6]);
462 if(FT_Init_FreeType(&lib))
463 error("ft init failure\n");
465 if(FT_New_Face(lib, argv[1], 0, &face)) {
466 fprintf(stderr, "Can't open face\n");
471 if(FT_Set_Pixel_Sizes(face, ppem, ppem)) {
472 fprintf(stderr, "Can't set size\n");
477 strcpy(name, face->family_name);
478 /* FIXME: should add a -o option instead */
479 for(cp = name; *cp; cp++)
481 if(*cp == ' ') *cp = '_';
482 else if (*cp >= 'A' && *cp <= 'Z') *cp += 'a' - 'A';
485 sprintf(output, "%s-%d-%d-%d.fnt", name, enc, dpi, ppem);
488 signal( SIGTERM, exit_on_signal );
489 signal( SIGINT, exit_on_signal );
491 signal( SIGHUP, exit_on_signal );
494 fp = fopen(output, "w");
495 output_name = output;
497 fill_fontinfo(face, enc, fp, dpi, def_char, avg_width);
503 #else /* HAVE_FREETYPE */
505 int main(int argc, char **argv)
507 fprintf( stderr, "%s needs to be built with FreeType support\n", argv[0] );
511 #endif /* HAVE_FREETYPE */