gdiplus: Allow excluding from infinite regions.
[wine/multimedia.git] / tools / sfnt2fnt.c
blob925855f8757d7a1252db2538a2e42a937b0ac90e
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 #define WINE_UNICODE_API /* nothing */
45 #include "wine/unicode.h"
46 #include "wingdi.h"
47 #include "basetsd.h"
49 #include "pshpack1.h"
51 typedef struct
53 INT16 dfType;
54 INT16 dfPoints;
55 INT16 dfVertRes;
56 INT16 dfHorizRes;
57 INT16 dfAscent;
58 INT16 dfInternalLeading;
59 INT16 dfExternalLeading;
60 BYTE dfItalic;
61 BYTE dfUnderline;
62 BYTE dfStrikeOut;
63 INT16 dfWeight;
64 BYTE dfCharSet;
65 INT16 dfPixWidth;
66 INT16 dfPixHeight;
67 BYTE dfPitchAndFamily;
68 INT16 dfAvgWidth;
69 INT16 dfMaxWidth;
70 BYTE dfFirstChar;
71 BYTE dfLastChar;
72 BYTE dfDefaultChar;
73 BYTE dfBreakChar;
74 INT16 dfWidthBytes;
75 LONG dfDevice;
76 LONG dfFace;
77 LONG dfBitsPointer;
78 LONG dfBitsOffset;
79 BYTE dfReserved;
80 LONG dfFlags;
81 INT16 dfAspace;
82 INT16 dfBspace;
83 INT16 dfCspace;
84 LONG dfColorPointer;
85 LONG dfReserved1[4];
86 } FONTINFO16;
88 typedef struct
90 WORD dfVersion;
91 DWORD dfSize;
92 char dfCopyright[60];
93 FONTINFO16 fi;
94 } FNT_HEADER;
96 typedef struct
98 WORD offset;
99 WORD length;
100 WORD flags;
101 WORD id;
102 WORD handle;
103 WORD usage;
104 } NE_NAMEINFO;
106 typedef struct
108 WORD type_id;
109 WORD count;
110 DWORD resloader;
111 } NE_TYPEINFO;
113 #define NE_FFLAGS_SINGLEDATA 0x0001
114 #define NE_FFLAGS_MULTIPLEDATA 0x0002
115 #define NE_FFLAGS_WIN32 0x0010
116 #define NE_FFLAGS_FRAMEBUF 0x0100
117 #define NE_FFLAGS_CONSOLE 0x0200
118 #define NE_FFLAGS_GUI 0x0300
119 #define NE_FFLAGS_SELFLOAD 0x0800
120 #define NE_FFLAGS_LINKERROR 0x2000
121 #define NE_FFLAGS_CALLWEP 0x4000
122 #define NE_FFLAGS_LIBMODULE 0x8000
124 #define NE_OSFLAGS_WINDOWS 0x02
126 #define NE_RSCTYPE_FONTDIR 0x8007
127 #define NE_RSCTYPE_FONT 0x8008
128 #define NE_RSCTYPE_SCALABLE_FONTPATH 0x80cc
130 #define NE_SEGFLAGS_DATA 0x0001
131 #define NE_SEGFLAGS_ALLOCATED 0x0002
132 #define NE_SEGFLAGS_LOADED 0x0004
133 #define NE_SEGFLAGS_ITERATED 0x0008
134 #define NE_SEGFLAGS_MOVEABLE 0x0010
135 #define NE_SEGFLAGS_SHAREABLE 0x0020
136 #define NE_SEGFLAGS_PRELOAD 0x0040
137 #define NE_SEGFLAGS_EXECUTEONLY 0x0080
138 #define NE_SEGFLAGS_READONLY 0x0080
139 #define NE_SEGFLAGS_RELOC_DATA 0x0100
140 #define NE_SEGFLAGS_SELFLOAD 0x0800
141 #define NE_SEGFLAGS_DISCARDABLE 0x1000
142 #define NE_SEGFLAGS_32BIT 0x2000
144 typedef struct {
145 WORD width;
146 DWORD offset;
147 } CHAR_TABLE_ENTRY;
149 typedef struct {
150 DWORD version;
151 ULONG numSizes;
152 } eblcHeader_t;
154 typedef struct {
155 CHAR ascender;
156 CHAR descender;
157 BYTE widthMax;
158 CHAR caretSlopeNumerator;
159 CHAR caretSlopeDenominator;
160 CHAR caretOffset;
161 CHAR minOriginSB;
162 CHAR minAdvanceSB;
163 CHAR maxBeforeBL;
164 CHAR maxAfterBL;
165 CHAR pad1;
166 CHAR pad2;
167 } sbitLineMetrics_t;
169 typedef struct {
170 ULONG indexSubTableArrayOffset;
171 ULONG indexTableSize;
172 ULONG numberOfIndexSubTables;
173 ULONG colorRef;
174 sbitLineMetrics_t hori;
175 sbitLineMetrics_t vert;
176 USHORT startGlyphIndex;
177 USHORT endGlyphIndex;
178 BYTE ppemX;
179 BYTE ppemY;
180 BYTE bitDepth;
181 CHAR flags;
182 } bitmapSizeTable_t;
184 typedef struct
186 FT_Int major;
187 FT_Int minor;
188 FT_Int patch;
189 } FT_Version_t;
190 static FT_Version_t FT_Version;
192 #include "poppack.h"
194 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
195 #define GET_BE_DWORD(ptr) ((DWORD)MAKELONG( GET_BE_WORD(&((WORD *)(ptr))[1]), \
196 GET_BE_WORD(&((WORD *)(ptr))[0]) ))
197 #ifdef WORDS_BIGENDIAN
198 static WORD byteswap_word(WORD x)
200 return ( ( (x & 0xff) << 8) |
201 ( (x & 0xff00) >> 8) );
203 static DWORD byteswap_dword(DWORD x)
205 return ( ( (x & 0xff) << 24) |
206 ( (x & 0xff00) << 8) |
207 ( (x & 0xff0000) >> 8) |
208 ( (x & 0xff000000) >> 24) );
210 # define PUT_LE_WORD(x) byteswap_word(x)
211 # define PUT_LE_DWORD(x) byteswap_dword(x)
212 #else
213 # define PUT_LE_WORD(x) (x)
214 # define PUT_LE_DWORD(x) (x)
215 #endif
217 struct fontinfo
219 FNT_HEADER hdr;
220 CHAR_TABLE_ENTRY dfCharTable[258];
221 BYTE *data;
224 static const BYTE MZ_hdr[] =
226 'M', 'Z', 0x0d, 0x01, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
227 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
228 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
229 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
230 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 'T', 'h',
231 'i', 's', ' ', 'P', 'r', 'o', 'g', 'r', 'a', 'm', ' ', 'c', 'a', 'n', 'n', 'o',
232 't', ' ', 'b', 'e', ' ', 'r', 'u', 'n', ' ', 'i', 'n', ' ', 'D', 'O', 'S', ' ',
233 'm', 'o', 'd', 'e', 0x0d, 0x0a, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
236 static char *option_output;
237 static int option_defchar = ' ';
238 static int option_dpi = 96;
239 static int option_fnt_mode = 0;
240 static int option_quiet = 0;
242 static const char *output_name;
244 static FT_Library ft_library;
246 static void usage(char **argv)
248 fprintf(stderr, "%s [options] input.ttf ppem,enc,avg_width ...\n", argv[0]);
249 fprintf(stderr, "Options:\n");
250 fprintf(stderr, " -h Display help\n" );
251 fprintf(stderr, " -d char Set the font default char\n" );
252 fprintf(stderr, " -o file Set output file name\n" );
253 fprintf(stderr, " -q Quiet mode\n" );
254 fprintf(stderr, " -r dpi Set resolution in DPI (default: 96)\n" );
255 fprintf(stderr, " -s Single .fnt file mode\n" );
258 #ifndef __GNUC__
259 #define __attribute__(X)
260 #endif
262 /* atexit handler to cleanup files */
263 static void cleanup(void)
265 if (output_name) unlink( output_name );
268 static void exit_on_signal( int sig )
270 exit(1); /* this will call the atexit functions */
273 static void error(const char *s, ...) __attribute__((format (printf, 1, 2)));
275 static void error(const char *s, ...)
277 va_list ap;
278 va_start(ap, s);
279 fprintf(stderr, "Error: ");
280 vfprintf(stderr, s, ap);
281 va_end(ap);
282 exit(1);
285 static const char *get_face_name( const struct fontinfo *info )
287 return (const char *)info->data + info->hdr.fi.dfFace - info->hdr.fi.dfBitsOffset;
290 static int lookup_charset(int enc)
292 /* FIXME: make winelib app and use TranslateCharsetInfo */
293 switch(enc) {
294 case 1250:
295 return EE_CHARSET;
296 case 1251:
297 return RUSSIAN_CHARSET;
298 case 1252:
299 return ANSI_CHARSET;
300 case 1253:
301 return GREEK_CHARSET;
302 case 1254:
303 return TURKISH_CHARSET;
304 case 1255:
305 return HEBREW_CHARSET;
306 case 1256:
307 return ARABIC_CHARSET;
308 case 1257:
309 return BALTIC_CHARSET;
310 case 1258:
311 return VIETNAMESE_CHARSET;
312 case 437:
313 case 737:
314 case 775:
315 case 850:
316 case 852:
317 case 855:
318 case 857:
319 case 860:
320 case 861:
321 case 862:
322 case 863:
323 case 864:
324 case 865:
325 case 866:
326 case 869:
327 return OEM_CHARSET;
328 case 874:
329 return THAI_CHARSET;
330 case 932:
331 return SHIFTJIS_CHARSET;
332 case 936:
333 return GB2312_CHARSET;
334 case 949:
335 return HANGUL_CHARSET;
336 case 950:
337 return CHINESEBIG5_CHARSET;
339 fprintf(stderr, "Unknown encoding %d - using OEM_CHARSET\n", enc);
341 return OEM_CHARSET;
344 static int get_char(const union cptable *cptable, int enc, int index)
346 /* Korean has the Won sign in place of '\\' */
347 if(enc == 949 && index == '\\')
348 return 0x20a9;
350 return cptable->sbcs.cp2uni[index];
353 static struct fontinfo *fill_fontinfo( const char *face_name, int ppem, int enc, int dpi,
354 unsigned char def_char, int avg_width )
356 FT_Face face;
357 int ascent = 0, il, el, width_bytes = 0, space_size, max_width = 0;
358 BYTE left_byte, right_byte, byte;
359 DWORD start;
360 int i, x, y, x_off, x_end, first_char;
361 FT_UInt gi;
362 int num_names;
363 const union cptable *cptable;
364 FT_SfntName sfntname;
365 TT_OS2 *os2;
366 FT_ULong needed;
367 eblcHeader_t *eblc;
368 bitmapSizeTable_t *size_table;
369 int num_sizes;
370 struct fontinfo *info;
371 size_t data_pos;
373 if (FT_New_Face(ft_library, face_name, 0, &face)) error( "Cannot open face %s\n", face_name );
374 if (FT_Set_Pixel_Sizes(face, ppem, ppem)) error( "cannot set face size to %u\n", ppem );
376 cptable = wine_cp_get_table(enc);
377 if(!cptable)
378 error("Can't find codepage %d\n", enc);
380 if(cptable->info.char_size != 1) {
381 /* for double byte charsets we actually want to use cp1252 */
382 cptable = wine_cp_get_table(1252);
383 if(!cptable)
384 error("Can't find codepage 1252\n");
387 assert( face->size->metrics.y_ppem == ppem );
389 needed = 0;
390 if (FT_Load_Sfnt_Table(face, TTAG_EBLC, 0, NULL, &needed))
391 fprintf(stderr,"Can't find EBLC table\n");
392 else
394 eblc = malloc(needed);
395 FT_Load_Sfnt_Table(face, TTAG_EBLC, 0, (FT_Byte *)eblc, &needed);
397 num_sizes = GET_BE_DWORD(&eblc->numSizes);
399 size_table = (bitmapSizeTable_t *)(eblc + 1);
400 for(i = 0; i < num_sizes; i++)
402 if( (signed char)size_table->hori.ascender - (signed char)size_table->hori.descender == ppem)
404 ascent = size_table->hori.ascender;
405 break;
407 size_table++;
410 free(eblc);
413 /* Versions of fontforge prior to early 2006 have incorrect
414 ascender values in the eblc table, so we won't find the
415 correct bitmapSizeTable. In this case use the height of
416 the Aring glyph instead. */
417 if(ascent == 0)
419 if(FT_Load_Char(face, 0xc5, FT_LOAD_DEFAULT))
420 error("Can't find Aring\n");
421 ascent = face->glyph->metrics.horiBearingY >> 6;
424 start = sizeof(FNT_HEADER);
426 if(FT_Load_Char(face, 'M', FT_LOAD_DEFAULT))
427 error("Can't find M\n");
428 il = ascent - (face->glyph->metrics.height >> 6);
430 /* Hack: Courier has no internal leading, nor do any Chinese or Japanese fonts */
431 if(!strcmp(face->family_name, "Courier") || enc == 936 || enc == 950 || enc == 932)
432 il = 0;
433 else if (!strcmp(face->family_name, "Fixedsys"))
434 il = 3;
436 /* Japanese System font has an external leading */
437 if (!strcmp(face->family_name, "System") && enc == 932)
438 el = 2;
439 else
440 el = 0;
442 first_char = FT_Get_First_Char(face, &gi);
443 if(first_char == 0xd) /* fontforge's first glyph is 0xd, we'll catch this and skip it */
444 first_char = 32; /* FT_Get_Next_Char for some reason returns too high
445 number in this case */
447 info = calloc( 1, sizeof(*info) );
449 info->hdr.fi.dfFirstChar = first_char;
450 info->hdr.fi.dfLastChar = 0xff;
451 start += ((unsigned char)info->hdr.fi.dfLastChar - (unsigned char)info->hdr.fi.dfFirstChar + 3 ) * sizeof(*info->dfCharTable);
453 num_names = FT_Get_Sfnt_Name_Count(face);
454 for(i = 0; i <num_names; i++) {
455 FT_Get_Sfnt_Name(face, i, &sfntname);
456 if(sfntname.platform_id == 1 && sfntname.encoding_id == 0 &&
457 sfntname.language_id == 0 && sfntname.name_id == 0) {
458 size_t len = min( sfntname.string_len, sizeof(info->hdr.dfCopyright)-1 );
459 memcpy(info->hdr.dfCopyright, sfntname.string, len);
460 info->hdr.dfCopyright[len] = 0;
464 os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
465 for(i = first_char; i < 0x100; i++) {
466 int c = get_char(cptable, enc, i);
467 gi = FT_Get_Char_Index(face, c);
468 if(gi == 0 && !option_quiet)
469 fprintf(stderr, "warning: %s %u: missing glyph for char %04x\n",
470 face->family_name, ppem, cptable->sbcs.cp2uni[i]);
471 if(FT_Load_Char(face, c, FT_LOAD_DEFAULT)) {
472 fprintf(stderr, "error loading char %d - bad news!\n", i);
473 continue;
475 info->dfCharTable[i].width = face->glyph->metrics.horiAdvance >> 6;
476 info->dfCharTable[i].offset = start + (width_bytes * ppem);
477 width_bytes += ((face->glyph->metrics.horiAdvance >> 6) + 7) >> 3;
478 if(max_width < (face->glyph->metrics.horiAdvance >> 6))
479 max_width = face->glyph->metrics.horiAdvance >> 6;
481 /* space */
482 space_size = (ppem + 3) / 4;
483 info->dfCharTable[i].width = space_size;
484 info->dfCharTable[i].offset = start + (width_bytes * ppem);
485 width_bytes += (space_size + 7) >> 3;
486 /* sentinel */
487 info->dfCharTable[++i].width = 0;
488 info->dfCharTable[i].offset = start + (width_bytes * ppem);
490 info->hdr.fi.dfType = 0;
491 info->hdr.fi.dfPoints = ((ppem - il - el) * 72 + dpi/2) / dpi;
492 info->hdr.fi.dfVertRes = dpi;
493 info->hdr.fi.dfHorizRes = dpi;
494 info->hdr.fi.dfAscent = ascent;
495 info->hdr.fi.dfInternalLeading = il;
496 info->hdr.fi.dfExternalLeading = el;
497 info->hdr.fi.dfItalic = (face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
498 info->hdr.fi.dfUnderline = 0;
499 info->hdr.fi.dfStrikeOut = 0;
500 info->hdr.fi.dfWeight = os2->usWeightClass;
501 info->hdr.fi.dfCharSet = lookup_charset(enc);
502 info->hdr.fi.dfPixWidth = (face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) ? avg_width : 0;
503 info->hdr.fi.dfPixHeight = ppem;
504 info->hdr.fi.dfPitchAndFamily = FT_IS_FIXED_WIDTH(face) ? 0 : TMPF_FIXED_PITCH;
505 switch(os2->panose[PAN_FAMILYTYPE_INDEX]) {
506 case PAN_FAMILY_SCRIPT:
507 info->hdr.fi.dfPitchAndFamily |= FF_SCRIPT;
508 break;
509 case PAN_FAMILY_DECORATIVE:
510 case PAN_FAMILY_PICTORIAL:
511 info->hdr.fi.dfPitchAndFamily |= FF_DECORATIVE;
512 break;
513 case PAN_FAMILY_TEXT_DISPLAY:
514 if(info->hdr.fi.dfPitchAndFamily == 0) /* fixed */
515 info->hdr.fi.dfPitchAndFamily = FF_MODERN;
516 else {
517 switch(os2->panose[PAN_SERIFSTYLE_INDEX]) {
518 case PAN_SERIF_NORMAL_SANS:
519 case PAN_SERIF_OBTUSE_SANS:
520 case PAN_SERIF_PERP_SANS:
521 info->hdr.fi.dfPitchAndFamily |= FF_SWISS;
522 break;
523 default:
524 info->hdr.fi.dfPitchAndFamily |= FF_ROMAN;
527 break;
528 default:
529 info->hdr.fi.dfPitchAndFamily |= FF_DONTCARE;
532 info->hdr.fi.dfAvgWidth = avg_width;
533 info->hdr.fi.dfMaxWidth = (enc == 932) ? avg_width * 2 : max_width;
534 info->hdr.fi.dfDefaultChar = def_char - info->hdr.fi.dfFirstChar;
535 info->hdr.fi.dfBreakChar = ' ' - info->hdr.fi.dfFirstChar;
536 info->hdr.fi.dfWidthBytes = (width_bytes + 1) & ~1;
538 info->hdr.fi.dfFace = start + info->hdr.fi.dfWidthBytes * ppem;
539 info->hdr.fi.dfBitsOffset = start;
540 info->hdr.fi.dfFlags = 0x10; /* DFF_1COLOR */
541 info->hdr.fi.dfFlags |= FT_IS_FIXED_WIDTH(face) ? 1 : 2; /* DFF_FIXED : DFF_PROPORTIONAL */
543 info->hdr.dfVersion = 0x300;
544 info->hdr.dfSize = start + info->hdr.fi.dfWidthBytes * ppem + strlen(face->family_name) + 1;
546 info->data = calloc( info->hdr.dfSize - start, 1 );
547 data_pos = 0;
549 for(i = first_char; i < 0x100; i++) {
550 int c = get_char(cptable, enc, i);
551 if(FT_Load_Char(face, c, FT_LOAD_DEFAULT)) {
552 continue;
554 assert(info->dfCharTable[i].width == face->glyph->metrics.horiAdvance >> 6);
556 for(x = 0; x < ((info->dfCharTable[i].width + 7) / 8); x++) {
557 for(y = 0; y < ppem; y++) {
558 if(y < ascent - face->glyph->bitmap_top ||
559 y >= face->glyph->bitmap.rows + ascent - face->glyph->bitmap_top) {
560 info->data[data_pos++] = 0;
561 continue;
563 x_off = face->glyph->bitmap_left / 8;
564 x_end = (face->glyph->bitmap_left + face->glyph->bitmap.width - 1) / 8;
565 if(x < x_off || x > x_end) {
566 info->data[data_pos++] = 0;
567 continue;
569 if(x == x_off)
570 left_byte = 0;
571 else
572 left_byte = face->glyph->bitmap.buffer[(y - (ascent - face->glyph->bitmap_top)) * face->glyph->bitmap.pitch + x - x_off - 1];
574 /* On the last non-trivial output byte (x == x_end) have we got one or two input bytes */
575 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)))
576 right_byte = 0;
577 else
578 right_byte = face->glyph->bitmap.buffer[(y - (ascent - face->glyph->bitmap_top)) * face->glyph->bitmap.pitch + x - x_off];
580 byte = (left_byte << (8 - (face->glyph->bitmap_left & 7))) & 0xff;
581 byte |= ((right_byte >> (face->glyph->bitmap_left & 7)) & 0xff);
582 info->data[data_pos++] = byte;
586 data_pos += ((space_size + 7) / 8) * ppem;
587 if (width_bytes & 1) data_pos += ppem;
589 memcpy( info->data + data_pos, face->family_name, strlen( face->family_name ));
590 data_pos += strlen( face->family_name ) + 1;
591 assert( start + data_pos == info->hdr.dfSize );
593 FT_Done_Face( face );
594 return info;
597 static void adjust_fontinfo( FONTINFO16 * fi )
599 fi->dfType = PUT_LE_WORD(fi->dfType);
600 fi->dfPoints = PUT_LE_WORD(fi->dfPoints);
601 fi->dfVertRes = PUT_LE_WORD(fi->dfVertRes);
602 fi->dfHorizRes = PUT_LE_WORD(fi->dfHorizRes);
603 fi->dfAscent = PUT_LE_WORD(fi->dfAscent);
604 fi->dfInternalLeading = PUT_LE_WORD(fi->dfInternalLeading);
605 fi->dfExternalLeading = PUT_LE_WORD(fi->dfExternalLeading);
606 fi->dfWeight = PUT_LE_WORD(fi->dfWeight);
607 fi->dfPixWidth = PUT_LE_WORD(fi->dfPixWidth);
608 fi->dfPixHeight = PUT_LE_WORD(fi->dfPixHeight);
609 fi->dfAvgWidth = PUT_LE_WORD(fi->dfAvgWidth);
610 fi->dfMaxWidth = PUT_LE_WORD(fi->dfMaxWidth);
611 fi->dfWidthBytes = PUT_LE_WORD(fi->dfWidthBytes);
612 fi->dfAspace = PUT_LE_WORD(fi->dfAspace);
613 fi->dfBspace = PUT_LE_WORD(fi->dfBspace);
614 fi->dfCspace = PUT_LE_WORD(fi->dfCspace);
615 fi->dfDevice = PUT_LE_DWORD(fi->dfDevice);
616 fi->dfFace = PUT_LE_DWORD(fi->dfFace);
617 fi->dfBitsPointer = PUT_LE_DWORD(fi->dfBitsPointer);
618 fi->dfBitsOffset = PUT_LE_DWORD(fi->dfBitsOffset);
619 fi->dfFlags = PUT_LE_DWORD(fi->dfFlags);
620 fi->dfColorPointer = PUT_LE_DWORD(fi->dfColorPointer);
623 static void write_fontinfo( const struct fontinfo *info, FILE *fp )
625 FNT_HEADER tmp_hdr;
626 int num_chars, i;
627 CHAR_TABLE_ENTRY tmp_chartable[258];
628 memcpy(&tmp_hdr, &info->hdr, sizeof(info->hdr));
629 tmp_hdr.dfVersion = PUT_LE_WORD(tmp_hdr.dfVersion);
630 tmp_hdr.dfSize = PUT_LE_DWORD(tmp_hdr.dfSize);
631 adjust_fontinfo(&(tmp_hdr.fi));
632 fwrite( &tmp_hdr, sizeof(info->hdr), 1, fp );
633 num_chars = ((unsigned char)info->hdr.fi.dfLastChar - (unsigned char)info->hdr.fi.dfFirstChar) + 3;
635 memcpy(&tmp_chartable, info->dfCharTable + info->hdr.fi.dfFirstChar, num_chars * sizeof(CHAR_TABLE_ENTRY));
636 for (i=0; i < num_chars; ++i) {
637 tmp_chartable[i].width = PUT_LE_WORD(tmp_chartable[i].width);
638 tmp_chartable[i].offset = PUT_LE_DWORD(tmp_chartable[i].offset);
640 fwrite( tmp_chartable, sizeof(CHAR_TABLE_ENTRY), num_chars, fp );
641 fwrite( info->data, info->hdr.dfSize - info->hdr.fi.dfBitsOffset, 1, fp );
644 /* parse options from the argv array and remove all the recognized ones */
645 static char **parse_options( int argc, char **argv )
647 int optc;
649 while ((optc = getopt( argc, argv, "d:ho:qr:s" )) != -1)
651 switch(optc)
653 case 'd':
654 option_defchar = atoi( optarg );
655 break;
656 case 'o':
657 option_output = strdup( optarg );
658 break;
659 case 'q':
660 option_quiet = 1;
661 break;
662 case 'r':
663 option_dpi = atoi( optarg );
664 break;
665 case 's':
666 option_fnt_mode = 1;
667 break;
668 case 'h':
669 usage(argv);
670 exit(0);
671 case '?':
672 usage(argv);
673 exit(1);
676 return &argv[optind];
679 int main(int argc, char **argv)
681 int i, j;
682 FILE *ofp;
683 short align, num_files;
684 int resource_table_len, non_resident_name_len, resident_name_len;
685 unsigned short resource_table_off, resident_name_off, module_ref_off, non_resident_name_off, fontdir_off, font_off;
686 char resident_name[200];
687 int fontdir_len = 2;
688 char non_resident_name[200];
689 unsigned short first_res = 0x0050, pad, res;
690 IMAGE_OS2_HEADER NE_hdr;
691 NE_TYPEINFO rc_type;
692 NE_NAMEINFO rc_name;
693 struct fontinfo **info;
694 char *input_file;
695 char **args;
696 short tmp16;
698 args = parse_options( argc, argv );
700 input_file = *args++;
701 if (!input_file || !*args)
703 usage(argv);
704 exit(1);
707 if(FT_Init_FreeType(&ft_library))
708 error("ft init failure\n");
710 FT_Version.major=FT_Version.minor=FT_Version.patch=-1;
711 FT_Library_Version(ft_library,&FT_Version.major,&FT_Version.minor,&FT_Version.patch);
713 num_files = 0;
714 while (args[num_files]) num_files++;
716 if (option_fnt_mode && num_files > 1)
717 error( "can only specify one font in .fnt mode\n" );
719 info = malloc( num_files * sizeof(*info) );
720 for (i = 0; i < num_files; i++)
722 int ppem, enc, avg_width;
723 const char *name;
725 if (sscanf( args[i], "%d,%d,%d", &ppem, &enc, &avg_width ) != 3)
727 usage(argv);
728 exit(1);
730 if (!(info[i] = fill_fontinfo( input_file, ppem, enc, option_dpi, option_defchar, avg_width )))
731 exit(1);
733 name = get_face_name( info[i] );
734 fontdir_len += 0x74 + strlen(name) + 1;
735 if(i == 0) {
736 sprintf(non_resident_name, "FONTRES 100,%d,%d : %s %d",
737 info[i]->hdr.fi.dfVertRes, info[i]->hdr.fi.dfHorizRes,
738 name, info[i]->hdr.fi.dfPoints );
739 strcpy(resident_name, name);
740 } else {
741 sprintf(non_resident_name + strlen(non_resident_name), ",%d", info[i]->hdr.fi.dfPoints );
745 if (option_dpi <= 108)
746 strcat(non_resident_name, " (VGA res)");
747 else
748 strcat(non_resident_name, " (8514 res)");
749 non_resident_name_len = strlen(non_resident_name) + 4;
751 /* shift count + fontdir entry + num_files of font + nul type + \007FONTDIR */
752 resource_table_len = sizeof(align) + sizeof("FONTDIR") +
753 sizeof(NE_TYPEINFO) + sizeof(NE_NAMEINFO) +
754 sizeof(NE_TYPEINFO) + sizeof(NE_NAMEINFO) * num_files +
755 sizeof(NE_TYPEINFO);
756 resource_table_off = sizeof(NE_hdr);
757 resident_name_off = resource_table_off + resource_table_len;
758 resident_name_len = strlen(resident_name) + 4;
759 module_ref_off = resident_name_off + resident_name_len;
760 non_resident_name_off = sizeof(MZ_hdr) + module_ref_off + sizeof(align);
762 memset(&NE_hdr, 0, sizeof(NE_hdr));
763 NE_hdr.ne_magic = PUT_LE_WORD(0x454e);
764 NE_hdr.ne_ver = 5;
765 NE_hdr.ne_rev = 1;
766 NE_hdr.ne_flags = PUT_LE_WORD(NE_FFLAGS_LIBMODULE | NE_FFLAGS_GUI);
767 NE_hdr.ne_cbnrestab = PUT_LE_WORD(non_resident_name_len);
768 NE_hdr.ne_segtab = PUT_LE_WORD(sizeof(NE_hdr));
769 NE_hdr.ne_rsrctab = PUT_LE_WORD(sizeof(NE_hdr));
770 NE_hdr.ne_restab = PUT_LE_WORD(resident_name_off);
771 NE_hdr.ne_modtab = PUT_LE_WORD(module_ref_off);
772 NE_hdr.ne_imptab = PUT_LE_WORD(module_ref_off);
773 NE_hdr.ne_enttab = NE_hdr.ne_modtab;
774 NE_hdr.ne_nrestab = PUT_LE_DWORD(non_resident_name_off);
775 NE_hdr.ne_align = PUT_LE_WORD(4);
776 NE_hdr.ne_exetyp = NE_OSFLAGS_WINDOWS;
777 NE_hdr.ne_expver = PUT_LE_WORD(0x400);
779 fontdir_off = (non_resident_name_off + non_resident_name_len + 15) & ~0xf;
780 font_off = (fontdir_off + fontdir_len + 15) & ~0x0f;
782 atexit( cleanup );
783 signal( SIGTERM, exit_on_signal );
784 signal( SIGINT, exit_on_signal );
785 #ifdef SIGHUP
786 signal( SIGHUP, exit_on_signal );
787 #endif
789 if (!option_output) /* build a default output name */
791 char *p = strrchr( input_file, '/' );
792 if (p) p++;
793 else p = input_file;
794 option_output = malloc( strlen(p) + sizeof(".fon") );
795 strcpy( option_output, p );
796 p = strrchr( option_output, '.' );
797 if (!p) p = option_output + strlen(option_output);
798 strcpy( p, option_fnt_mode ? ".fnt" : ".fon" );
801 if (!(ofp = fopen(option_output, "wb")))
803 perror( option_output );
804 exit(1);
806 output_name = option_output;
807 if (option_fnt_mode)
809 write_fontinfo( info[0], ofp );
810 goto done;
813 fwrite(MZ_hdr, sizeof(MZ_hdr), 1, ofp);
814 fwrite(&NE_hdr, sizeof(NE_hdr), 1, ofp);
816 align = PUT_LE_WORD(4);
817 fwrite(&align, sizeof(align), 1, ofp);
819 rc_type.type_id = PUT_LE_WORD(NE_RSCTYPE_FONTDIR);
820 rc_type.count = PUT_LE_WORD(1);
821 rc_type.resloader = 0;
822 fwrite(&rc_type, sizeof(rc_type), 1, ofp);
824 rc_name.offset = PUT_LE_WORD(fontdir_off >> 4);
825 rc_name.length = PUT_LE_WORD((fontdir_len + 15) >> 4);
826 rc_name.flags = PUT_LE_WORD(NE_SEGFLAGS_MOVEABLE | NE_SEGFLAGS_PRELOAD);
827 rc_name.id = PUT_LE_WORD(resident_name_off - sizeof("FONTDIR") - sizeof(NE_hdr));
828 rc_name.handle = 0;
829 rc_name.usage = 0;
830 fwrite(&rc_name, sizeof(rc_name), 1, ofp);
832 rc_type.type_id = PUT_LE_WORD(NE_RSCTYPE_FONT);
833 rc_type.count = PUT_LE_WORD(num_files);
834 rc_type.resloader = 0;
835 fwrite(&rc_type, sizeof(rc_type), 1, ofp);
837 for(res = first_res | 0x8000, i = 0; i < num_files; i++, res++) {
838 int len = (info[i]->hdr.dfSize + 15) & ~0xf;
840 rc_name.offset = PUT_LE_WORD(font_off >> 4);
841 rc_name.length = PUT_LE_WORD(len >> 4);
842 rc_name.flags = PUT_LE_WORD(NE_SEGFLAGS_MOVEABLE | NE_SEGFLAGS_SHAREABLE | NE_SEGFLAGS_DISCARDABLE);
843 rc_name.id = PUT_LE_WORD(res);
844 rc_name.handle = 0;
845 rc_name.usage = 0;
846 fwrite(&rc_name, sizeof(rc_name), 1, ofp);
848 font_off += len;
851 /* empty type info */
852 memset(&rc_type, 0, sizeof(rc_type));
853 fwrite(&rc_type, sizeof(rc_type), 1, ofp);
855 fputc(strlen("FONTDIR"), ofp);
856 fwrite("FONTDIR", strlen("FONTDIR"), 1, ofp);
857 fputc(strlen(resident_name), ofp);
858 fwrite(resident_name, strlen(resident_name), 1, ofp);
860 fputc(0x00, ofp); fputc(0x00, ofp);
861 fputc(0x00, ofp);
862 fputc(0x00, ofp); fputc(0x00, ofp);
864 fputc(strlen(non_resident_name), ofp);
865 fwrite(non_resident_name, strlen(non_resident_name), 1, ofp);
866 fputc(0x00, ofp); /* terminator */
868 /* empty ne_modtab and ne_imptab */
869 fputc(0x00, ofp);
870 fputc(0x00, ofp);
872 pad = ftell(ofp) & 0xf;
873 if(pad != 0)
874 pad = 0x10 - pad;
875 for(i = 0; i < pad; i++)
876 fputc(0x00, ofp);
878 /* FONTDIR resource */
879 tmp16 = PUT_LE_WORD(num_files);
880 fwrite(&tmp16, sizeof(tmp16), 1, ofp);
882 for(res = first_res, i = 0; i < num_files; i++, res++) {
883 FNT_HEADER tmp_hdr;
884 int sz;
885 const char *name = get_face_name( info[i] );
886 tmp16 = PUT_LE_WORD(res);
887 fwrite(&tmp16, sizeof(tmp16), 1, ofp);
888 sz = FIELD_OFFSET(FNT_HEADER,fi.dfBitsOffset);
889 memcpy(&tmp_hdr, &info[i]->hdr, sz);
890 tmp_hdr.dfVersion = PUT_LE_WORD(tmp_hdr.dfVersion);
891 tmp_hdr.dfSize = PUT_LE_DWORD(tmp_hdr.dfSize);
892 adjust_fontinfo(&(tmp_hdr.fi));
893 fwrite(&tmp_hdr, FIELD_OFFSET(FNT_HEADER,fi.dfBitsOffset), 1, ofp);
894 fputc(0x00, ofp);
895 fwrite(name, strlen(name) + 1, 1, ofp);
898 pad = ftell(ofp) & 0xf;
899 if(pad != 0)
900 pad = 0x10 - pad;
901 for(i = 0; i < pad; i++)
902 fputc(0x00, ofp);
904 for(res = first_res, i = 0; i < num_files; i++, res++) {
905 write_fontinfo( info[i], ofp );
906 pad = info[i]->hdr.dfSize & 0xf;
907 if(pad != 0)
908 pad = 0x10 - pad;
909 for(j = 0; j < pad; j++)
910 fputc(0x00, ofp);
912 done:
913 fclose(ofp);
914 output_name = NULL;
915 exit(0);
918 #else /* HAVE_FREETYPE */
920 int main(int argc, char **argv)
922 fprintf( stderr, "%s needs to be built with FreeType support\n", argv[0] );
923 exit(1);
926 #endif /* HAVE_FREETYPE */