urlmon/tests: Use BOOL type where appropriate.
[wine.git] / tools / sfnt2fnt.c
blob1952c5cf162a38877d966b7a6e56323113789a2b
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
22 #include "wine/port.h"
24 #include <assert.h>
25 #include <ctype.h>
26 #include <errno.h>
27 #include <signal.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #ifdef HAVE_GETOPT_H
31 # include <getopt.h>
32 #endif
34 #ifdef HAVE_FREETYPE
36 #ifdef HAVE_FT2BUILD_H
37 #include <ft2build.h>
38 #endif
39 #include FT_FREETYPE_H
40 #include FT_SFNT_NAMES_H
41 #include FT_TRUETYPE_TABLES_H
42 #include FT_TRUETYPE_TAGS_H
44 #include "wine/unicode.h"
45 #include "wingdi.h"
46 #include "basetsd.h"
48 #include "pshpack1.h"
50 typedef struct
52 INT16 dfType;
53 INT16 dfPoints;
54 INT16 dfVertRes;
55 INT16 dfHorizRes;
56 INT16 dfAscent;
57 INT16 dfInternalLeading;
58 INT16 dfExternalLeading;
59 BYTE dfItalic;
60 BYTE dfUnderline;
61 BYTE dfStrikeOut;
62 INT16 dfWeight;
63 BYTE dfCharSet;
64 INT16 dfPixWidth;
65 INT16 dfPixHeight;
66 BYTE dfPitchAndFamily;
67 INT16 dfAvgWidth;
68 INT16 dfMaxWidth;
69 BYTE dfFirstChar;
70 BYTE dfLastChar;
71 BYTE dfDefaultChar;
72 BYTE dfBreakChar;
73 INT16 dfWidthBytes;
74 LONG dfDevice;
75 LONG dfFace;
76 LONG dfBitsPointer;
77 LONG dfBitsOffset;
78 BYTE dfReserved;
79 LONG dfFlags;
80 INT16 dfAspace;
81 INT16 dfBspace;
82 INT16 dfCspace;
83 LONG dfColorPointer;
84 LONG dfReserved1[4];
85 } FONTINFO16;
87 typedef struct
89 WORD dfVersion;
90 DWORD dfSize;
91 char dfCopyright[60];
92 FONTINFO16 fi;
93 } FNT_HEADER;
95 typedef struct
97 WORD offset;
98 WORD length;
99 WORD flags;
100 WORD id;
101 WORD handle;
102 WORD usage;
103 } NE_NAMEINFO;
105 typedef struct
107 WORD type_id;
108 WORD count;
109 DWORD resloader;
110 } NE_TYPEINFO;
112 #define NE_FFLAGS_SINGLEDATA 0x0001
113 #define NE_FFLAGS_MULTIPLEDATA 0x0002
114 #define NE_FFLAGS_WIN32 0x0010
115 #define NE_FFLAGS_FRAMEBUF 0x0100
116 #define NE_FFLAGS_CONSOLE 0x0200
117 #define NE_FFLAGS_GUI 0x0300
118 #define NE_FFLAGS_SELFLOAD 0x0800
119 #define NE_FFLAGS_LINKERROR 0x2000
120 #define NE_FFLAGS_CALLWEP 0x4000
121 #define NE_FFLAGS_LIBMODULE 0x8000
123 #define NE_OSFLAGS_WINDOWS 0x02
125 #define NE_RSCTYPE_FONTDIR 0x8007
126 #define NE_RSCTYPE_FONT 0x8008
127 #define NE_RSCTYPE_SCALABLE_FONTPATH 0x80cc
129 #define NE_SEGFLAGS_DATA 0x0001
130 #define NE_SEGFLAGS_ALLOCATED 0x0002
131 #define NE_SEGFLAGS_LOADED 0x0004
132 #define NE_SEGFLAGS_ITERATED 0x0008
133 #define NE_SEGFLAGS_MOVEABLE 0x0010
134 #define NE_SEGFLAGS_SHAREABLE 0x0020
135 #define NE_SEGFLAGS_PRELOAD 0x0040
136 #define NE_SEGFLAGS_EXECUTEONLY 0x0080
137 #define NE_SEGFLAGS_READONLY 0x0080
138 #define NE_SEGFLAGS_RELOC_DATA 0x0100
139 #define NE_SEGFLAGS_SELFLOAD 0x0800
140 #define NE_SEGFLAGS_DISCARDABLE 0x1000
141 #define NE_SEGFLAGS_32BIT 0x2000
143 typedef struct {
144 WORD width;
145 DWORD offset;
146 } CHAR_TABLE_ENTRY;
148 typedef struct {
149 DWORD version;
150 ULONG numSizes;
151 } eblcHeader_t;
153 typedef struct {
154 CHAR ascender;
155 CHAR descender;
156 BYTE widthMax;
157 CHAR caretSlopeNumerator;
158 CHAR caretSlopeDenominator;
159 CHAR caretOffset;
160 CHAR minOriginSB;
161 CHAR minAdvanceSB;
162 CHAR maxBeforeBL;
163 CHAR maxAfterBL;
164 CHAR pad1;
165 CHAR pad2;
166 } sbitLineMetrics_t;
168 typedef struct {
169 ULONG indexSubTableArrayOffset;
170 ULONG indexTableSize;
171 ULONG numberOfIndexSubTables;
172 ULONG colorRef;
173 sbitLineMetrics_t hori;
174 sbitLineMetrics_t vert;
175 USHORT startGlyphIndex;
176 USHORT endGlyphIndex;
177 BYTE ppemX;
178 BYTE ppemY;
179 BYTE bitDepth;
180 CHAR flags;
181 } bitmapSizeTable_t;
183 typedef struct
185 FT_Int major;
186 FT_Int minor;
187 FT_Int patch;
188 } FT_Version_t;
189 static FT_Version_t FT_Version;
191 #include "poppack.h"
193 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
194 #define GET_BE_DWORD(ptr) ((DWORD)MAKELONG( GET_BE_WORD(&((WORD *)(ptr))[1]), \
195 GET_BE_WORD(&((WORD *)(ptr))[0]) ))
196 #ifdef WORDS_BIGENDIAN
197 static WORD byteswap_word(WORD x)
199 return ( ( (x & 0xff) << 8) |
200 ( (x & 0xff00) >> 8) );
202 static DWORD byteswap_dword(DWORD x)
204 return ( ( (x & 0xff) << 24) |
205 ( (x & 0xff00) << 8) |
206 ( (x & 0xff0000) >> 8) |
207 ( (x & 0xff000000) >> 24) );
209 # define PUT_LE_WORD(x) byteswap_word(x)
210 # define PUT_LE_DWORD(x) byteswap_dword(x)
211 #else
212 # define PUT_LE_WORD(x) (x)
213 # define PUT_LE_DWORD(x) (x)
214 #endif
216 struct fontinfo
218 FNT_HEADER hdr;
219 CHAR_TABLE_ENTRY dfCharTable[258];
220 BYTE *data;
223 static const BYTE MZ_hdr[] =
225 'M', 'Z', 0x0d, 0x01, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
226 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
227 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
228 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
229 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 'T', 'h',
230 'i', 's', ' ', 'P', 'r', 'o', 'g', 'r', 'a', 'm', ' ', 'c', 'a', 'n', 'n', 'o',
231 't', ' ', 'b', 'e', ' ', 'r', 'u', 'n', ' ', 'i', 'n', ' ', 'D', 'O', 'S', ' ',
232 'm', 'o', 'd', 'e', 0x0d, 0x0a, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
235 static char *option_output;
236 static int option_defchar = ' ';
237 static int option_dpi = 96;
238 static int option_fnt_mode = 0;
239 static int option_quiet = 0;
241 static const char *output_name;
243 static FT_Library ft_library;
245 static void usage(char **argv)
247 fprintf(stderr, "%s [options] input.ttf ppem,enc,avg_width ...\n", argv[0]);
248 fprintf(stderr, "Options:\n");
249 fprintf(stderr, " -h Display help\n" );
250 fprintf(stderr, " -d char Set the font default char\n" );
251 fprintf(stderr, " -o file Set output file name\n" );
252 fprintf(stderr, " -q Quiet mode\n" );
253 fprintf(stderr, " -r dpi Set resolution in DPI (default: 96)\n" );
254 fprintf(stderr, " -s Single .fnt file mode\n" );
257 #ifndef __GNUC__
258 #define __attribute__(X)
259 #endif
261 /* atexit handler to cleanup files */
262 static void cleanup(void)
264 if (output_name) unlink( output_name );
267 static void exit_on_signal( int sig )
269 exit(1); /* this will call the atexit functions */
272 static void error(const char *s, ...) __attribute__((format (printf, 1, 2)));
274 static void error(const char *s, ...)
276 va_list ap;
277 va_start(ap, s);
278 fprintf(stderr, "Error: ");
279 vfprintf(stderr, s, ap);
280 va_end(ap);
281 exit(1);
284 static const char *get_face_name( const struct fontinfo *info )
286 return (const char *)info->data + info->hdr.fi.dfFace - info->hdr.fi.dfBitsOffset;
289 static int lookup_charset(int enc)
291 /* FIXME: make winelib app and use TranslateCharsetInfo */
292 switch(enc) {
293 case 1250:
294 return EE_CHARSET;
295 case 1251:
296 return RUSSIAN_CHARSET;
297 case 1252:
298 return ANSI_CHARSET;
299 case 1253:
300 return GREEK_CHARSET;
301 case 1254:
302 return TURKISH_CHARSET;
303 case 1255:
304 return HEBREW_CHARSET;
305 case 1256:
306 return ARABIC_CHARSET;
307 case 1257:
308 return BALTIC_CHARSET;
309 case 1258:
310 return VIETNAMESE_CHARSET;
311 case 437:
312 case 737:
313 case 775:
314 case 850:
315 case 852:
316 case 855:
317 case 857:
318 case 860:
319 case 861:
320 case 862:
321 case 863:
322 case 864:
323 case 865:
324 case 866:
325 case 869:
326 return OEM_CHARSET;
327 case 874:
328 return THAI_CHARSET;
329 case 932:
330 return SHIFTJIS_CHARSET;
331 case 936:
332 return GB2312_CHARSET;
333 case 949:
334 return HANGUL_CHARSET;
335 case 950:
336 return CHINESEBIG5_CHARSET;
338 fprintf(stderr, "Unknown encoding %d - using OEM_CHARSET\n", enc);
340 return OEM_CHARSET;
343 static int get_char(const union cptable *cptable, int enc, int index)
345 /* Korean has the Won sign in place of '\\' */
346 if(enc == 949 && index == '\\')
347 return 0x20a9;
349 return cptable->sbcs.cp2uni[index];
352 static struct fontinfo *fill_fontinfo( const char *face_name, int ppem, int enc, int dpi,
353 unsigned char def_char, int avg_width )
355 FT_Face face;
356 int ascent = 0, il, el, width_bytes = 0, space_size, max_width = 0;
357 BYTE left_byte, right_byte, byte;
358 DWORD start;
359 int i, x, y, x_off, x_end, first_char;
360 FT_UInt gi;
361 int num_names;
362 const union cptable *cptable;
363 FT_SfntName sfntname;
364 TT_OS2 *os2;
365 FT_ULong needed;
366 eblcHeader_t *eblc;
367 bitmapSizeTable_t *size_table;
368 int num_sizes;
369 struct fontinfo *info;
370 size_t data_pos;
372 if (FT_New_Face(ft_library, face_name, 0, &face)) error( "Cannot open face %s\n", face_name );
373 if (FT_Set_Pixel_Sizes(face, ppem, ppem)) error( "cannot set face size to %u\n", ppem );
375 cptable = wine_cp_get_table(enc);
376 if(!cptable)
377 error("Can't find codepage %d\n", enc);
379 if(cptable->info.char_size != 1) {
380 /* for double byte charsets we actually want to use cp1252 */
381 cptable = wine_cp_get_table(1252);
382 if(!cptable)
383 error("Can't find codepage 1252\n");
386 assert( face->size->metrics.y_ppem == ppem );
388 needed = 0;
389 if (FT_Load_Sfnt_Table(face, TTAG_EBLC, 0, NULL, &needed))
390 fprintf(stderr,"Can't find EBLC table\n");
391 else
393 eblc = malloc(needed);
394 FT_Load_Sfnt_Table(face, TTAG_EBLC, 0, (FT_Byte *)eblc, &needed);
396 num_sizes = GET_BE_DWORD(&eblc->numSizes);
398 size_table = (bitmapSizeTable_t *)(eblc + 1);
399 for(i = 0; i < num_sizes; i++)
401 if( (signed char)size_table->hori.ascender - (signed char)size_table->hori.descender == ppem)
403 ascent = size_table->hori.ascender;
404 break;
406 size_table++;
409 free(eblc);
412 /* Versions of fontforge prior to early 2006 have incorrect
413 ascender values in the eblc table, so we won't find the
414 correct bitmapSizeTable. In this case use the height of
415 the Aring glyph instead. */
416 if(ascent == 0)
418 if(FT_Load_Char(face, 0xc5, FT_LOAD_DEFAULT))
419 error("Can't find Aring\n");
420 ascent = face->glyph->metrics.horiBearingY >> 6;
423 start = sizeof(FNT_HEADER);
425 if(FT_Load_Char(face, 'M', FT_LOAD_DEFAULT))
426 error("Can't find M\n");
427 il = ascent - (face->glyph->metrics.height >> 6);
429 /* Hack: Courier has no internal leading, nor do any Chinese or Japanese fonts */
430 if(!strcmp(face->family_name, "Courier") || enc == 936 || enc == 950 || enc == 932)
431 il = 0;
432 else if (!strcmp(face->family_name, "Fixedsys"))
433 il = 3;
435 /* Japanese System font has an external leading */
436 if (!strcmp(face->family_name, "System") && enc == 932)
437 el = 2;
438 else
439 el = 0;
441 first_char = FT_Get_First_Char(face, &gi);
442 if(first_char == 0xd) /* fontforge's first glyph is 0xd, we'll catch this and skip it */
443 first_char = 32; /* FT_Get_Next_Char for some reason returns too high
444 number in this case */
446 info = calloc( 1, sizeof(*info) );
448 info->hdr.fi.dfFirstChar = first_char;
449 info->hdr.fi.dfLastChar = 0xff;
450 start += ((unsigned char)info->hdr.fi.dfLastChar - (unsigned char)info->hdr.fi.dfFirstChar + 3 ) * sizeof(*info->dfCharTable);
452 num_names = FT_Get_Sfnt_Name_Count(face);
453 for(i = 0; i <num_names; i++) {
454 FT_Get_Sfnt_Name(face, i, &sfntname);
455 if(sfntname.platform_id == 1 && sfntname.encoding_id == 0 &&
456 sfntname.language_id == 0 && sfntname.name_id == 0) {
457 size_t len = min( sfntname.string_len, sizeof(info->hdr.dfCopyright)-1 );
458 memcpy(info->hdr.dfCopyright, sfntname.string, len);
459 info->hdr.dfCopyright[len] = 0;
463 os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
464 for(i = first_char; i < 0x100; i++) {
465 int c = get_char(cptable, enc, i);
466 gi = FT_Get_Char_Index(face, c);
467 if(gi == 0 && !option_quiet)
468 fprintf(stderr, "warning: %s %u: missing glyph for char %04x\n",
469 face->family_name, ppem, cptable->sbcs.cp2uni[i]);
470 if(FT_Load_Char(face, c, FT_LOAD_DEFAULT)) {
471 fprintf(stderr, "error loading char %d - bad news!\n", i);
472 continue;
474 info->dfCharTable[i].width = face->glyph->metrics.horiAdvance >> 6;
475 info->dfCharTable[i].offset = start + (width_bytes * ppem);
476 width_bytes += ((face->glyph->metrics.horiAdvance >> 6) + 7) >> 3;
477 if(max_width < (face->glyph->metrics.horiAdvance >> 6))
478 max_width = face->glyph->metrics.horiAdvance >> 6;
480 /* space */
481 space_size = (ppem + 3) / 4;
482 info->dfCharTable[i].width = space_size;
483 info->dfCharTable[i].offset = start + (width_bytes * ppem);
484 width_bytes += (space_size + 7) >> 3;
485 /* sentinel */
486 info->dfCharTable[++i].width = 0;
487 info->dfCharTable[i].offset = start + (width_bytes * ppem);
489 info->hdr.fi.dfType = 0;
490 info->hdr.fi.dfPoints = ((ppem - il - el) * 72 + dpi/2) / dpi;
491 info->hdr.fi.dfVertRes = dpi;
492 info->hdr.fi.dfHorizRes = dpi;
493 info->hdr.fi.dfAscent = ascent;
494 info->hdr.fi.dfInternalLeading = il;
495 info->hdr.fi.dfExternalLeading = el;
496 info->hdr.fi.dfItalic = (face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
497 info->hdr.fi.dfUnderline = 0;
498 info->hdr.fi.dfStrikeOut = 0;
499 info->hdr.fi.dfWeight = os2->usWeightClass;
500 info->hdr.fi.dfCharSet = lookup_charset(enc);
501 info->hdr.fi.dfPixWidth = (face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) ? avg_width : 0;
502 info->hdr.fi.dfPixHeight = ppem;
503 info->hdr.fi.dfPitchAndFamily = FT_IS_FIXED_WIDTH(face) ? 0 : TMPF_FIXED_PITCH;
504 switch(os2->panose[PAN_FAMILYTYPE_INDEX]) {
505 case PAN_FAMILY_SCRIPT:
506 info->hdr.fi.dfPitchAndFamily |= FF_SCRIPT;
507 break;
508 case PAN_FAMILY_DECORATIVE:
509 case PAN_FAMILY_PICTORIAL:
510 info->hdr.fi.dfPitchAndFamily |= FF_DECORATIVE;
511 break;
512 case PAN_FAMILY_TEXT_DISPLAY:
513 if(info->hdr.fi.dfPitchAndFamily == 0) /* fixed */
514 info->hdr.fi.dfPitchAndFamily = FF_MODERN;
515 else {
516 switch(os2->panose[PAN_SERIFSTYLE_INDEX]) {
517 case PAN_SERIF_NORMAL_SANS:
518 case PAN_SERIF_OBTUSE_SANS:
519 case PAN_SERIF_PERP_SANS:
520 info->hdr.fi.dfPitchAndFamily |= FF_SWISS;
521 break;
522 default:
523 info->hdr.fi.dfPitchAndFamily |= FF_ROMAN;
526 break;
527 default:
528 info->hdr.fi.dfPitchAndFamily |= FF_DONTCARE;
531 info->hdr.fi.dfAvgWidth = avg_width;
532 info->hdr.fi.dfMaxWidth = (enc == 932) ? avg_width * 2 : max_width;
533 info->hdr.fi.dfDefaultChar = def_char - info->hdr.fi.dfFirstChar;
534 info->hdr.fi.dfBreakChar = ' ' - info->hdr.fi.dfFirstChar;
535 info->hdr.fi.dfWidthBytes = (width_bytes + 1) & ~1;
537 info->hdr.fi.dfFace = start + info->hdr.fi.dfWidthBytes * ppem;
538 info->hdr.fi.dfBitsOffset = start;
539 info->hdr.fi.dfFlags = 0x10; /* DFF_1COLOR */
540 info->hdr.fi.dfFlags |= FT_IS_FIXED_WIDTH(face) ? 1 : 2; /* DFF_FIXED : DFF_PROPORTIONAL */
542 info->hdr.dfVersion = 0x300;
543 info->hdr.dfSize = start + info->hdr.fi.dfWidthBytes * ppem + strlen(face->family_name) + 1;
545 info->data = calloc( info->hdr.dfSize - start, 1 );
546 data_pos = 0;
548 for(i = first_char; i < 0x100; i++) {
549 int c = get_char(cptable, enc, i);
550 if(FT_Load_Char(face, c, FT_LOAD_DEFAULT)) {
551 continue;
553 assert(info->dfCharTable[i].width == face->glyph->metrics.horiAdvance >> 6);
555 for(x = 0; x < ((info->dfCharTable[i].width + 7) / 8); x++) {
556 for(y = 0; y < ppem; y++) {
557 if(y < ascent - face->glyph->bitmap_top ||
558 y >= face->glyph->bitmap.rows + ascent - face->glyph->bitmap_top) {
559 info->data[data_pos++] = 0;
560 continue;
562 x_off = face->glyph->bitmap_left / 8;
563 x_end = (face->glyph->bitmap_left + face->glyph->bitmap.width - 1) / 8;
564 if(x < x_off || x > x_end) {
565 info->data[data_pos++] = 0;
566 continue;
568 if(x == x_off)
569 left_byte = 0;
570 else
571 left_byte = face->glyph->bitmap.buffer[(y - (ascent - face->glyph->bitmap_top)) * face->glyph->bitmap.pitch + x - x_off - 1];
573 /* On the last non-trivial output byte (x == x_end) have we got one or two input bytes */
574 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)))
575 right_byte = 0;
576 else
577 right_byte = face->glyph->bitmap.buffer[(y - (ascent - face->glyph->bitmap_top)) * face->glyph->bitmap.pitch + x - x_off];
579 byte = (left_byte << (8 - (face->glyph->bitmap_left & 7))) & 0xff;
580 byte |= ((right_byte >> (face->glyph->bitmap_left & 7)) & 0xff);
581 info->data[data_pos++] = byte;
585 data_pos += ((space_size + 7) / 8) * ppem;
586 if (width_bytes & 1) data_pos += ppem;
588 memcpy( info->data + data_pos, face->family_name, strlen( face->family_name ));
589 data_pos += strlen( face->family_name ) + 1;
590 assert( start + data_pos == info->hdr.dfSize );
592 FT_Done_Face( face );
593 return info;
596 static void adjust_fontinfo( FONTINFO16 * fi )
598 fi->dfType = PUT_LE_WORD(fi->dfType);
599 fi->dfPoints = PUT_LE_WORD(fi->dfPoints);
600 fi->dfVertRes = PUT_LE_WORD(fi->dfVertRes);
601 fi->dfHorizRes = PUT_LE_WORD(fi->dfHorizRes);
602 fi->dfAscent = PUT_LE_WORD(fi->dfAscent);
603 fi->dfInternalLeading = PUT_LE_WORD(fi->dfInternalLeading);
604 fi->dfExternalLeading = PUT_LE_WORD(fi->dfExternalLeading);
605 fi->dfWeight = PUT_LE_WORD(fi->dfWeight);
606 fi->dfPixWidth = PUT_LE_WORD(fi->dfPixWidth);
607 fi->dfPixHeight = PUT_LE_WORD(fi->dfPixHeight);
608 fi->dfAvgWidth = PUT_LE_WORD(fi->dfAvgWidth);
609 fi->dfMaxWidth = PUT_LE_WORD(fi->dfMaxWidth);
610 fi->dfWidthBytes = PUT_LE_WORD(fi->dfWidthBytes);
611 fi->dfAspace = PUT_LE_WORD(fi->dfAspace);
612 fi->dfBspace = PUT_LE_WORD(fi->dfBspace);
613 fi->dfCspace = PUT_LE_WORD(fi->dfCspace);
614 fi->dfDevice = PUT_LE_DWORD(fi->dfDevice);
615 fi->dfFace = PUT_LE_DWORD(fi->dfFace);
616 fi->dfBitsPointer = PUT_LE_DWORD(fi->dfBitsPointer);
617 fi->dfBitsOffset = PUT_LE_DWORD(fi->dfBitsOffset);
618 fi->dfFlags = PUT_LE_DWORD(fi->dfFlags);
619 fi->dfColorPointer = PUT_LE_DWORD(fi->dfColorPointer);
622 static void write_fontinfo( const struct fontinfo *info, FILE *fp )
624 FNT_HEADER tmp_hdr;
625 int num_chars, i;
626 CHAR_TABLE_ENTRY tmp_chartable[258];
627 memcpy(&tmp_hdr, &info->hdr, sizeof(info->hdr));
628 tmp_hdr.dfVersion = PUT_LE_WORD(tmp_hdr.dfVersion);
629 tmp_hdr.dfSize = PUT_LE_DWORD(tmp_hdr.dfSize);
630 adjust_fontinfo(&(tmp_hdr.fi));
631 fwrite( &tmp_hdr, sizeof(info->hdr), 1, fp );
632 num_chars = ((unsigned char)info->hdr.fi.dfLastChar - (unsigned char)info->hdr.fi.dfFirstChar) + 3;
634 memcpy(&tmp_chartable, info->dfCharTable + info->hdr.fi.dfFirstChar, num_chars * sizeof(CHAR_TABLE_ENTRY));
635 for (i=0; i < num_chars; ++i) {
636 tmp_chartable[i].width = PUT_LE_WORD(tmp_chartable[i].width);
637 tmp_chartable[i].offset = PUT_LE_DWORD(tmp_chartable[i].offset);
639 fwrite( tmp_chartable, sizeof(CHAR_TABLE_ENTRY), num_chars, fp );
640 fwrite( info->data, info->hdr.dfSize - info->hdr.fi.dfBitsOffset, 1, fp );
643 /* parse options from the argv array and remove all the recognized ones */
644 static char **parse_options( int argc, char **argv )
646 int optc;
648 while ((optc = getopt( argc, argv, "d:ho:qr:s" )) != -1)
650 switch(optc)
652 case 'd':
653 option_defchar = atoi( optarg );
654 break;
655 case 'o':
656 option_output = strdup( optarg );
657 break;
658 case 'q':
659 option_quiet = 1;
660 break;
661 case 'r':
662 option_dpi = atoi( optarg );
663 break;
664 case 's':
665 option_fnt_mode = 1;
666 break;
667 case 'h':
668 usage(argv);
669 exit(0);
670 case '?':
671 usage(argv);
672 exit(1);
675 return &argv[optind];
678 int main(int argc, char **argv)
680 int i, j;
681 FILE *ofp;
682 short align, num_files;
683 int resource_table_len, non_resident_name_len, resident_name_len;
684 unsigned short resource_table_off, resident_name_off, module_ref_off, non_resident_name_off, fontdir_off, font_off;
685 char resident_name[200];
686 int fontdir_len = 2;
687 char non_resident_name[200];
688 unsigned short first_res = 0x0050, pad, res;
689 IMAGE_OS2_HEADER NE_hdr;
690 NE_TYPEINFO rc_type;
691 NE_NAMEINFO rc_name;
692 struct fontinfo **info;
693 char *input_file;
694 char **args;
695 short tmp16;
697 args = parse_options( argc, argv );
699 input_file = *args++;
700 if (!input_file || !*args)
702 usage(argv);
703 exit(1);
706 if(FT_Init_FreeType(&ft_library))
707 error("ft init failure\n");
709 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
710 FT_Library_Version(ft_library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
712 num_files = 0;
713 while (args[num_files]) num_files++;
715 if (option_fnt_mode && num_files > 1)
716 error( "can only specify one font in .fnt mode\n" );
718 info = malloc( num_files * sizeof(*info) );
719 for (i = 0; i < num_files; i++)
721 int ppem, enc, avg_width;
722 const char *name;
724 if (sscanf( args[i], "%d,%d,%d", &ppem, &enc, &avg_width ) != 3)
726 usage(argv);
727 exit(1);
729 if (!(info[i] = fill_fontinfo( input_file, ppem, enc, option_dpi, option_defchar, avg_width )))
730 exit(1);
732 name = get_face_name( info[i] );
733 fontdir_len += 0x74 + strlen(name) + 1;
734 if(i == 0) {
735 sprintf(non_resident_name, "FONTRES 100,%d,%d : %s %d",
736 info[i]->hdr.fi.dfVertRes, info[i]->hdr.fi.dfHorizRes,
737 name, info[i]->hdr.fi.dfPoints );
738 strcpy(resident_name, name);
739 } else {
740 sprintf(non_resident_name + strlen(non_resident_name), ",%d", info[i]->hdr.fi.dfPoints );
744 if (option_dpi <= 108)
745 strcat(non_resident_name, " (VGA res)");
746 else
747 strcat(non_resident_name, " (8514 res)");
748 non_resident_name_len = strlen(non_resident_name) + 4;
750 /* shift count + fontdir entry + num_files of font + nul type + \007FONTDIR */
751 resource_table_len = sizeof(align) + sizeof("FONTDIR") +
752 sizeof(NE_TYPEINFO) + sizeof(NE_NAMEINFO) +
753 sizeof(NE_TYPEINFO) + sizeof(NE_NAMEINFO) * num_files +
754 sizeof(NE_TYPEINFO);
755 resource_table_off = sizeof(NE_hdr);
756 resident_name_off = resource_table_off + resource_table_len;
757 resident_name_len = strlen(resident_name) + 4;
758 module_ref_off = resident_name_off + resident_name_len;
759 non_resident_name_off = sizeof(MZ_hdr) + module_ref_off + sizeof(align);
761 memset(&NE_hdr, 0, sizeof(NE_hdr));
762 NE_hdr.ne_magic = PUT_LE_WORD(0x454e);
763 NE_hdr.ne_ver = 5;
764 NE_hdr.ne_rev = 1;
765 NE_hdr.ne_flags = PUT_LE_WORD(NE_FFLAGS_LIBMODULE | NE_FFLAGS_GUI);
766 NE_hdr.ne_cbnrestab = PUT_LE_WORD(non_resident_name_len);
767 NE_hdr.ne_segtab = PUT_LE_WORD(sizeof(NE_hdr));
768 NE_hdr.ne_rsrctab = PUT_LE_WORD(sizeof(NE_hdr));
769 NE_hdr.ne_restab = PUT_LE_WORD(resident_name_off);
770 NE_hdr.ne_modtab = PUT_LE_WORD(module_ref_off);
771 NE_hdr.ne_imptab = PUT_LE_WORD(module_ref_off);
772 NE_hdr.ne_enttab = NE_hdr.ne_modtab;
773 NE_hdr.ne_nrestab = PUT_LE_DWORD(non_resident_name_off);
774 NE_hdr.ne_align = PUT_LE_WORD(4);
775 NE_hdr.ne_exetyp = NE_OSFLAGS_WINDOWS;
776 NE_hdr.ne_expver = PUT_LE_WORD(0x400);
778 fontdir_off = (non_resident_name_off + non_resident_name_len + 15) & ~0xf;
779 font_off = (fontdir_off + fontdir_len + 15) & ~0x0f;
781 atexit( cleanup );
782 signal( SIGTERM, exit_on_signal );
783 signal( SIGINT, exit_on_signal );
784 #ifdef SIGHUP
785 signal( SIGHUP, exit_on_signal );
786 #endif
788 if (!option_output) /* build a default output name */
790 char *p = strrchr( input_file, '/' );
791 if (p) p++;
792 else p = input_file;
793 option_output = malloc( strlen(p) + sizeof(".fon") );
794 strcpy( option_output, p );
795 p = strrchr( option_output, '.' );
796 if (!p) p = option_output + strlen(option_output);
797 strcpy( p, option_fnt_mode ? ".fnt" : ".fon" );
800 if (!(ofp = fopen(option_output, "wb")))
802 perror( option_output );
803 exit(1);
805 output_name = option_output;
806 if (option_fnt_mode)
808 write_fontinfo( info[0], ofp );
809 goto done;
812 fwrite(MZ_hdr, sizeof(MZ_hdr), 1, ofp);
813 fwrite(&NE_hdr, sizeof(NE_hdr), 1, ofp);
815 align = PUT_LE_WORD(4);
816 fwrite(&align, sizeof(align), 1, ofp);
818 rc_type.type_id = PUT_LE_WORD(NE_RSCTYPE_FONTDIR);
819 rc_type.count = PUT_LE_WORD(1);
820 rc_type.resloader = 0;
821 fwrite(&rc_type, sizeof(rc_type), 1, ofp);
823 rc_name.offset = PUT_LE_WORD(fontdir_off >> 4);
824 rc_name.length = PUT_LE_WORD((fontdir_len + 15) >> 4);
825 rc_name.flags = PUT_LE_WORD(NE_SEGFLAGS_MOVEABLE | NE_SEGFLAGS_PRELOAD);
826 rc_name.id = PUT_LE_WORD(resident_name_off - sizeof("FONTDIR") - sizeof(NE_hdr));
827 rc_name.handle = 0;
828 rc_name.usage = 0;
829 fwrite(&rc_name, sizeof(rc_name), 1, ofp);
831 rc_type.type_id = PUT_LE_WORD(NE_RSCTYPE_FONT);
832 rc_type.count = PUT_LE_WORD(num_files);
833 rc_type.resloader = 0;
834 fwrite(&rc_type, sizeof(rc_type), 1, ofp);
836 for(res = first_res | 0x8000, i = 0; i < num_files; i++, res++) {
837 int len = (info[i]->hdr.dfSize + 15) & ~0xf;
839 rc_name.offset = PUT_LE_WORD(font_off >> 4);
840 rc_name.length = PUT_LE_WORD(len >> 4);
841 rc_name.flags = PUT_LE_WORD(NE_SEGFLAGS_MOVEABLE | NE_SEGFLAGS_SHAREABLE | NE_SEGFLAGS_DISCARDABLE);
842 rc_name.id = PUT_LE_WORD(res);
843 rc_name.handle = 0;
844 rc_name.usage = 0;
845 fwrite(&rc_name, sizeof(rc_name), 1, ofp);
847 font_off += len;
850 /* empty type info */
851 memset(&rc_type, 0, sizeof(rc_type));
852 fwrite(&rc_type, sizeof(rc_type), 1, ofp);
854 fputc(strlen("FONTDIR"), ofp);
855 fwrite("FONTDIR", strlen("FONTDIR"), 1, ofp);
856 fputc(strlen(resident_name), ofp);
857 fwrite(resident_name, strlen(resident_name), 1, ofp);
859 fputc(0x00, ofp); fputc(0x00, ofp);
860 fputc(0x00, ofp);
861 fputc(0x00, ofp); fputc(0x00, ofp);
863 fputc(strlen(non_resident_name), ofp);
864 fwrite(non_resident_name, strlen(non_resident_name), 1, ofp);
865 fputc(0x00, ofp); /* terminator */
867 /* empty ne_modtab and ne_imptab */
868 fputc(0x00, ofp);
869 fputc(0x00, ofp);
871 pad = ftell(ofp) & 0xf;
872 if(pad != 0)
873 pad = 0x10 - pad;
874 for(i = 0; i < pad; i++)
875 fputc(0x00, ofp);
877 /* FONTDIR resource */
878 tmp16 = PUT_LE_WORD(num_files);
879 fwrite(&tmp16, sizeof(tmp16), 1, ofp);
881 for(res = first_res, i = 0; i < num_files; i++, res++) {
882 FNT_HEADER tmp_hdr;
883 int sz;
884 const char *name = get_face_name( info[i] );
885 tmp16 = PUT_LE_WORD(res);
886 fwrite(&tmp16, sizeof(tmp16), 1, ofp);
887 sz = FIELD_OFFSET(FNT_HEADER,fi.dfBitsOffset);
888 memcpy(&tmp_hdr, &info[i]->hdr, sz);
889 tmp_hdr.dfVersion = PUT_LE_WORD(tmp_hdr.dfVersion);
890 tmp_hdr.dfSize = PUT_LE_DWORD(tmp_hdr.dfSize);
891 adjust_fontinfo(&(tmp_hdr.fi));
892 fwrite(&tmp_hdr, FIELD_OFFSET(FNT_HEADER,fi.dfBitsOffset), 1, ofp);
893 fputc(0x00, ofp);
894 fwrite(name, strlen(name) + 1, 1, ofp);
897 pad = ftell(ofp) & 0xf;
898 if(pad != 0)
899 pad = 0x10 - pad;
900 for(i = 0; i < pad; i++)
901 fputc(0x00, ofp);
903 for(res = first_res, i = 0; i < num_files; i++, res++) {
904 write_fontinfo( info[i], ofp );
905 pad = info[i]->hdr.dfSize & 0xf;
906 if(pad != 0)
907 pad = 0x10 - pad;
908 for(j = 0; j < pad; j++)
909 fputc(0x00, ofp);
911 done:
912 fclose(ofp);
913 output_name = NULL;
914 exit(0);
917 #else /* HAVE_FREETYPE */
919 int main(int argc, char **argv)
921 fprintf( stderr, "%s needs to be built with FreeType support\n", argv[0] );
922 exit(1);
925 #endif /* HAVE_FREETYPE */