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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "wine/port.h"
31 #ifdef HAVE_FT2BUILD_H
34 #include FT_FREETYPE_H
35 #include FT_SFNT_NAMES_H
36 #include FT_TRUETYPE_TABLES_H
37 #include FT_TRUETYPE_TAGS_H
39 #include "wine/unicode.h"
40 #include "wine/wingdi16.h"
66 CHAR caretSlopeNumerator;
67 CHAR caretSlopeDenominator;
78 ULONG indexSubTableArrayOffset;
80 ULONG numberOfIndexSubTables;
82 sbitLineMetrics_t hori;
83 sbitLineMetrics_t vert;
84 USHORT startGlyphIndex;
92 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
93 #define GET_BE_DWORD(ptr) ((DWORD)MAKELONG( GET_BE_WORD(&((WORD *)(ptr))[1]), \
94 GET_BE_WORD(&((WORD *)(ptr))[0]) ))
98 static const char *output_name;
100 static void usage(char **argv)
102 fprintf(stderr, "%s foo.ttf ppem enc dpi def_char avg_width\n", argv[0]);
107 #define __attribute__(X)
110 /* atexit handler to cleanup files */
111 static void cleanup(void)
113 if (output_name) unlink( output_name );
116 static void error(const char *s, ...) __attribute__((format (printf, 1, 2)));
118 static void error(const char *s, ...)
122 fprintf(stderr, "Error: ");
123 vfprintf(stderr, s, ap);
128 static int lookup_charset(int enc)
130 /* FIXME: make winelib app and use TranslateCharsetInfo */
135 return RUSSIAN_CHARSET;
139 return GREEK_CHARSET;
141 return TURKISH_CHARSET;
143 return HEBREW_CHARSET;
145 return ARABIC_CHARSET;
147 return BALTIC_CHARSET;
149 return VIETNAMESE_CHARSET;
169 return SHIFTJIS_CHARSET;
171 return GB2312_CHARSET;
173 return HANGUL_CHARSET;
175 return CHINESEBIG5_CHARSET;
177 fprintf(stderr, "Unknown encoding %d - using OEM_CHARSET\n", enc);
182 static int get_char(const union cptable *cptable, int enc, int index)
184 /* Korean has the Won sign in place of '\\' */
185 if(enc == 949 && index == '\\')
188 return cptable->sbcs.cp2uni[index];
191 static void fill_fontinfo(FT_Face face, int enc, FILE *fp, int dpi, unsigned char def_char, int avg_width)
193 int ascent = 0, il, ppem, descent = 0, width_bytes = 0, space_size, max_width = 0;
196 BYTE left_byte, right_byte, byte;
198 CHAR_TABLE_ENTRY *dfCharTable;
199 int i, x, y, x_off, x_end, first_char;
202 const union cptable *cptable;
203 FT_SfntName sfntname;
206 #ifdef HAVE_FT_LOAD_SFNT_TABLE
209 bitmapSizeTable_t *size_table;
213 cptable = wine_cp_get_table(enc);
215 error("Can't find codepage %d\n", enc);
217 if(cptable->info.char_size != 1) {
218 /* for double byte charsets we actually want to use cp1252 */
219 cptable = wine_cp_get_table(1252);
221 error("Can't find codepage 1252\n");
224 ppem = face->size->metrics.y_ppem;
226 #ifdef HAVE_FT_LOAD_SFNT_TABLE
228 if(FT_Load_Sfnt_Table(face, TTAG_EBLC, 0, NULL, &needed))
229 error("Can't find EBLC table\n");
231 eblc = malloc(needed);
232 FT_Load_Sfnt_Table(face, TTAG_EBLC, 0, (FT_Byte *)eblc, &needed);
234 num_sizes = GET_BE_DWORD(&eblc->numSizes);
236 size_table = (bitmapSizeTable_t *)(eblc + 1);
237 for(i = 0; i < num_sizes; i++)
239 if(size_table->hori.ascender - size_table->hori.descender == ppem)
241 ascent = size_table->hori.ascender;
242 descent = -size_table->hori.descender;
251 /* Versions of fontforge prior to early 2006 have incorrect
252 ascender values in the eblc table, so we won't find the
253 correct bitmapSizeTable. In this case use the height of
254 the Aring glyph instead. */
257 if(FT_Load_Char(face, 0xc5, FT_LOAD_DEFAULT))
258 error("Can't find Aring\n");
259 ascent = face->glyph->metrics.horiBearingY >> 6;
260 descent = ppem - ascent;
263 start = sizeof(FNT_HEADER) + sizeof(FONTINFO16);
265 if(FT_Load_Char(face, 'M', FT_LOAD_DEFAULT))
266 error("Can't find M\n");
267 il = ascent - (face->glyph->metrics.height >> 6);
269 /* Hack: Courier has no internal leading, nor do any Chinese fonts */
270 if(!strcmp(face->family_name, "Courier") || enc == 936 || enc == 950)
273 first_char = FT_Get_First_Char(face, &gi);
274 if(first_char == 0xd) /* fontforge's first glyph is 0xd, we'll catch this and skip it */
275 first_char = 32; /* FT_Get_Next_Char for some reason returns too high
276 number in this case */
278 dfCharTable = malloc((255 + 3) * sizeof(*dfCharTable));
279 memset(dfCharTable, 0, (255 + 3) * sizeof(*dfCharTable));
281 memset(&fi, 0, sizeof(fi));
282 fi.dfFirstChar = first_char;
283 fi.dfLastChar = 0xff;
284 start += ((unsigned char)fi.dfLastChar - (unsigned char)fi.dfFirstChar + 3 ) * sizeof(*dfCharTable);
286 num_names = FT_Get_Sfnt_Name_Count(face);
287 for(i = 0; i <num_names; i++) {
288 FT_Get_Sfnt_Name(face, i, &sfntname);
289 if(sfntname.platform_id == 1 && sfntname.encoding_id == 0 &&
290 sfntname.language_id == 0 && sfntname.name_id == 0) {
291 size_t len = min( sfntname.string_len, sizeof(hdr.dfCopyright)-1 );
292 memcpy(hdr.dfCopyright, sfntname.string, len);
293 hdr.dfCopyright[len] = 0;
297 os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
298 for(i = first_char; i < 0x100; i++) {
299 int c = get_char(cptable, enc, i);
300 gi = FT_Get_Char_Index(face, c);
302 fprintf(stderr, "Missing glyph for char %04x\n", cptable->sbcs.cp2uni[i]);
303 if(FT_Load_Char(face, c, FT_LOAD_DEFAULT)) {
304 fprintf(stderr, "error loading char %d - bad news!\n", i);
307 dfCharTable[i].width = face->glyph->metrics.horiAdvance >> 6;
308 dfCharTable[i].offset = start + (width_bytes * ppem);
309 width_bytes += ((face->glyph->metrics.horiAdvance >> 6) + 7) >> 3;
310 if(max_width < (face->glyph->metrics.horiAdvance >> 6))
311 max_width = face->glyph->metrics.horiAdvance >> 6;
314 space_size = (ppem + 3) / 4;
315 dfCharTable[i].width = space_size;
316 dfCharTable[i].offset = start + (width_bytes * ppem);
317 width_bytes += (space_size + 7) >> 3;
319 dfCharTable[++i].width = 0;
320 dfCharTable[i].offset = start + (width_bytes * ppem);
323 fi.dfPoints = ((ppem - il) * 72 + dpi/2) / dpi;
326 fi.dfAscent = ascent;
327 fi.dfInternalLeading = il;
328 fi.dfExternalLeading = 0;
329 fi.dfItalic = (face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
332 fi.dfWeight = os2->usWeightClass;
333 fi.dfCharSet = lookup_charset(enc);
334 fi.dfPixWidth = (face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) ?
336 fi.dfPixHeight = ppem;
337 fi.dfPitchAndFamily = FT_IS_FIXED_WIDTH(face) ? 0 : TMPF_FIXED_PITCH;
338 switch(os2->panose[PAN_FAMILYTYPE_INDEX]) {
339 case PAN_FAMILY_SCRIPT:
340 fi.dfPitchAndFamily |= FF_SCRIPT;
342 case PAN_FAMILY_DECORATIVE:
343 case PAN_FAMILY_PICTORIAL:
344 fi.dfPitchAndFamily |= FF_DECORATIVE;
346 case PAN_FAMILY_TEXT_DISPLAY:
347 if(fi.dfPitchAndFamily == 0) /* fixed */
348 fi.dfPitchAndFamily = FF_MODERN;
350 switch(os2->panose[PAN_SERIFSTYLE_INDEX]) {
351 case PAN_SERIF_NORMAL_SANS:
352 case PAN_SERIF_OBTUSE_SANS:
353 case PAN_SERIF_PERP_SANS:
354 fi.dfPitchAndFamily |= FF_SWISS;
357 fi.dfPitchAndFamily |= FF_ROMAN;
362 fi.dfPitchAndFamily |= FF_DONTCARE;
365 fi.dfAvgWidth = avg_width;
366 fi.dfMaxWidth = max_width;
367 fi.dfDefaultChar = def_char - fi.dfFirstChar;
368 fi.dfBreakChar = ' ' - fi.dfFirstChar;
369 fi.dfWidthBytes = (width_bytes + 1) & ~1;
371 fi.dfFace = start + fi.dfWidthBytes * ppem;
372 fi.dfBitsOffset = start;
373 fi.dfFlags = 0x10; /* DFF_1COLOR */
374 fi.dfFlags |= FT_IS_FIXED_WIDTH(face) ? 1 : 2; /* DFF_FIXED : DFF_PROPORTIONAL */
376 hdr.dfVersion = 0x300;
377 hdr.dfSize = start + fi.dfWidthBytes * ppem + strlen(face->family_name) + 1;
378 fwrite(&hdr, sizeof(hdr), 1, fp);
379 fwrite(&fi, sizeof(fi), 1, fp);
380 fwrite(dfCharTable + fi.dfFirstChar, sizeof(*dfCharTable), ((unsigned char)fi.dfLastChar - (unsigned char)fi.dfFirstChar) + 3, fp);
382 for(i = first_char; i < 0x100; i++) {
383 int c = get_char(cptable, enc, i);
384 if(FT_Load_Char(face, c, FT_LOAD_DEFAULT)) {
387 assert(dfCharTable[i].width == face->glyph->metrics.horiAdvance >> 6);
389 for(x = 0; x < ((dfCharTable[i].width + 7) / 8); x++) {
390 for(y = 0; y < ppem; y++) {
391 if(y < ascent - face->glyph->bitmap_top ||
392 y >= face->glyph->bitmap.rows + ascent - face->glyph->bitmap_top) {
396 x_off = face->glyph->bitmap_left / 8;
397 x_end = (face->glyph->bitmap_left + face->glyph->bitmap.width - 1) / 8;
398 if(x < x_off || x > x_end) {
405 left_byte = face->glyph->bitmap.buffer[(y - (ascent - face->glyph->bitmap_top)) * face->glyph->bitmap.pitch + x - x_off - 1];
407 /* On the last non-trival output byte (x == x_end) have we got one or two input bytes */
408 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)))
411 right_byte = face->glyph->bitmap.buffer[(y - (ascent - face->glyph->bitmap_top)) * face->glyph->bitmap.pitch + x - x_off];
413 byte = (left_byte << (8 - (face->glyph->bitmap_left & 7))) & 0xff;
414 byte |= ((right_byte >> (face->glyph->bitmap_left & 7)) & 0xff);
419 for(x = 0; x < (space_size + 7) / 8; x++) {
420 for(y = 0; y < ppem; y++)
424 if(width_bytes & 1) {
425 for(y = 0; y < ppem; y++)
428 fprintf(fp, "%s", face->family_name);
434 int main(int argc, char **argv)
440 unsigned int def_char;
450 ppem = atoi(argv[2]);
453 def_char = atoi(argv[5]);
454 avg_width = atoi(argv[6]);
456 if(FT_Init_FreeType(&lib))
457 error("ft init failure\n");
459 if(FT_New_Face(lib, argv[1], 0, &face)) {
460 fprintf(stderr, "Can't open face\n");
465 if(FT_Set_Pixel_Sizes(face, ppem, ppem)) {
466 fprintf(stderr, "Can't set size\n");
471 strcpy(name, face->family_name);
472 /* FIXME: should add a -o option instead */
473 for(cp = name; *cp; cp++)
475 if(*cp == ' ') *cp = '_';
476 else if (*cp >= 'A' && *cp <= 'Z') *cp += 'a' - 'A';
479 sprintf(output, "%s-%d-%d-%d.fnt", name, enc, dpi, ppem);
482 fp = fopen(output, "w");
483 output_name = output;
485 fill_fontinfo(face, enc, fp, dpi, def_char, avg_width);
491 #else /* HAVE_FREETYPE */
493 int main(int argc, char **argv)
495 fprintf( stderr, "%s needs to be built with FreeType support\n", argv[0] );
499 #endif /* HAVE_FREETYPE */