widl: Only output code for non-object interfaces in client and server.
[wine.git] / tools / sfnt2fnt.c
blob921bb9a9856192d2a52ccfefd8b308b259d7cafe
1 /*
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
21 #include "config.h"
22 #include "wine/port.h"
24 #include <assert.h>
25 #include <ctype.h>
26 #include <stdio.h>
27 #include <stdlib.h>
29 #ifdef HAVE_FREETYPE
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
39 #include "wine/unicode.h"
40 #include "wine/wingdi16.h"
41 #include "wingdi.h"
43 #include "pshpack1.h"
45 typedef struct
47 WORD dfVersion;
48 DWORD dfSize;
49 char dfCopyright[60];
50 } FNT_HEADER;
52 typedef struct {
53 WORD width;
54 DWORD offset;
55 } CHAR_TABLE_ENTRY;
57 typedef struct {
58 DWORD version;
59 ULONG numSizes;
60 } eblcHeader_t;
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;
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;
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]) ))
96 #include "poppack.h"
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]);
103 return;
106 #ifndef __GNUC__
107 #define __attribute__(X)
108 #endif
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, ...)
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);
128 static int lookup_charset(int enc)
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;
177 fprintf(stderr, "Unknown encoding %d - using OEM_CHARSET\n", enc);
179 return OEM_CHARSET;
182 static void fill_fontinfo(FT_Face face, int enc, FILE *fp, int dpi, unsigned char def_char, int avg_width)
184 int ascent = 0, il, ppem, descent = 0, width_bytes = 0, space_size, max_width = 0;
185 FNT_HEADER hdr;
186 FONTINFO16 fi;
187 BYTE left_byte, right_byte, byte;
188 DWORD start;
189 CHAR_TABLE_ENTRY *dfCharTable;
190 int i, x, y, x_off, x_end, first_char;
191 FT_UInt gi;
192 int num_names;
193 const union cptable *cptable;
194 FT_SfntName sfntname;
195 TT_OS2 *os2;
196 FT_ULong needed;
197 eblcHeader_t *eblc;
198 bitmapSizeTable_t *size_table;
199 int num_sizes;
201 cptable = wine_cp_get_table(enc);
202 if(!cptable)
203 error("Can't find codepage %d\n", enc);
205 if(cptable->info.char_size != 1) {
206 /* for double byte charsets we actually want to use cp1252 */
207 cptable = wine_cp_get_table(1252);
208 if(!cptable)
209 error("Can't find codepage 1252\n");
212 ppem = face->size->metrics.y_ppem;
214 needed = 0;
215 if(FT_Load_Sfnt_Table(face, TTAG_EBLC, 0, NULL, &needed))
216 error("Can't find EBLC table\n");
218 eblc = malloc(needed);
219 FT_Load_Sfnt_Table(face, TTAG_EBLC, 0, (FT_Byte *)eblc, &needed);
221 num_sizes = GET_BE_DWORD(&eblc->numSizes);
223 size_table = (bitmapSizeTable_t *)(eblc + 1);
224 for(i = 0; i < num_sizes; i++)
226 if(size_table->hori.ascender - size_table->hori.descender == ppem)
228 ascent = size_table->hori.ascender;
229 descent = -size_table->hori.descender;
230 break;
232 size_table++;
235 /* Versions of fontforge prior to early 2006 have incorrect
236 ascender values in the eblc table, so we won't find the
237 correct bitmapSizeTable. In this case use the height of
238 the Aring glyph instead. */
239 if(ascent == 0)
241 if(FT_Load_Char(face, 0xc5, FT_LOAD_DEFAULT))
242 error("Can't find Aring\n");
243 ascent = face->glyph->metrics.horiBearingY >> 6;
244 descent = ppem - ascent;
247 free(eblc);
249 start = sizeof(FNT_HEADER) + sizeof(FONTINFO16);
251 if(FT_Load_Char(face, 'M', FT_LOAD_DEFAULT))
252 error("Can't find M\n");
253 il = ascent - (face->glyph->metrics.height >> 6);
255 /* Hack: Courier has no internal leading, nor do any Chinese fonts */
256 if(!strcmp(face->family_name, "Courier") || enc == 936 || enc == 950)
257 il = 0;
259 first_char = FT_Get_First_Char(face, &gi);
260 if(first_char == 0xd) /* fontforge's first glyph is 0xd, we'll catch this and skip it */
261 first_char = 32; /* FT_Get_Next_Char for some reason returns too high
262 number in this case */
264 dfCharTable = malloc((255 + 3) * sizeof(*dfCharTable));
265 memset(dfCharTable, 0, (255 + 3) * sizeof(*dfCharTable));
267 memset(&fi, 0, sizeof(fi));
268 fi.dfFirstChar = first_char;
269 fi.dfLastChar = 0xff;
270 start += ((unsigned char)fi.dfLastChar - (unsigned char)fi.dfFirstChar + 3 ) * sizeof(*dfCharTable);
272 num_names = FT_Get_Sfnt_Name_Count(face);
273 for(i = 0; i <num_names; i++) {
274 FT_Get_Sfnt_Name(face, i, &sfntname);
275 if(sfntname.platform_id == 1 && sfntname.encoding_id == 0 &&
276 sfntname.language_id == 0 && sfntname.name_id == 0) {
277 size_t len = min( sfntname.string_len, sizeof(hdr.dfCopyright)-1 );
278 memcpy(hdr.dfCopyright, sfntname.string, len);
279 hdr.dfCopyright[len] = 0;
283 os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
284 for(i = first_char; i < 0x100; i++) {
285 gi = FT_Get_Char_Index(face, cptable->sbcs.cp2uni[i]);
286 if(gi == 0)
287 fprintf(stderr, "Missing glyph for char %04x\n", cptable->sbcs.cp2uni[i]);
288 if(FT_Load_Char(face, cptable->sbcs.cp2uni[i], FT_LOAD_DEFAULT)) {
289 fprintf(stderr, "error loading char %d - bad news!\n", i);
290 continue;
292 dfCharTable[i].width = face->glyph->metrics.horiAdvance >> 6;
293 dfCharTable[i].offset = start + (width_bytes * ppem);
294 width_bytes += ((face->glyph->metrics.horiAdvance >> 6) + 7) >> 3;
295 if(max_width < (face->glyph->metrics.horiAdvance >> 6))
296 max_width = face->glyph->metrics.horiAdvance >> 6;
298 /* space */
299 space_size = (ppem + 3) / 4;
300 dfCharTable[i].width = space_size;
301 dfCharTable[i].offset = start + (width_bytes * ppem);
302 width_bytes += (space_size + 7) >> 3;
303 /* sentinel */
304 dfCharTable[++i].width = 0;
305 dfCharTable[i].offset = start + (width_bytes * ppem);
307 fi.dfType = 0;
308 fi.dfPoints = ((ppem - il) * 72 + dpi/2) / dpi;
309 fi.dfVertRes = dpi;
310 fi.dfHorizRes = dpi;
311 fi.dfAscent = ascent;
312 fi.dfInternalLeading = il;
313 fi.dfExternalLeading = 0;
314 fi.dfItalic = (face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
315 fi.dfUnderline = 0;
316 fi.dfStrikeOut = 0;
317 fi.dfWeight = os2->usWeightClass;
318 fi.dfCharSet = lookup_charset(enc);
319 fi.dfPixWidth = (face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) ?
320 avg_width : 0;
321 fi.dfPixHeight = ppem;
322 fi.dfPitchAndFamily = FT_IS_FIXED_WIDTH(face) ? 0 : TMPF_FIXED_PITCH;
323 switch(os2->panose[PAN_FAMILYTYPE_INDEX]) {
324 case PAN_FAMILY_SCRIPT:
325 fi.dfPitchAndFamily |= FF_SCRIPT;
326 break;
327 case PAN_FAMILY_DECORATIVE:
328 case PAN_FAMILY_PICTORIAL:
329 fi.dfPitchAndFamily |= FF_DECORATIVE;
330 break;
331 case PAN_FAMILY_TEXT_DISPLAY:
332 if(fi.dfPitchAndFamily == 0) /* fixed */
333 fi.dfPitchAndFamily = FF_MODERN;
334 else {
335 switch(os2->panose[PAN_SERIFSTYLE_INDEX]) {
336 case PAN_SERIF_NORMAL_SANS:
337 case PAN_SERIF_OBTUSE_SANS:
338 case PAN_SERIF_PERP_SANS:
339 fi.dfPitchAndFamily |= FF_SWISS;
340 break;
341 default:
342 fi.dfPitchAndFamily |= FF_ROMAN;
345 break;
346 default:
347 fi.dfPitchAndFamily |= FF_DONTCARE;
350 fi.dfAvgWidth = avg_width;
351 fi.dfMaxWidth = max_width;
352 fi.dfDefaultChar = def_char - fi.dfFirstChar;
353 fi.dfBreakChar = ' ' - fi.dfFirstChar;
354 fi.dfWidthBytes = (width_bytes + 1) & ~1;
356 fi.dfFace = start + fi.dfWidthBytes * ppem;
357 fi.dfBitsOffset = start;
358 fi.dfFlags = 0x10; /* DFF_1COLOR */
359 fi.dfFlags |= FT_IS_FIXED_WIDTH(face) ? 1 : 2; /* DFF_FIXED : DFF_PROPORTIONAL */
361 hdr.dfVersion = 0x300;
362 hdr.dfSize = start + fi.dfWidthBytes * ppem + strlen(face->family_name) + 1;
363 fwrite(&hdr, sizeof(hdr), 1, fp);
364 fwrite(&fi, sizeof(fi), 1, fp);
365 fwrite(dfCharTable + fi.dfFirstChar, sizeof(*dfCharTable), ((unsigned char)fi.dfLastChar - (unsigned char)fi.dfFirstChar) + 3, fp);
367 for(i = first_char; i < 0x100; i++) {
368 if(FT_Load_Char(face, cptable->sbcs.cp2uni[i], FT_LOAD_DEFAULT)) {
369 continue;
371 assert(dfCharTable[i].width == face->glyph->metrics.horiAdvance >> 6);
373 for(x = 0; x < ((dfCharTable[i].width + 7) / 8); x++) {
374 for(y = 0; y < ppem; y++) {
375 if(y < ascent - face->glyph->bitmap_top ||
376 y >= face->glyph->bitmap.rows + ascent - face->glyph->bitmap_top) {
377 fputc('\0', fp);
378 continue;
380 x_off = face->glyph->bitmap_left / 8;
381 x_end = (face->glyph->bitmap_left + face->glyph->bitmap.width - 1) / 8;
382 if(x < x_off || x > x_end) {
383 fputc('\0', fp);
384 continue;
386 if(x == x_off)
387 left_byte = 0;
388 else
389 left_byte = face->glyph->bitmap.buffer[(y - (ascent - face->glyph->bitmap_top)) * face->glyph->bitmap.pitch + x - x_off - 1];
391 /* On the last non-trival output byte (x == x_end) have we got one or two input bytes */
392 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)))
393 right_byte = 0;
394 else
395 right_byte = face->glyph->bitmap.buffer[(y - (ascent - face->glyph->bitmap_top)) * face->glyph->bitmap.pitch + x - x_off];
397 byte = (left_byte << (8 - (face->glyph->bitmap_left & 7))) & 0xff;
398 byte |= ((right_byte >> (face->glyph->bitmap_left & 7)) & 0xff);
399 fputc(byte, fp);
403 for(x = 0; x < (space_size + 7) / 8; x++) {
404 for(y = 0; y < ppem; y++)
405 fputc('\0', fp);
408 if(width_bytes & 1) {
409 for(y = 0; y < ppem; y++)
410 fputc('\0', fp);
412 fprintf(fp, "%s", face->family_name);
413 fputc('\0', fp);
418 int main(int argc, char **argv)
420 int ppem, enc;
421 FT_Face face;
422 FT_Library lib;
423 int dpi, avg_width;
424 unsigned int def_char;
425 FILE *fp;
426 char output[256];
427 char name[256];
428 char *cp;
429 if(argc != 7) {
430 usage(argv);
431 exit(0);
434 ppem = atoi(argv[2]);
435 enc = atoi(argv[3]);
436 dpi = atoi(argv[4]);
437 def_char = atoi(argv[5]);
438 avg_width = atoi(argv[6]);
440 if(FT_Init_FreeType(&lib))
441 error("ft init failure\n");
443 if(FT_New_Face(lib, argv[1], 0, &face)) {
444 fprintf(stderr, "Can't open face\n");
445 usage(argv);
446 exit(1);
449 if(FT_Set_Pixel_Sizes(face, ppem, ppem)) {
450 fprintf(stderr, "Can't set size\n");
451 usage(argv);
452 exit(1);
455 strcpy(name, face->family_name);
456 /* FIXME: should add a -o option instead */
457 for(cp = name; *cp; cp++)
459 if(*cp == ' ') *cp = '_';
460 else if (*cp >= 'A' && *cp <= 'Z') *cp += 'a' - 'A';
463 sprintf(output, "%s-%d-%d-%d.fnt", name, enc, dpi, ppem);
465 atexit( cleanup );
466 fp = fopen(output, "w");
467 output_name = output;
469 fill_fontinfo(face, enc, fp, dpi, def_char, avg_width);
470 fclose(fp);
471 output_name = NULL;
472 exit(0);
475 #else /* HAVE_FREETYPE */
477 int main(int argc, char **argv)
479 fprintf( stderr, "%s needs to be built with FreeType support\n", argv[0] );
480 exit(1);
483 #endif /* HAVE_FREETYPE */