wineconsole: Italian language support.
[wine/hacks.git] / tools / sfnt2fnt.c
blob51a0e418abba8bb8155394478dd85d1551aacf01
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 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 == '\\')
186 return 0x20a9;
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;
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 FT_ULong needed;
206 eblcHeader_t *eblc;
207 bitmapSizeTable_t *size_table;
208 int num_sizes;
210 cptable = wine_cp_get_table(enc);
211 if(!cptable)
212 error("Can't find codepage %d\n", enc);
214 if(cptable->info.char_size != 1) {
215 /* for double byte charsets we actually want to use cp1252 */
216 cptable = wine_cp_get_table(1252);
217 if(!cptable)
218 error("Can't find codepage 1252\n");
221 ppem = face->size->metrics.y_ppem;
223 needed = 0;
224 if(FT_Load_Sfnt_Table(face, TTAG_EBLC, 0, NULL, &needed))
225 error("Can't find EBLC table\n");
227 eblc = malloc(needed);
228 FT_Load_Sfnt_Table(face, TTAG_EBLC, 0, (FT_Byte *)eblc, &needed);
230 num_sizes = GET_BE_DWORD(&eblc->numSizes);
232 size_table = (bitmapSizeTable_t *)(eblc + 1);
233 for(i = 0; i < num_sizes; i++)
235 if(size_table->hori.ascender - size_table->hori.descender == ppem)
237 ascent = size_table->hori.ascender;
238 descent = -size_table->hori.descender;
239 break;
241 size_table++;
244 /* Versions of fontforge prior to early 2006 have incorrect
245 ascender values in the eblc table, so we won't find the
246 correct bitmapSizeTable. In this case use the height of
247 the Aring glyph instead. */
248 if(ascent == 0)
250 if(FT_Load_Char(face, 0xc5, FT_LOAD_DEFAULT))
251 error("Can't find Aring\n");
252 ascent = face->glyph->metrics.horiBearingY >> 6;
253 descent = ppem - ascent;
256 free(eblc);
258 start = sizeof(FNT_HEADER) + sizeof(FONTINFO16);
260 if(FT_Load_Char(face, 'M', FT_LOAD_DEFAULT))
261 error("Can't find M\n");
262 il = ascent - (face->glyph->metrics.height >> 6);
264 /* Hack: Courier has no internal leading, nor do any Chinese fonts */
265 if(!strcmp(face->family_name, "Courier") || enc == 936 || enc == 950)
266 il = 0;
268 first_char = FT_Get_First_Char(face, &gi);
269 if(first_char == 0xd) /* fontforge's first glyph is 0xd, we'll catch this and skip it */
270 first_char = 32; /* FT_Get_Next_Char for some reason returns too high
271 number in this case */
273 dfCharTable = malloc((255 + 3) * sizeof(*dfCharTable));
274 memset(dfCharTable, 0, (255 + 3) * sizeof(*dfCharTable));
276 memset(&fi, 0, sizeof(fi));
277 fi.dfFirstChar = first_char;
278 fi.dfLastChar = 0xff;
279 start += ((unsigned char)fi.dfLastChar - (unsigned char)fi.dfFirstChar + 3 ) * sizeof(*dfCharTable);
281 num_names = FT_Get_Sfnt_Name_Count(face);
282 for(i = 0; i <num_names; i++) {
283 FT_Get_Sfnt_Name(face, i, &sfntname);
284 if(sfntname.platform_id == 1 && sfntname.encoding_id == 0 &&
285 sfntname.language_id == 0 && sfntname.name_id == 0) {
286 size_t len = min( sfntname.string_len, sizeof(hdr.dfCopyright)-1 );
287 memcpy(hdr.dfCopyright, sfntname.string, len);
288 hdr.dfCopyright[len] = 0;
292 os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
293 for(i = first_char; i < 0x100; i++) {
294 int c = get_char(cptable, enc, i);
295 gi = FT_Get_Char_Index(face, c);
296 if(gi == 0)
297 fprintf(stderr, "Missing glyph for char %04x\n", cptable->sbcs.cp2uni[i]);
298 if(FT_Load_Char(face, c, FT_LOAD_DEFAULT)) {
299 fprintf(stderr, "error loading char %d - bad news!\n", i);
300 continue;
302 dfCharTable[i].width = face->glyph->metrics.horiAdvance >> 6;
303 dfCharTable[i].offset = start + (width_bytes * ppem);
304 width_bytes += ((face->glyph->metrics.horiAdvance >> 6) + 7) >> 3;
305 if(max_width < (face->glyph->metrics.horiAdvance >> 6))
306 max_width = face->glyph->metrics.horiAdvance >> 6;
308 /* space */
309 space_size = (ppem + 3) / 4;
310 dfCharTable[i].width = space_size;
311 dfCharTable[i].offset = start + (width_bytes * ppem);
312 width_bytes += (space_size + 7) >> 3;
313 /* sentinel */
314 dfCharTable[++i].width = 0;
315 dfCharTable[i].offset = start + (width_bytes * ppem);
317 fi.dfType = 0;
318 fi.dfPoints = ((ppem - il) * 72 + dpi/2) / dpi;
319 fi.dfVertRes = dpi;
320 fi.dfHorizRes = dpi;
321 fi.dfAscent = ascent;
322 fi.dfInternalLeading = il;
323 fi.dfExternalLeading = 0;
324 fi.dfItalic = (face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
325 fi.dfUnderline = 0;
326 fi.dfStrikeOut = 0;
327 fi.dfWeight = os2->usWeightClass;
328 fi.dfCharSet = lookup_charset(enc);
329 fi.dfPixWidth = (face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) ?
330 avg_width : 0;
331 fi.dfPixHeight = ppem;
332 fi.dfPitchAndFamily = FT_IS_FIXED_WIDTH(face) ? 0 : TMPF_FIXED_PITCH;
333 switch(os2->panose[PAN_FAMILYTYPE_INDEX]) {
334 case PAN_FAMILY_SCRIPT:
335 fi.dfPitchAndFamily |= FF_SCRIPT;
336 break;
337 case PAN_FAMILY_DECORATIVE:
338 case PAN_FAMILY_PICTORIAL:
339 fi.dfPitchAndFamily |= FF_DECORATIVE;
340 break;
341 case PAN_FAMILY_TEXT_DISPLAY:
342 if(fi.dfPitchAndFamily == 0) /* fixed */
343 fi.dfPitchAndFamily = FF_MODERN;
344 else {
345 switch(os2->panose[PAN_SERIFSTYLE_INDEX]) {
346 case PAN_SERIF_NORMAL_SANS:
347 case PAN_SERIF_OBTUSE_SANS:
348 case PAN_SERIF_PERP_SANS:
349 fi.dfPitchAndFamily |= FF_SWISS;
350 break;
351 default:
352 fi.dfPitchAndFamily |= FF_ROMAN;
355 break;
356 default:
357 fi.dfPitchAndFamily |= FF_DONTCARE;
360 fi.dfAvgWidth = avg_width;
361 fi.dfMaxWidth = max_width;
362 fi.dfDefaultChar = def_char - fi.dfFirstChar;
363 fi.dfBreakChar = ' ' - fi.dfFirstChar;
364 fi.dfWidthBytes = (width_bytes + 1) & ~1;
366 fi.dfFace = start + fi.dfWidthBytes * ppem;
367 fi.dfBitsOffset = start;
368 fi.dfFlags = 0x10; /* DFF_1COLOR */
369 fi.dfFlags |= FT_IS_FIXED_WIDTH(face) ? 1 : 2; /* DFF_FIXED : DFF_PROPORTIONAL */
371 hdr.dfVersion = 0x300;
372 hdr.dfSize = start + fi.dfWidthBytes * ppem + strlen(face->family_name) + 1;
373 fwrite(&hdr, sizeof(hdr), 1, fp);
374 fwrite(&fi, sizeof(fi), 1, fp);
375 fwrite(dfCharTable + fi.dfFirstChar, sizeof(*dfCharTable), ((unsigned char)fi.dfLastChar - (unsigned char)fi.dfFirstChar) + 3, fp);
377 for(i = first_char; i < 0x100; i++) {
378 int c = get_char(cptable, enc, i);
379 if(FT_Load_Char(face, c, FT_LOAD_DEFAULT)) {
380 continue;
382 assert(dfCharTable[i].width == face->glyph->metrics.horiAdvance >> 6);
384 for(x = 0; x < ((dfCharTable[i].width + 7) / 8); x++) {
385 for(y = 0; y < ppem; y++) {
386 if(y < ascent - face->glyph->bitmap_top ||
387 y >= face->glyph->bitmap.rows + ascent - face->glyph->bitmap_top) {
388 fputc('\0', fp);
389 continue;
391 x_off = face->glyph->bitmap_left / 8;
392 x_end = (face->glyph->bitmap_left + face->glyph->bitmap.width - 1) / 8;
393 if(x < x_off || x > x_end) {
394 fputc('\0', fp);
395 continue;
397 if(x == x_off)
398 left_byte = 0;
399 else
400 left_byte = face->glyph->bitmap.buffer[(y - (ascent - face->glyph->bitmap_top)) * face->glyph->bitmap.pitch + x - x_off - 1];
402 /* On the last non-trival output byte (x == x_end) have we got one or two input bytes */
403 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)))
404 right_byte = 0;
405 else
406 right_byte = face->glyph->bitmap.buffer[(y - (ascent - face->glyph->bitmap_top)) * face->glyph->bitmap.pitch + x - x_off];
408 byte = (left_byte << (8 - (face->glyph->bitmap_left & 7))) & 0xff;
409 byte |= ((right_byte >> (face->glyph->bitmap_left & 7)) & 0xff);
410 fputc(byte, fp);
414 for(x = 0; x < (space_size + 7) / 8; x++) {
415 for(y = 0; y < ppem; y++)
416 fputc('\0', fp);
419 if(width_bytes & 1) {
420 for(y = 0; y < ppem; y++)
421 fputc('\0', fp);
423 fprintf(fp, "%s", face->family_name);
424 fputc('\0', fp);
429 int main(int argc, char **argv)
431 int ppem, enc;
432 FT_Face face;
433 FT_Library lib;
434 int dpi, avg_width;
435 unsigned int def_char;
436 FILE *fp;
437 char output[256];
438 char name[256];
439 char *cp;
440 if(argc != 7) {
441 usage(argv);
442 exit(0);
445 ppem = atoi(argv[2]);
446 enc = atoi(argv[3]);
447 dpi = atoi(argv[4]);
448 def_char = atoi(argv[5]);
449 avg_width = atoi(argv[6]);
451 if(FT_Init_FreeType(&lib))
452 error("ft init failure\n");
454 if(FT_New_Face(lib, argv[1], 0, &face)) {
455 fprintf(stderr, "Can't open face\n");
456 usage(argv);
457 exit(1);
460 if(FT_Set_Pixel_Sizes(face, ppem, ppem)) {
461 fprintf(stderr, "Can't set size\n");
462 usage(argv);
463 exit(1);
466 strcpy(name, face->family_name);
467 /* FIXME: should add a -o option instead */
468 for(cp = name; *cp; cp++)
470 if(*cp == ' ') *cp = '_';
471 else if (*cp >= 'A' && *cp <= 'Z') *cp += 'a' - 'A';
474 sprintf(output, "%s-%d-%d-%d.fnt", name, enc, dpi, ppem);
476 atexit( cleanup );
477 fp = fopen(output, "w");
478 output_name = output;
480 fill_fontinfo(face, enc, fp, dpi, def_char, avg_width);
481 fclose(fp);
482 output_name = NULL;
483 exit(0);
486 #else /* HAVE_FREETYPE */
488 int main(int argc, char **argv)
490 fprintf( stderr, "%s needs to be built with FreeType support\n", argv[0] );
491 exit(1);
494 #endif /* HAVE_FREETYPE */