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 void fill_fontinfo(FT_Face face
, int enc
, FILE *fp
, int dpi
, unsigned char def_char
, int avg_width
)
184 int ascent
= 0, il
, ppem
, descent
= 0, width_bytes
= 0, space_size
, max_width
= 0;
187 BYTE left_byte
, right_byte
, byte
;
189 CHAR_TABLE_ENTRY
*dfCharTable
;
190 int i
, x
, y
, x_off
, x_end
, first_char
;
193 const union cptable
*cptable
;
194 FT_SfntName sfntname
;
198 bitmapSizeTable_t
*size_table
;
201 cptable
= wine_cp_get_table(enc
);
203 error("Can't find codepage %d\n", enc
);
205 if(cptable
->info
.char_size
!= 1) {
206 /* for double byte charsets we actually want to use cp1252 */
207 cptable
= wine_cp_get_table(1252);
209 error("Can't find codepage 1252\n");
212 ppem
= face
->size
->metrics
.y_ppem
;
215 if(FT_Load_Sfnt_Table(face
, TTAG_EBLC
, 0, NULL
, &needed
))
216 error("Can't find EBLC table\n");
218 eblc
= malloc(needed
);
219 FT_Load_Sfnt_Table(face
, TTAG_EBLC
, 0, (FT_Byte
*)eblc
, &needed
);
221 num_sizes
= GET_BE_DWORD(&eblc
->numSizes
);
223 size_table
= (bitmapSizeTable_t
*)(eblc
+ 1);
224 for(i
= 0; i
< num_sizes
; i
++)
226 if(size_table
->hori
.ascender
- size_table
->hori
.descender
== ppem
)
228 ascent
= size_table
->hori
.ascender
;
229 descent
= -size_table
->hori
.descender
;
235 /* Versions of fontforge prior to early 2006 have incorrect
236 ascender values in the eblc table, so we won't find the
237 correct bitmapSizeTable. In this case use the height of
238 the Aring glyph instead. */
241 if(FT_Load_Char(face
, 0xc5, FT_LOAD_DEFAULT
))
242 error("Can't find Aring\n");
243 ascent
= face
->glyph
->metrics
.horiBearingY
>> 6;
244 descent
= ppem
- ascent
;
249 start
= sizeof(FNT_HEADER
) + sizeof(FONTINFO16
);
251 if(FT_Load_Char(face
, 'M', FT_LOAD_DEFAULT
))
252 error("Can't find M\n");
253 il
= ascent
- (face
->glyph
->metrics
.height
>> 6);
255 /* Hack: Courier has no internal leading, nor do any Chinese fonts */
256 if(!strcmp(face
->family_name
, "Courier") || enc
== 936 || enc
== 950)
259 first_char
= FT_Get_First_Char(face
, &gi
);
260 if(first_char
== 0xd) /* fontforge's first glyph is 0xd, we'll catch this and skip it */
261 first_char
= 32; /* FT_Get_Next_Char for some reason returns too high
262 number in this case */
264 dfCharTable
= malloc((255 + 3) * sizeof(*dfCharTable
));
265 memset(dfCharTable
, 0, (255 + 3) * sizeof(*dfCharTable
));
267 memset(&fi
, 0, sizeof(fi
));
268 fi
.dfFirstChar
= first_char
;
269 fi
.dfLastChar
= 0xff;
270 start
+= ((unsigned char)fi
.dfLastChar
- (unsigned char)fi
.dfFirstChar
+ 3 ) * sizeof(*dfCharTable
);
272 num_names
= FT_Get_Sfnt_Name_Count(face
);
273 for(i
= 0; i
<num_names
; i
++) {
274 FT_Get_Sfnt_Name(face
, i
, &sfntname
);
275 if(sfntname
.platform_id
== 1 && sfntname
.encoding_id
== 0 &&
276 sfntname
.language_id
== 0 && sfntname
.name_id
== 0) {
277 size_t len
= min( sfntname
.string_len
, sizeof(hdr
.dfCopyright
)-1 );
278 memcpy(hdr
.dfCopyright
, sfntname
.string
, len
);
279 hdr
.dfCopyright
[len
] = 0;
283 os2
= FT_Get_Sfnt_Table(face
, ft_sfnt_os2
);
284 for(i
= first_char
; i
< 0x100; i
++) {
285 gi
= FT_Get_Char_Index(face
, cptable
->sbcs
.cp2uni
[i
]);
287 fprintf(stderr
, "Missing glyph for char %04x\n", cptable
->sbcs
.cp2uni
[i
]);
288 if(FT_Load_Char(face
, cptable
->sbcs
.cp2uni
[i
], FT_LOAD_DEFAULT
)) {
289 fprintf(stderr
, "error loading char %d - bad news!\n", i
);
292 dfCharTable
[i
].width
= face
->glyph
->metrics
.horiAdvance
>> 6;
293 dfCharTable
[i
].offset
= start
+ (width_bytes
* ppem
);
294 width_bytes
+= ((face
->glyph
->metrics
.horiAdvance
>> 6) + 7) >> 3;
295 if(max_width
< (face
->glyph
->metrics
.horiAdvance
>> 6))
296 max_width
= face
->glyph
->metrics
.horiAdvance
>> 6;
299 space_size
= (ppem
+ 3) / 4;
300 dfCharTable
[i
].width
= space_size
;
301 dfCharTable
[i
].offset
= start
+ (width_bytes
* ppem
);
302 width_bytes
+= (space_size
+ 7) >> 3;
304 dfCharTable
[++i
].width
= 0;
305 dfCharTable
[i
].offset
= start
+ (width_bytes
* ppem
);
308 fi
.dfPoints
= ((ppem
- il
) * 72 + dpi
/2) / dpi
;
311 fi
.dfAscent
= ascent
;
312 fi
.dfInternalLeading
= il
;
313 fi
.dfExternalLeading
= 0;
314 fi
.dfItalic
= (face
->style_flags
& FT_STYLE_FLAG_ITALIC
) ? 1 : 0;
317 fi
.dfWeight
= os2
->usWeightClass
;
318 fi
.dfCharSet
= lookup_charset(enc
);
319 fi
.dfPixWidth
= (face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
) ?
321 fi
.dfPixHeight
= ppem
;
322 fi
.dfPitchAndFamily
= FT_IS_FIXED_WIDTH(face
) ? 0 : TMPF_FIXED_PITCH
;
323 switch(os2
->panose
[PAN_FAMILYTYPE_INDEX
]) {
324 case PAN_FAMILY_SCRIPT
:
325 fi
.dfPitchAndFamily
|= FF_SCRIPT
;
327 case PAN_FAMILY_DECORATIVE
:
328 case PAN_FAMILY_PICTORIAL
:
329 fi
.dfPitchAndFamily
|= FF_DECORATIVE
;
331 case PAN_FAMILY_TEXT_DISPLAY
:
332 if(fi
.dfPitchAndFamily
== 0) /* fixed */
333 fi
.dfPitchAndFamily
= FF_MODERN
;
335 switch(os2
->panose
[PAN_SERIFSTYLE_INDEX
]) {
336 case PAN_SERIF_NORMAL_SANS
:
337 case PAN_SERIF_OBTUSE_SANS
:
338 case PAN_SERIF_PERP_SANS
:
339 fi
.dfPitchAndFamily
|= FF_SWISS
;
342 fi
.dfPitchAndFamily
|= FF_ROMAN
;
347 fi
.dfPitchAndFamily
|= FF_DONTCARE
;
350 fi
.dfAvgWidth
= avg_width
;
351 fi
.dfMaxWidth
= max_width
;
352 fi
.dfDefaultChar
= def_char
- fi
.dfFirstChar
;
353 fi
.dfBreakChar
= ' ' - fi
.dfFirstChar
;
354 fi
.dfWidthBytes
= (width_bytes
+ 1) & ~1;
356 fi
.dfFace
= start
+ fi
.dfWidthBytes
* ppem
;
357 fi
.dfBitsOffset
= start
;
358 fi
.dfFlags
= 0x10; /* DFF_1COLOR */
359 fi
.dfFlags
|= FT_IS_FIXED_WIDTH(face
) ? 1 : 2; /* DFF_FIXED : DFF_PROPORTIONAL */
361 hdr
.dfVersion
= 0x300;
362 hdr
.dfSize
= start
+ fi
.dfWidthBytes
* ppem
+ strlen(face
->family_name
) + 1;
363 fwrite(&hdr
, sizeof(hdr
), 1, fp
);
364 fwrite(&fi
, sizeof(fi
), 1, fp
);
365 fwrite(dfCharTable
+ fi
.dfFirstChar
, sizeof(*dfCharTable
), ((unsigned char)fi
.dfLastChar
- (unsigned char)fi
.dfFirstChar
) + 3, fp
);
367 for(i
= first_char
; i
< 0x100; i
++) {
368 if(FT_Load_Char(face
, cptable
->sbcs
.cp2uni
[i
], FT_LOAD_DEFAULT
)) {
371 assert(dfCharTable
[i
].width
== face
->glyph
->metrics
.horiAdvance
>> 6);
373 for(x
= 0; x
< ((dfCharTable
[i
].width
+ 7) / 8); x
++) {
374 for(y
= 0; y
< ppem
; y
++) {
375 if(y
< ascent
- face
->glyph
->bitmap_top
||
376 y
>= face
->glyph
->bitmap
.rows
+ ascent
- face
->glyph
->bitmap_top
) {
380 x_off
= face
->glyph
->bitmap_left
/ 8;
381 x_end
= (face
->glyph
->bitmap_left
+ face
->glyph
->bitmap
.width
- 1) / 8;
382 if(x
< x_off
|| x
> x_end
) {
389 left_byte
= face
->glyph
->bitmap
.buffer
[(y
- (ascent
- face
->glyph
->bitmap_top
)) * face
->glyph
->bitmap
.pitch
+ x
- x_off
- 1];
391 /* On the last non-trival output byte (x == x_end) have we got one or two input bytes */
392 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)))
395 right_byte
= face
->glyph
->bitmap
.buffer
[(y
- (ascent
- face
->glyph
->bitmap_top
)) * face
->glyph
->bitmap
.pitch
+ x
- x_off
];
397 byte
= (left_byte
<< (8 - (face
->glyph
->bitmap_left
& 7))) & 0xff;
398 byte
|= ((right_byte
>> (face
->glyph
->bitmap_left
& 7)) & 0xff);
403 for(x
= 0; x
< (space_size
+ 7) / 8; x
++) {
404 for(y
= 0; y
< ppem
; y
++)
408 if(width_bytes
& 1) {
409 for(y
= 0; y
< ppem
; y
++)
412 fprintf(fp
, "%s", face
->family_name
);
418 int main(int argc
, char **argv
)
424 unsigned int def_char
;
434 ppem
= atoi(argv
[2]);
437 def_char
= atoi(argv
[5]);
438 avg_width
= atoi(argv
[6]);
440 if(FT_Init_FreeType(&lib
))
441 error("ft init failure\n");
443 if(FT_New_Face(lib
, argv
[1], 0, &face
)) {
444 fprintf(stderr
, "Can't open face\n");
449 if(FT_Set_Pixel_Sizes(face
, ppem
, ppem
)) {
450 fprintf(stderr
, "Can't set size\n");
455 strcpy(name
, face
->family_name
);
456 /* FIXME: should add a -o option instead */
457 for(cp
= name
; *cp
; cp
++)
459 if(*cp
== ' ') *cp
= '_';
460 else if (*cp
>= 'A' && *cp
<= 'Z') *cp
+= 'a' - 'A';
463 sprintf(output
, "%s-%d-%d-%d.fnt", name
, enc
, dpi
, ppem
);
466 fp
= fopen(output
, "w");
467 output_name
= output
;
469 fill_fontinfo(face
, enc
, fp
, dpi
, def_char
, avg_width
);
475 #else /* HAVE_FREETYPE */
477 int main(int argc
, char **argv
)
479 fprintf( stderr
, "%s needs to be built with FreeType support\n", argv
[0] );
483 #endif /* HAVE_FREETYPE */