2 * sfnttofnt. Bitmap only ttf to Window fnt file converter
4 * Copyright 2004 Huw Davies
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "wine/port.h"
31 #ifdef HAVE_FT2BUILD_H
34 #include FT_FREETYPE_H
35 #include FT_SFNT_NAMES_H
36 #include FT_TRUETYPE_TABLES_H
37 #include FT_TRUETYPE_TAGS_H
39 #include "wine/unicode.h"
40 #include "wine/wingdi16.h"
66 CHAR caretSlopeNumerator
;
67 CHAR caretSlopeDenominator
;
78 ULONG indexSubTableArrayOffset
;
80 ULONG numberOfIndexSubTables
;
82 sbitLineMetrics_t hori
;
83 sbitLineMetrics_t vert
;
84 USHORT startGlyphIndex
;
92 #define GET_BE_WORD(ptr) MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
93 #define GET_BE_DWORD(ptr) ((DWORD)MAKELONG( GET_BE_WORD(&((WORD *)(ptr))[1]), \
94 GET_BE_WORD(&((WORD *)(ptr))[0]) ))
98 static const char *output_name
;
100 static void usage(char **argv
)
102 fprintf(stderr
, "%s foo.ttf ppem enc dpi def_char avg_width\n", argv
[0]);
107 #define __attribute__(X)
110 /* atexit handler to cleanup files */
111 static void cleanup(void)
113 if (output_name
) unlink( output_name
);
116 static void error(const char *s
, ...) __attribute__((format (printf
, 1, 2)));
118 static void error(const char *s
, ...)
122 fprintf(stderr
, "Error: ");
123 vfprintf(stderr
, s
, ap
);
128 static int lookup_charset(int enc
)
130 /* FIXME: make winelib app and use TranslateCharsetInfo */
135 return RUSSIAN_CHARSET
;
139 return GREEK_CHARSET
;
141 return TURKISH_CHARSET
;
143 return HEBREW_CHARSET
;
145 return ARABIC_CHARSET
;
147 return BALTIC_CHARSET
;
149 return VIETNAMESE_CHARSET
;
169 return SHIFTJIS_CHARSET
;
171 return GB2312_CHARSET
;
173 return HANGUL_CHARSET
;
175 return CHINESEBIG5_CHARSET
;
177 fprintf(stderr
, "Unknown encoding %d - using OEM_CHARSET\n", enc
);
182 static int get_char(const union cptable
*cptable
, int enc
, int index
)
184 /* Korean has the Won sign in place of '\\' */
185 if(enc
== 949 && index
== '\\')
188 return cptable
->sbcs
.cp2uni
[index
];
191 static void fill_fontinfo(FT_Face face
, int enc
, FILE *fp
, int dpi
, unsigned char def_char
, int avg_width
)
193 int ascent
= 0, il
, ppem
, descent
= 0, width_bytes
= 0, space_size
, max_width
= 0;
196 BYTE left_byte
, right_byte
, byte
;
198 CHAR_TABLE_ENTRY
*dfCharTable
;
199 int i
, x
, y
, x_off
, x_end
, first_char
;
202 const union cptable
*cptable
;
203 FT_SfntName sfntname
;
207 bitmapSizeTable_t
*size_table
;
210 cptable
= wine_cp_get_table(enc
);
212 error("Can't find codepage %d\n", enc
);
214 if(cptable
->info
.char_size
!= 1) {
215 /* for double byte charsets we actually want to use cp1252 */
216 cptable
= wine_cp_get_table(1252);
218 error("Can't find codepage 1252\n");
221 ppem
= face
->size
->metrics
.y_ppem
;
224 if(FT_Load_Sfnt_Table(face
, TTAG_EBLC
, 0, NULL
, &needed
))
225 error("Can't find EBLC table\n");
227 eblc
= malloc(needed
);
228 FT_Load_Sfnt_Table(face
, TTAG_EBLC
, 0, (FT_Byte
*)eblc
, &needed
);
230 num_sizes
= GET_BE_DWORD(&eblc
->numSizes
);
232 size_table
= (bitmapSizeTable_t
*)(eblc
+ 1);
233 for(i
= 0; i
< num_sizes
; i
++)
235 if(size_table
->hori
.ascender
- size_table
->hori
.descender
== ppem
)
237 ascent
= size_table
->hori
.ascender
;
238 descent
= -size_table
->hori
.descender
;
244 /* Versions of fontforge prior to early 2006 have incorrect
245 ascender values in the eblc table, so we won't find the
246 correct bitmapSizeTable. In this case use the height of
247 the Aring glyph instead. */
250 if(FT_Load_Char(face
, 0xc5, FT_LOAD_DEFAULT
))
251 error("Can't find Aring\n");
252 ascent
= face
->glyph
->metrics
.horiBearingY
>> 6;
253 descent
= ppem
- ascent
;
258 start
= sizeof(FNT_HEADER
) + sizeof(FONTINFO16
);
260 if(FT_Load_Char(face
, 'M', FT_LOAD_DEFAULT
))
261 error("Can't find M\n");
262 il
= ascent
- (face
->glyph
->metrics
.height
>> 6);
264 /* Hack: Courier has no internal leading, nor do any Chinese fonts */
265 if(!strcmp(face
->family_name
, "Courier") || enc
== 936 || enc
== 950)
268 first_char
= FT_Get_First_Char(face
, &gi
);
269 if(first_char
== 0xd) /* fontforge's first glyph is 0xd, we'll catch this and skip it */
270 first_char
= 32; /* FT_Get_Next_Char for some reason returns too high
271 number in this case */
273 dfCharTable
= malloc((255 + 3) * sizeof(*dfCharTable
));
274 memset(dfCharTable
, 0, (255 + 3) * sizeof(*dfCharTable
));
276 memset(&fi
, 0, sizeof(fi
));
277 fi
.dfFirstChar
= first_char
;
278 fi
.dfLastChar
= 0xff;
279 start
+= ((unsigned char)fi
.dfLastChar
- (unsigned char)fi
.dfFirstChar
+ 3 ) * sizeof(*dfCharTable
);
281 num_names
= FT_Get_Sfnt_Name_Count(face
);
282 for(i
= 0; i
<num_names
; i
++) {
283 FT_Get_Sfnt_Name(face
, i
, &sfntname
);
284 if(sfntname
.platform_id
== 1 && sfntname
.encoding_id
== 0 &&
285 sfntname
.language_id
== 0 && sfntname
.name_id
== 0) {
286 size_t len
= min( sfntname
.string_len
, sizeof(hdr
.dfCopyright
)-1 );
287 memcpy(hdr
.dfCopyright
, sfntname
.string
, len
);
288 hdr
.dfCopyright
[len
] = 0;
292 os2
= FT_Get_Sfnt_Table(face
, ft_sfnt_os2
);
293 for(i
= first_char
; i
< 0x100; i
++) {
294 int c
= get_char(cptable
, enc
, i
);
295 gi
= FT_Get_Char_Index(face
, c
);
297 fprintf(stderr
, "Missing glyph for char %04x\n", cptable
->sbcs
.cp2uni
[i
]);
298 if(FT_Load_Char(face
, c
, FT_LOAD_DEFAULT
)) {
299 fprintf(stderr
, "error loading char %d - bad news!\n", i
);
302 dfCharTable
[i
].width
= face
->glyph
->metrics
.horiAdvance
>> 6;
303 dfCharTable
[i
].offset
= start
+ (width_bytes
* ppem
);
304 width_bytes
+= ((face
->glyph
->metrics
.horiAdvance
>> 6) + 7) >> 3;
305 if(max_width
< (face
->glyph
->metrics
.horiAdvance
>> 6))
306 max_width
= face
->glyph
->metrics
.horiAdvance
>> 6;
309 space_size
= (ppem
+ 3) / 4;
310 dfCharTable
[i
].width
= space_size
;
311 dfCharTable
[i
].offset
= start
+ (width_bytes
* ppem
);
312 width_bytes
+= (space_size
+ 7) >> 3;
314 dfCharTable
[++i
].width
= 0;
315 dfCharTable
[i
].offset
= start
+ (width_bytes
* ppem
);
318 fi
.dfPoints
= ((ppem
- il
) * 72 + dpi
/2) / dpi
;
321 fi
.dfAscent
= ascent
;
322 fi
.dfInternalLeading
= il
;
323 fi
.dfExternalLeading
= 0;
324 fi
.dfItalic
= (face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 1 : 0;
327 fi
.dfWeight
= os2
->usWeightClass
;
328 fi
.dfCharSet
= lookup_charset(enc
);
329 fi
.dfPixWidth
= (face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
) ?
331 fi
.dfPixHeight
= ppem
;
332 fi
.dfPitchAndFamily
= FT_IS_FIXED_WIDTH(face
) ? 0 : TMPF_FIXED_PITCH
;
333 switch(os2
->panose
[PAN_FAMILYTYPE_INDEX
]) {
334 case PAN_FAMILY_SCRIPT
:
335 fi
.dfPitchAndFamily
|= FF_SCRIPT
;
337 case PAN_FAMILY_DECORATIVE
:
338 case PAN_FAMILY_PICTORIAL
:
339 fi
.dfPitchAndFamily
|= FF_DECORATIVE
;
341 case PAN_FAMILY_TEXT_DISPLAY
:
342 if(fi
.dfPitchAndFamily
== 0) /* fixed */
343 fi
.dfPitchAndFamily
= FF_MODERN
;
345 switch(os2
->panose
[PAN_SERIFSTYLE_INDEX
]) {
346 case PAN_SERIF_NORMAL_SANS
:
347 case PAN_SERIF_OBTUSE_SANS
:
348 case PAN_SERIF_PERP_SANS
:
349 fi
.dfPitchAndFamily
|= FF_SWISS
;
352 fi
.dfPitchAndFamily
|= FF_ROMAN
;
357 fi
.dfPitchAndFamily
|= FF_DONTCARE
;
360 fi
.dfAvgWidth
= avg_width
;
361 fi
.dfMaxWidth
= max_width
;
362 fi
.dfDefaultChar
= def_char
- fi
.dfFirstChar
;
363 fi
.dfBreakChar
= ' ' - fi
.dfFirstChar
;
364 fi
.dfWidthBytes
= (width_bytes
+ 1) & ~1;
366 fi
.dfFace
= start
+ fi
.dfWidthBytes
* ppem
;
367 fi
.dfBitsOffset
= start
;
368 fi
.dfFlags
= 0x10; /* DFF_1COLOR */
369 fi
.dfFlags
|= FT_IS_FIXED_WIDTH(face
) ? 1 : 2; /* DFF_FIXED : DFF_PROPORTIONAL */
371 hdr
.dfVersion
= 0x300;
372 hdr
.dfSize
= start
+ fi
.dfWidthBytes
* ppem
+ strlen(face
->family_name
) + 1;
373 fwrite(&hdr
, sizeof(hdr
), 1, fp
);
374 fwrite(&fi
, sizeof(fi
), 1, fp
);
375 fwrite(dfCharTable
+ fi
.dfFirstChar
, sizeof(*dfCharTable
), ((unsigned char)fi
.dfLastChar
- (unsigned char)fi
.dfFirstChar
) + 3, fp
);
377 for(i
= first_char
; i
< 0x100; i
++) {
378 int c
= get_char(cptable
, enc
, i
);
379 if(FT_Load_Char(face
, c
, FT_LOAD_DEFAULT
)) {
382 assert(dfCharTable
[i
].width
== face
->glyph
->metrics
.horiAdvance
>> 6);
384 for(x
= 0; x
< ((dfCharTable
[i
].width
+ 7) / 8); x
++) {
385 for(y
= 0; y
< ppem
; y
++) {
386 if(y
< ascent
- face
->glyph
->bitmap_top
||
387 y
>= face
->glyph
->bitmap
.rows
+ ascent
- face
->glyph
->bitmap_top
) {
391 x_off
= face
->glyph
->bitmap_left
/ 8;
392 x_end
= (face
->glyph
->bitmap_left
+ face
->glyph
->bitmap
.width
- 1) / 8;
393 if(x
< x_off
|| x
> x_end
) {
400 left_byte
= face
->glyph
->bitmap
.buffer
[(y
- (ascent
- face
->glyph
->bitmap_top
)) * face
->glyph
->bitmap
.pitch
+ x
- x_off
- 1];
402 /* On the last non-trival output byte (x == x_end) have we got one or two input bytes */
403 if(x
== x_end
&& (face
->glyph
->bitmap_left
% 8 != 0) && ((face
->glyph
->bitmap
.width
% 8 == 0) || (x
!= (((face
->glyph
->bitmap
.width
) & ~0x7) + face
->glyph
->bitmap_left
) / 8)))
406 right_byte
= face
->glyph
->bitmap
.buffer
[(y
- (ascent
- face
->glyph
->bitmap_top
)) * face
->glyph
->bitmap
.pitch
+ x
- x_off
];
408 byte
= (left_byte
<< (8 - (face
->glyph
->bitmap_left
& 7))) & 0xff;
409 byte
|= ((right_byte
>> (face
->glyph
->bitmap_left
& 7)) & 0xff);
414 for(x
= 0; x
< (space_size
+ 7) / 8; x
++) {
415 for(y
= 0; y
< ppem
; y
++)
419 if(width_bytes
& 1) {
420 for(y
= 0; y
< ppem
; y
++)
423 fprintf(fp
, "%s", face
->family_name
);
429 int main(int argc
, char **argv
)
435 unsigned int def_char
;
445 ppem
= atoi(argv
[2]);
448 def_char
= atoi(argv
[5]);
449 avg_width
= atoi(argv
[6]);
451 if(FT_Init_FreeType(&lib
))
452 error("ft init failure\n");
454 if(FT_New_Face(lib
, argv
[1], 0, &face
)) {
455 fprintf(stderr
, "Can't open face\n");
460 if(FT_Set_Pixel_Sizes(face
, ppem
, ppem
)) {
461 fprintf(stderr
, "Can't set size\n");
466 strcpy(name
, face
->family_name
);
467 /* FIXME: should add a -o option instead */
468 for(cp
= name
; *cp
; cp
++)
470 if(*cp
== ' ') *cp
= '_';
471 else if (*cp
>= 'A' && *cp
<= 'Z') *cp
+= 'a' - 'A';
474 sprintf(output
, "%s-%d-%d-%d.fnt", name
, enc
, dpi
, ppem
);
477 fp
= fopen(output
, "w");
478 output_name
= output
;
480 fill_fontinfo(face
, enc
, fp
, dpi
, def_char
, avg_width
);
486 #else /* HAVE_FREETYPE */
488 int main(int argc
, char **argv
)
490 fprintf( stderr
, "%s needs to be built with FreeType support\n", argv
[0] );
494 #endif /* HAVE_FREETYPE */