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 #define WINE_UNICODE_API /* nothing */
45 #include "wine/unicode.h"
58 INT16 dfInternalLeading
;
59 INT16 dfExternalLeading
;
67 BYTE dfPitchAndFamily
;
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
158 CHAR caretSlopeNumerator
;
159 CHAR caretSlopeDenominator
;
170 ULONG indexSubTableArrayOffset
;
171 ULONG indexTableSize
;
172 ULONG numberOfIndexSubTables
;
174 sbitLineMetrics_t hori
;
175 sbitLineMetrics_t vert
;
176 USHORT startGlyphIndex
;
177 USHORT endGlyphIndex
;
190 static FT_Version_t FT_Version
;
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)
213 # define PUT_LE_WORD(x) (x)
214 # define PUT_LE_DWORD(x) (x)
220 CHAR_TABLE_ENTRY dfCharTable
[258];
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" );
259 #define __attribute__(X)
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
, ...)
279 fprintf(stderr
, "Error: ");
280 vfprintf(stderr
, s
, ap
);
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 */
297 return RUSSIAN_CHARSET
;
301 return GREEK_CHARSET
;
303 return TURKISH_CHARSET
;
305 return HEBREW_CHARSET
;
307 return ARABIC_CHARSET
;
309 return BALTIC_CHARSET
;
311 return VIETNAMESE_CHARSET
;
331 return SHIFTJIS_CHARSET
;
333 return GB2312_CHARSET
;
335 return HANGUL_CHARSET
;
337 return CHINESEBIG5_CHARSET
;
339 fprintf(stderr
, "Unknown encoding %d - using OEM_CHARSET\n", enc
);
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
== '\\')
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
)
357 int ascent
= 0, il
, el
, width_bytes
= 0, space_size
, max_width
= 0;
358 BYTE left_byte
, right_byte
, byte
;
360 int i
, x
, y
, x_off
, x_end
, first_char
;
363 const union cptable
*cptable
;
364 FT_SfntName sfntname
;
368 bitmapSizeTable_t
*size_table
;
370 struct fontinfo
*info
;
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
);
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);
384 error("Can't find codepage 1252\n");
387 assert( face
->size
->metrics
.y_ppem
== ppem
);
390 if (FT_Load_Sfnt_Table(face
, TTAG_EBLC
, 0, NULL
, &needed
))
391 fprintf(stderr
,"Can't find EBLC table\n");
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
;
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. */
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)
433 else if (!strcmp(face
->family_name
, "Fixedsys"))
436 /* Japanese System font has an external leading */
437 if (!strcmp(face
->family_name
, "System") && enc
== 932)
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
);
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;
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;
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
;
509 case PAN_FAMILY_DECORATIVE
:
510 case PAN_FAMILY_PICTORIAL
:
511 info
->hdr
.fi
.dfPitchAndFamily
|= FF_DECORATIVE
;
513 case PAN_FAMILY_TEXT_DISPLAY
:
514 if(info
->hdr
.fi
.dfPitchAndFamily
== 0) /* fixed */
515 info
->hdr
.fi
.dfPitchAndFamily
= FF_MODERN
;
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
;
524 info
->hdr
.fi
.dfPitchAndFamily
|= FF_ROMAN
;
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 );
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
)) {
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;
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;
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)))
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
);
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
)
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
)
649 while ((optc
= getopt( argc
, argv
, "d:ho:qr:s" )) != -1)
654 option_defchar
= atoi( optarg
);
657 option_output
= strdup( optarg
);
663 option_dpi
= atoi( optarg
);
676 return &argv
[optind
];
679 int main(int argc
, char **argv
)
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];
688 char non_resident_name
[200];
689 unsigned short first_res
= 0x0050, pad
, res
;
690 IMAGE_OS2_HEADER NE_hdr
;
693 struct fontinfo
**info
;
698 args
= parse_options( argc
, argv
);
700 input_file
= *args
++;
701 if (!input_file
|| !*args
)
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
);
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
;
725 if (sscanf( args
[i
], "%d,%d,%d", &ppem
, &enc
, &avg_width
) != 3)
730 if (!(info
[i
] = fill_fontinfo( input_file
, ppem
, enc
, option_dpi
, option_defchar
, avg_width
)))
733 name
= get_face_name( info
[i
] );
734 fontdir_len
+= 0x74 + strlen(name
) + 1;
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
);
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)");
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
+
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);
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;
783 signal( SIGTERM
, exit_on_signal
);
784 signal( SIGINT
, exit_on_signal
);
786 signal( SIGHUP
, exit_on_signal
);
789 if (!option_output
) /* build a default output name */
791 char *p
= strrchr( 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
);
806 output_name
= option_output
;
809 write_fontinfo( info
[0], ofp
);
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
));
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
);
846 fwrite(&rc_name
, sizeof(rc_name
), 1, ofp
);
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
);
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 */
872 pad
= ftell(ofp
) & 0xf;
875 for(i
= 0; i
< pad
; i
++)
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
++) {
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
);
895 fwrite(name
, strlen(name
) + 1, 1, ofp
);
898 pad
= ftell(ofp
) & 0xf;
901 for(i
= 0; i
< pad
; i
++)
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;
909 for(j
= 0; j
< pad
; j
++)
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] );
926 #endif /* HAVE_FREETYPE */