advpack: Put function declarations in advpack_private.h.
[wine] / tools / sfnt2fnt.c
1 /*
2  * sfnttofnt.  Bitmap only ttf to Window fnt file converter
3  *
4  * Copyright 2004 Huw Davies
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <assert.h>
25 #include <ctype.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28
29 #ifdef HAVE_FREETYPE
30
31 #ifdef HAVE_FT2BUILD_H
32 #include <ft2build.h>
33 #endif
34 #include FT_FREETYPE_H
35 #include FT_SFNT_NAMES_H
36 #include FT_TRUETYPE_TABLES_H
37 #include FT_TRUETYPE_TAGS_H
38
39 #include "wine/unicode.h"
40 #include "wine/wingdi16.h"
41 #include "wingdi.h"
42
43 #include "pshpack1.h"
44
45 typedef struct
46 {
47     WORD dfVersion;
48     DWORD dfSize;
49     char dfCopyright[60];
50 } FNT_HEADER;
51
52 typedef struct {
53     WORD width;
54     DWORD offset;
55 } CHAR_TABLE_ENTRY;
56
57 typedef struct {
58     DWORD version;
59     ULONG numSizes;
60 } eblcHeader_t;
61
62 typedef struct {
63     CHAR ascender;
64     CHAR descender;
65     BYTE widthMax;
66     CHAR caretSlopeNumerator;
67     CHAR caretSlopeDenominator;
68     CHAR caretOffset;
69     CHAR minOriginSB;
70     CHAR minAdvanceSB;
71     CHAR maxBeforeBL;
72     CHAR maxAfterBL;
73     CHAR pad1;
74     CHAR pad2;
75 } sbitLineMetrics_t;
76
77 typedef struct {
78     ULONG indexSubTableArrayOffset;
79     ULONG indexTableSize;
80     ULONG numberOfIndexSubTables;
81     ULONG colorRef;
82     sbitLineMetrics_t hori;
83     sbitLineMetrics_t vert;
84     USHORT startGlyphIndex;
85     USHORT endGlyphIndex;
86     BYTE ppemX;
87     BYTE ppemY;
88     BYTE bitDepth;
89     CHAR flags;
90 } bitmapSizeTable_t;
91
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]) ))
95
96 #include "poppack.h"
97
98 static const char *output_name;
99
100 static void usage(char **argv)
101 {
102     fprintf(stderr, "%s foo.ttf ppem enc dpi def_char avg_width\n", argv[0]);
103     return;
104 }
105
106 #ifndef __GNUC__
107 #define __attribute__(X)
108 #endif
109
110 /* atexit handler to cleanup files */
111 static void cleanup(void)
112 {
113     if (output_name) unlink( output_name );
114 }
115
116 static void error(const char *s, ...) __attribute__((format (printf, 1, 2)));
117
118 static void error(const char *s, ...)
119 {
120     va_list ap;
121     va_start(ap, s);
122     fprintf(stderr, "Error: ");
123     vfprintf(stderr, s, ap);
124     va_end(ap);
125     exit(1);
126 }
127
128 static int lookup_charset(int enc)
129 {
130     /* FIXME: make winelib app and use TranslateCharsetInfo */
131     switch(enc) {
132     case 1250:
133         return EE_CHARSET;
134     case 1251:
135         return RUSSIAN_CHARSET;
136     case 1252:
137         return ANSI_CHARSET;
138     case 1253:
139         return GREEK_CHARSET;
140     case 1254:
141         return TURKISH_CHARSET;
142     case 1255:
143         return HEBREW_CHARSET;
144     case 1256:
145         return ARABIC_CHARSET;
146     case 1257:
147         return BALTIC_CHARSET;
148     case 1258:
149         return VIETNAMESE_CHARSET;
150     case 437:
151     case 737:
152     case 775:
153     case 850:
154     case 852:
155     case 855:
156     case 857:
157     case 860:
158     case 861:
159     case 862:
160     case 863:
161     case 864:
162     case 865:
163     case 866:
164     case 869:
165         return OEM_CHARSET;
166     case 874:
167         return THAI_CHARSET;
168     case 932:
169         return SHIFTJIS_CHARSET;
170     case 936:
171         return GB2312_CHARSET;
172     case 949:
173         return HANGUL_CHARSET;
174     case 950:
175         return CHINESEBIG5_CHARSET;
176     }
177     fprintf(stderr, "Unknown encoding %d - using OEM_CHARSET\n", enc);
178
179     return OEM_CHARSET;
180 }
181
182 static int get_char(const union cptable *cptable, int enc, int index)
183 {
184     /* Korean has the Won sign in place of '\\' */
185     if(enc == 949 && index == '\\')
186         return 0x20a9;
187
188     return cptable->sbcs.cp2uni[index];
189 }
190
191 static void fill_fontinfo(FT_Face face, int enc, FILE *fp, int dpi, unsigned char def_char, int avg_width)
192 {
193     int ascent = 0, il, ppem, descent = 0, width_bytes = 0, space_size, max_width = 0;
194     FNT_HEADER hdr;
195     FONTINFO16 fi;
196     BYTE left_byte, right_byte, byte;
197     DWORD start;
198     CHAR_TABLE_ENTRY *dfCharTable;
199     int i, x, y, x_off, x_end, first_char;
200     FT_UInt gi;
201     int num_names;
202     const union cptable *cptable;
203     FT_SfntName sfntname;
204     TT_OS2 *os2;
205
206 #ifdef HAVE_FT_LOAD_SFNT_TABLE
207     FT_ULong needed;
208     eblcHeader_t *eblc;
209     bitmapSizeTable_t *size_table;
210     int num_sizes;
211 #endif
212
213     cptable = wine_cp_get_table(enc);
214     if(!cptable)
215         error("Can't find codepage %d\n", enc);
216
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);
220         if(!cptable)
221             error("Can't find codepage 1252\n");
222     }
223
224     ppem = face->size->metrics.y_ppem;
225
226 #ifdef HAVE_FT_LOAD_SFNT_TABLE
227     needed = 0;
228     if(FT_Load_Sfnt_Table(face, TTAG_EBLC, 0, NULL, &needed))
229         error("Can't find EBLC table\n");
230
231     eblc = malloc(needed);
232     FT_Load_Sfnt_Table(face, TTAG_EBLC, 0, (FT_Byte *)eblc, &needed);
233
234     num_sizes = GET_BE_DWORD(&eblc->numSizes);
235
236     size_table = (bitmapSizeTable_t *)(eblc + 1);
237     for(i = 0; i < num_sizes; i++)
238     {
239         if(size_table->hori.ascender - size_table->hori.descender == ppem)
240         {
241             ascent = size_table->hori.ascender;
242             descent = -size_table->hori.descender;
243             break;
244         }
245         size_table++;
246     }
247
248     free(eblc);
249 #endif
250
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. */
255     if(ascent == 0) 
256     {
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;
261     }
262
263     start = sizeof(FNT_HEADER) + sizeof(FONTINFO16);
264
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);
268
269     /* Hack: Courier has no internal leading, nor do any Chinese fonts */
270     if(!strcmp(face->family_name, "Courier") || enc == 936 || enc == 950)
271         il = 0;
272
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 */
277
278     dfCharTable = malloc((255 + 3) * sizeof(*dfCharTable));
279     memset(dfCharTable, 0, (255 + 3) * sizeof(*dfCharTable));
280
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);
285
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;
294         }
295     }
296
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);
301         if(gi == 0)
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);
305             continue;
306         }
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;
312     }
313     /* space */
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;
318     /* sentinel */
319     dfCharTable[++i].width = 0;
320     dfCharTable[i].offset = start + (width_bytes * ppem);
321
322     fi.dfType = 0;
323     fi.dfPoints = ((ppem - il) * 72 + dpi/2) / dpi;
324     fi.dfVertRes = dpi;
325     fi.dfHorizRes = 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;
330     fi.dfUnderline = 0;
331     fi.dfStrikeOut = 0;
332     fi.dfWeight = os2->usWeightClass;
333     fi.dfCharSet = lookup_charset(enc);
334     fi.dfPixWidth = (face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) ?
335         avg_width : 0;
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;
341         break;
342     case PAN_FAMILY_DECORATIVE:
343     case PAN_FAMILY_PICTORIAL:
344         fi.dfPitchAndFamily |= FF_DECORATIVE;
345         break;
346     case PAN_FAMILY_TEXT_DISPLAY:
347         if(fi.dfPitchAndFamily == 0) /* fixed */
348             fi.dfPitchAndFamily = FF_MODERN;
349         else {
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;
355                 break;
356             default:
357                 fi.dfPitchAndFamily |= FF_ROMAN;
358             }
359         }
360         break;
361     default:
362         fi.dfPitchAndFamily |= FF_DONTCARE;
363     }
364
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;
370
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 */
375
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);
381
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)) {
385             continue;
386         }
387         assert(dfCharTable[i].width == face->glyph->metrics.horiAdvance >> 6);
388
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) {
393                     fputc('\0', fp);
394                     continue;
395                 }
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) {
399                     fputc('\0', fp);
400                     continue;
401                 }
402                 if(x == x_off)
403                     left_byte = 0;
404                 else
405                     left_byte = face->glyph->bitmap.buffer[(y - (ascent - face->glyph->bitmap_top)) * face->glyph->bitmap.pitch + x - x_off - 1];
406
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)))
409                     right_byte = 0;
410                 else
411                     right_byte = face->glyph->bitmap.buffer[(y - (ascent - face->glyph->bitmap_top)) * face->glyph->bitmap.pitch + x - x_off];
412
413                 byte = (left_byte << (8 - (face->glyph->bitmap_left & 7))) & 0xff;
414                 byte |= ((right_byte >> (face->glyph->bitmap_left & 7)) & 0xff);
415                 fputc(byte, fp);
416             }
417         }
418     }
419     for(x = 0; x < (space_size + 7) / 8; x++) {
420         for(y = 0; y < ppem; y++)
421             fputc('\0', fp);
422     }
423
424     if(width_bytes & 1) {
425         for(y = 0; y < ppem; y++)
426             fputc('\0', fp);
427     }
428     fprintf(fp, "%s", face->family_name);
429     fputc('\0', fp);
430
431 }
432
433
434 int main(int argc, char **argv)
435 {
436     int ppem, enc;
437     FT_Face face;
438     FT_Library lib;
439     int dpi, avg_width;
440     unsigned int def_char;
441     FILE *fp;
442     char output[256];
443     char name[256];
444     char *cp;
445     if(argc != 7) {
446         usage(argv);
447         exit(0);
448     }
449
450     ppem = atoi(argv[2]);
451     enc = atoi(argv[3]);
452     dpi = atoi(argv[4]);
453     def_char = atoi(argv[5]);
454     avg_width = atoi(argv[6]);
455
456     if(FT_Init_FreeType(&lib))
457         error("ft init failure\n");
458
459     if(FT_New_Face(lib, argv[1], 0, &face)) {
460         fprintf(stderr, "Can't open face\n");
461         usage(argv);
462         exit(1);
463     }
464
465     if(FT_Set_Pixel_Sizes(face, ppem, ppem)) {
466         fprintf(stderr, "Can't set size\n");
467         usage(argv);
468         exit(1);
469     }
470
471     strcpy(name, face->family_name);
472     /* FIXME: should add a -o option instead */
473     for(cp = name; *cp; cp++)
474     {
475         if(*cp == ' ') *cp = '_';
476         else if (*cp >= 'A' && *cp <= 'Z') *cp += 'a' - 'A';
477     }
478
479     sprintf(output, "%s-%d-%d-%d.fnt", name, enc, dpi, ppem);
480
481     atexit( cleanup );
482     fp = fopen(output, "w");
483     output_name = output;
484
485     fill_fontinfo(face, enc, fp, dpi, def_char, avg_width);
486     fclose(fp);
487     output_name = NULL;
488     exit(0);
489 }
490
491 #else /* HAVE_FREETYPE */
492
493 int main(int argc, char **argv)
494 {
495     fprintf( stderr, "%s needs to be built with FreeType support\n", argv[0] );
496     exit(1);
497 }
498
499 #endif /* HAVE_FREETYPE */