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
22 #include "wine/port.h"
36 #ifdef HAVE_FT2BUILD_H
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"
57 INT16 dfInternalLeading
;
58 INT16 dfExternalLeading
;
66 BYTE dfPitchAndFamily
;
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
157 CHAR caretSlopeNumerator
;
158 CHAR caretSlopeDenominator
;
169 ULONG indexSubTableArrayOffset
;
170 ULONG indexTableSize
;
171 ULONG numberOfIndexSubTables
;
173 sbitLineMetrics_t hori
;
174 sbitLineMetrics_t vert
;
175 USHORT startGlyphIndex
;
176 USHORT endGlyphIndex
;
189 static FT_Version_t FT_Version
;
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)
212 # define PUT_LE_WORD(x) (x)
213 # define PUT_LE_DWORD(x) (x)
219 CHAR_TABLE_ENTRY dfCharTable
[258];
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" );
258 #define __attribute__(X)
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
, ...)
278 fprintf(stderr
, "Error: ");
279 vfprintf(stderr
, s
, ap
);
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 */
296 return RUSSIAN_CHARSET
;
300 return GREEK_CHARSET
;
302 return TURKISH_CHARSET
;
304 return HEBREW_CHARSET
;
306 return ARABIC_CHARSET
;
308 return BALTIC_CHARSET
;
310 return VIETNAMESE_CHARSET
;
330 return SHIFTJIS_CHARSET
;
332 return GB2312_CHARSET
;
334 return HANGUL_CHARSET
;
336 return CHINESEBIG5_CHARSET
;
338 fprintf(stderr
, "Unknown encoding %d - using OEM_CHARSET\n", enc
);
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
== '\\')
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
)
356 int ascent
= 0, il
, el
, width_bytes
= 0, space_size
, max_width
= 0;
357 BYTE left_byte
, right_byte
, byte
;
359 int i
, x
, y
, x_off
, x_end
, first_char
;
362 const union cptable
*cptable
;
363 FT_SfntName sfntname
;
367 bitmapSizeTable_t
*size_table
;
369 struct fontinfo
*info
;
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
);
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);
383 error("Can't find codepage 1252\n");
386 assert( face
->size
->metrics
.y_ppem
== ppem
);
389 if (FT_Load_Sfnt_Table(face
, TTAG_EBLC
, 0, NULL
, &needed
))
390 fprintf(stderr
,"Can't find EBLC table\n");
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
;
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. */
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)
432 else if (!strcmp(face
->family_name
, "Fixedsys"))
435 /* Japanese System font has an external leading */
436 if (!strcmp(face
->family_name
, "System") && enc
== 932)
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
);
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;
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;
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
;
508 case PAN_FAMILY_DECORATIVE
:
509 case PAN_FAMILY_PICTORIAL
:
510 info
->hdr
.fi
.dfPitchAndFamily
|= FF_DECORATIVE
;
512 case PAN_FAMILY_TEXT_DISPLAY
:
513 if(info
->hdr
.fi
.dfPitchAndFamily
== 0) /* fixed */
514 info
->hdr
.fi
.dfPitchAndFamily
= FF_MODERN
;
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
;
523 info
->hdr
.fi
.dfPitchAndFamily
|= FF_ROMAN
;
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 );
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
)) {
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;
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;
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)))
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
);
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
)
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
)
648 while ((optc
= getopt( argc
, argv
, "d:ho:qr:s" )) != -1)
653 option_defchar
= atoi( optarg
);
656 option_output
= strdup( optarg
);
662 option_dpi
= atoi( optarg
);
675 return &argv
[optind
];
678 int main(int argc
, char **argv
)
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];
687 char non_resident_name
[200];
688 unsigned short first_res
= 0x0050, pad
, res
;
689 IMAGE_OS2_HEADER NE_hdr
;
692 struct fontinfo
**info
;
697 args
= parse_options( argc
, argv
);
699 input_file
= *args
++;
700 if (!input_file
|| !*args
)
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
);
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
;
724 if (sscanf( args
[i
], "%d,%d,%d", &ppem
, &enc
, &avg_width
) != 3)
729 if (!(info
[i
] = fill_fontinfo( input_file
, ppem
, enc
, option_dpi
, option_defchar
, avg_width
)))
732 name
= get_face_name( info
[i
] );
733 fontdir_len
+= 0x74 + strlen(name
) + 1;
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
);
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)");
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
+
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);
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;
782 signal( SIGTERM
, exit_on_signal
);
783 signal( SIGINT
, exit_on_signal
);
785 signal( SIGHUP
, exit_on_signal
);
788 if (!option_output
) /* build a default output name */
790 char *p
= strrchr( 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
);
805 output_name
= option_output
;
808 write_fontinfo( info
[0], ofp
);
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
));
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
);
845 fwrite(&rc_name
, sizeof(rc_name
), 1, ofp
);
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
);
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 */
871 pad
= ftell(ofp
) & 0xf;
874 for(i
= 0; i
< pad
; i
++)
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
++) {
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
);
894 fwrite(name
, strlen(name
) + 1, 1, ofp
);
897 pad
= ftell(ofp
) & 0xf;
900 for(i
= 0; i
< pad
; i
++)
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;
908 for(j
= 0; j
< pad
; j
++)
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] );
925 #endif /* HAVE_FREETYPE */