rpcrt4: Don't release the interface pointer on failure.
[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
38 #include "wine/unicode.h"
39 #include "wine/wingdi16.h"
40 #include "wingdi.h"
41
42 #include "pshpack1.h"
43
44 typedef struct
45 {
46     WORD dfVersion;
47     DWORD dfSize;
48     char dfCopyright[60];
49 } FNT_HEADER;
50
51 typedef struct {
52     WORD width;
53     DWORD offset;
54 } CHAR_TABLE_ENTRY;
55
56 #include "poppack.h"
57
58 static void usage(char **argv)
59 {
60     fprintf(stderr, "%s foo.ttf ppem enc dpi def_char avg_width\n", argv[0]);
61     return;
62 }
63
64 #ifndef __GNUC__
65 #define __attribute__(X)
66 #endif
67
68 static void error(const char *s, ...) __attribute__((format (printf, 1, 2)));
69
70 static void error(const char *s, ...)
71 {
72     va_list ap;
73     va_start(ap, s);
74     fprintf(stderr, "Error: ");
75     vfprintf(stderr, s, ap);
76     va_end(ap);
77     exit(1);
78 }
79
80 static int lookup_charset(int enc)
81 {
82     /* FIXME: make winelib app and use TranslateCharsetInfo */
83     switch(enc) {
84     case 1250:
85         return EE_CHARSET;
86     case 1251:
87         return RUSSIAN_CHARSET;
88     case 1252:
89         return ANSI_CHARSET;
90     case 1253:
91         return GREEK_CHARSET;
92     case 1254:
93         return TURKISH_CHARSET;
94     case 1255:
95         return HEBREW_CHARSET;
96     case 1256:
97         return ARABIC_CHARSET;
98     case 1257:
99         return BALTIC_CHARSET;
100     case 1258:
101         return VIETNAMESE_CHARSET;
102     case 437:
103     case 737:
104     case 775:
105     case 850:
106     case 852:
107     case 855:
108     case 857:
109     case 860:
110     case 861:
111     case 862:
112     case 863:
113     case 864:
114     case 865:
115     case 866:
116     case 869:
117         return OEM_CHARSET;
118     case 874:
119         return THAI_CHARSET;
120     case 932:
121         return SHIFTJIS_CHARSET;
122     case 936:
123         return GB2312_CHARSET;
124     case 949:
125         return HANGUL_CHARSET;
126     case 950:
127         return CHINESEBIG5_CHARSET;
128     }
129     fprintf(stderr, "Unknown encoding %d - using OEM_CHARSET\n", enc);
130
131     return OEM_CHARSET;
132 }
133
134 static void fill_fontinfo(FT_Face face, int enc, FILE *fp, int dpi, unsigned char def_char, int avg_width)
135 {
136     int ascent, il, ppem, descent, width_bytes = 0, space_size, max_width = 0;
137     FNT_HEADER hdr;
138     FONTINFO16 fi;
139     BYTE left_byte, right_byte, byte;
140     DWORD start;
141     CHAR_TABLE_ENTRY *dfCharTable;
142     int i, x, y, x_off, x_end, first_char;
143     FT_UInt gi;
144     int num_names;
145     const union cptable *cptable;
146     FT_SfntName sfntname;
147     TT_OS2 *os2;
148     cptable = wine_cp_get_table(enc);
149     if(!cptable)
150         error("Can't find codepage %d\n", enc);
151
152     if(cptable->info.char_size != 1) {
153         /* for double byte charsets we actually want to use cp1252 */
154         cptable = wine_cp_get_table(1252);
155         if(!cptable)
156             error("Can't find codepage 1252\n");
157     }
158
159     ppem = face->size->metrics.y_ppem;
160     start = sizeof(FNT_HEADER) + sizeof(FONTINFO16);
161
162     if(FT_Load_Char(face, 0xc5, FT_LOAD_DEFAULT))
163         error("Can't find Aring\n");
164     ascent = face->glyph->metrics.height >> 6;
165     descent = ppem - ascent;
166     if(FT_Load_Char(face, 'M', FT_LOAD_DEFAULT))
167         error("Can't find M\n");
168     il = ascent - (face->glyph->metrics.height >> 6);
169
170     /* Hack: Courier has no internal leading, nor do any Chinese fonts */
171     if(!strcmp(face->family_name, "Courier") || enc == 936 || enc == 950)
172         il = 0;
173
174     first_char = FT_Get_First_Char(face, &gi);
175     if(first_char == 0xd) /* fontforge's first glyph is 0xd, we'll catch this and skip it */
176         first_char = 32; /* FT_Get_Next_Char for some reason returns too high
177                             number in this case */
178
179     dfCharTable = malloc((255 + 3) * sizeof(*dfCharTable));
180     memset(dfCharTable, 0, (255 + 3) * sizeof(*dfCharTable));
181
182     memset(&fi, 0, sizeof(fi));
183     fi.dfFirstChar = first_char;
184     fi.dfLastChar = 0xff;
185     start += ((unsigned char)fi.dfLastChar - (unsigned char)fi.dfFirstChar + 3 ) * sizeof(*dfCharTable);
186
187     num_names = FT_Get_Sfnt_Name_Count(face);
188     for(i = 0; i <num_names; i++) {
189         FT_Get_Sfnt_Name(face, i, &sfntname);
190         if(sfntname.platform_id == 1 && sfntname.encoding_id == 0 &&
191            sfntname.language_id == 0 && sfntname.name_id == 0) {
192             size_t len = min( sfntname.string_len, sizeof(hdr.dfCopyright)-1 );
193             memcpy(hdr.dfCopyright, sfntname.string, len);
194             hdr.dfCopyright[len] = 0;
195         }
196     }
197
198     os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
199     for(i = first_char; i < 0x100; i++) {
200         gi = FT_Get_Char_Index(face, cptable->sbcs.cp2uni[i]);
201         if(gi == 0)
202             fprintf(stderr, "Missing glyph for char %04x\n", cptable->sbcs.cp2uni[i]);
203         if(FT_Load_Char(face, cptable->sbcs.cp2uni[i], FT_LOAD_DEFAULT)) {
204             fprintf(stderr, "error loading char %d - bad news!\n", i);
205             continue;
206         }
207         dfCharTable[i].width = face->glyph->metrics.horiAdvance >> 6;
208         dfCharTable[i].offset = start + (width_bytes * ppem);
209         width_bytes += ((face->glyph->metrics.horiAdvance >> 6) + 7) >> 3;
210         if(max_width < (face->glyph->metrics.horiAdvance >> 6))
211             max_width = face->glyph->metrics.horiAdvance >> 6;
212     }
213     /* space */
214     space_size = (ppem + 3) / 4;
215     dfCharTable[i].width = space_size;
216     dfCharTable[i].offset = start + (width_bytes * ppem);
217     width_bytes += (space_size + 7) >> 3;
218     /* sentinel */
219     dfCharTable[++i].width = 0;
220     dfCharTable[i].offset = start + (width_bytes * ppem);
221
222     fi.dfType = 0;
223     fi.dfPoints = ((ppem - il) * 72 + dpi/2) / dpi;
224     fi.dfVertRes = dpi;
225     fi.dfHorizRes = dpi;
226     fi.dfAscent = ascent;
227     fi.dfInternalLeading = il;
228     fi.dfExternalLeading = 0;
229     fi.dfItalic = (face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
230     fi.dfUnderline = 0;
231     fi.dfStrikeOut = 0;
232     fi.dfWeight = os2->usWeightClass;
233     fi.dfCharSet = lookup_charset(enc);
234     fi.dfPixWidth = (face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) ?
235         avg_width : 0;
236     fi.dfPixHeight = ppem;
237     fi.dfPitchAndFamily = FT_IS_FIXED_WIDTH(face) ? 0 : TMPF_FIXED_PITCH;
238     switch(os2->panose[PAN_FAMILYTYPE_INDEX]) {
239     case PAN_FAMILY_SCRIPT:
240         fi.dfPitchAndFamily |= FF_SCRIPT;
241         break;
242     case PAN_FAMILY_DECORATIVE:
243     case PAN_FAMILY_PICTORIAL:
244         fi.dfPitchAndFamily |= FF_DECORATIVE;
245         break;
246     case PAN_FAMILY_TEXT_DISPLAY:
247         if(fi.dfPitchAndFamily == 0) /* fixed */
248             fi.dfPitchAndFamily = FF_MODERN;
249         else {
250             switch(os2->panose[PAN_SERIFSTYLE_INDEX]) {
251             case PAN_SERIF_NORMAL_SANS:
252             case PAN_SERIF_OBTUSE_SANS:
253             case PAN_SERIF_PERP_SANS:
254                 fi.dfPitchAndFamily |= FF_SWISS;
255                 break;
256             default:
257                 fi.dfPitchAndFamily |= FF_ROMAN;
258             }
259         }
260         break;
261     default:
262         fi.dfPitchAndFamily |= FF_DONTCARE;
263     }
264
265     fi.dfAvgWidth = avg_width;
266     fi.dfMaxWidth = max_width;
267     fi.dfDefaultChar = def_char - fi.dfFirstChar;
268     fi.dfBreakChar = ' ' - fi.dfFirstChar;
269     fi.dfWidthBytes = (width_bytes + 1) & ~1;
270
271     fi.dfFace = start + fi.dfWidthBytes * ppem;
272     fi.dfBitsOffset = start;
273     fi.dfFlags = 0x10; /* DFF_1COLOR */
274     fi.dfFlags |= FT_IS_FIXED_WIDTH(face) ? 1 : 2; /* DFF_FIXED : DFF_PROPORTIONAL */
275
276     hdr.dfVersion = 0x300;
277     hdr.dfSize = start + fi.dfWidthBytes * ppem + strlen(face->family_name) + 1;
278     fwrite(&hdr, sizeof(hdr), 1, fp);
279     fwrite(&fi, sizeof(fi), 1, fp);
280     fwrite(dfCharTable + fi.dfFirstChar, sizeof(*dfCharTable), ((unsigned char)fi.dfLastChar - (unsigned char)fi.dfFirstChar) + 3, fp);
281
282     for(i = first_char; i < 0x100; i++) {
283         if(FT_Load_Char(face, cptable->sbcs.cp2uni[i], FT_LOAD_DEFAULT)) {
284             continue;
285         }
286         assert(dfCharTable[i].width == face->glyph->metrics.horiAdvance >> 6);
287
288         for(x = 0; x < ((dfCharTable[i].width + 7) / 8); x++) {
289             for(y = 0; y < ppem; y++) {
290                 if(y < ascent - face->glyph->bitmap_top ||
291                    y >=  face->glyph->bitmap.rows + ascent - face->glyph->bitmap_top) {
292                     fputc('\0', fp);
293                     continue;
294                 }
295                 x_off = face->glyph->bitmap_left / 8;
296                 x_end = (face->glyph->bitmap_left + face->glyph->bitmap.width - 1) / 8;
297                 if(x < x_off || x > x_end) {
298                     fputc('\0', fp);
299                     continue;
300                 }
301                 if(x == x_off)
302                     left_byte = 0;
303                 else
304                     left_byte = face->glyph->bitmap.buffer[(y - (ascent - face->glyph->bitmap_top)) * face->glyph->bitmap.pitch + x - x_off - 1];
305
306                 /* On the last non-trival output byte (x == x_end) have we got one or two input bytes */
307                 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)))
308                     right_byte = 0;
309                 else
310                     right_byte = face->glyph->bitmap.buffer[(y - (ascent - face->glyph->bitmap_top)) * face->glyph->bitmap.pitch + x - x_off];
311
312                 byte = (left_byte << (8 - (face->glyph->bitmap_left & 7))) & 0xff;
313                 byte |= ((right_byte >> (face->glyph->bitmap_left & 7)) & 0xff);
314                 fputc(byte, fp);
315             }
316         }
317     }
318     for(x = 0; x < (space_size + 7) / 8; x++) {
319         for(y = 0; y < ppem; y++)
320             fputc('\0', fp);
321     }
322
323     if(width_bytes & 1) {
324         for(y = 0; y < ppem; y++)
325             fputc('\0', fp);
326     }
327     fprintf(fp, "%s", face->family_name);
328     fputc('\0', fp);
329
330 }
331
332
333 int main(int argc, char **argv)
334 {
335     int ppem, enc;
336     FT_Face face;
337     FT_Library lib;
338     int dpi, avg_width;
339     unsigned int def_char;
340     FILE *fp;
341     char output[256];
342     char name[256];
343     char *cp;
344     if(argc != 7) {
345         usage(argv);
346         exit(0);
347     }
348
349     ppem = atoi(argv[2]);
350     enc = atoi(argv[3]);
351     dpi = atoi(argv[4]);
352     def_char = atoi(argv[5]);
353     avg_width = atoi(argv[6]);
354
355     if(FT_Init_FreeType(&lib))
356         error("ft init failure\n");
357
358     if(FT_New_Face(lib, argv[1], 0, &face)) {
359         fprintf(stderr, "Can't open face\n");
360         usage(argv);
361         exit(1);
362     }
363
364     if(FT_Set_Pixel_Sizes(face, ppem, ppem)) {
365         fprintf(stderr, "Can't set size\n");
366         usage(argv);
367         exit(1);
368     }
369
370     strcpy(name, face->family_name);
371     /* FIXME: should add a -o option instead */
372     for(cp = name; *cp; cp++)
373     {
374         if(*cp == ' ') *cp = '_';
375         else if (*cp >= 'A' && *cp <= 'Z') *cp += 'a' - 'A';
376     }
377
378     sprintf(output, "%s-%d-%d-%d.fnt", name, enc, dpi, ppem);
379
380     fp = fopen(output, "w");
381
382     fill_fontinfo(face, enc, fp, dpi, def_char, avg_width);
383     fclose(fp);
384     exit(0);
385 }
386
387 #else /* HAVE_FREETYPE */
388
389 int main(int argc, char **argv)
390 {
391     fprintf( stderr, "%s needs to be built with FreeType support\n", argv[0] );
392     exit(1);
393 }
394
395 #endif /* HAVE_FREETYPE */