2 ttf.cc -- implement ttf -> pfa routine.
4 source file of the GNU LilyPond music typesetter
6 (c) 2005--2007 Han-Wen Nienhuys <hanwen@xs4all.nl>
11 #include <freetype/tttables.h>
13 #include "memory-stream.hh"
15 #include "lily-guile.hh"
17 #include "open-type-font.hh"
21 make_index_to_charcode_map (FT_Face face
)
23 Index_to_charcode_map m
;
27 FT_CharMap current_cmap
= face
->charmap
;
28 FT_Select_Charmap (face
, FT_ENCODING_UNICODE
);
31 for (charcode
= FT_Get_First_Char (face
, &gindex
); gindex
!= 0;
32 charcode
= FT_Get_Next_Char (face
, charcode
, &gindex
))
37 FT_Set_Charmap (face
, current_cmap
);
43 Based on ttfps by Juliusz Chroboczek
46 print_header (void *out
, FT_Face face
)
48 lily_cookie_fprintf (out
, "%%!PS-TrueTypeFont\n");
51 = (TT_Postscript
*) FT_Get_Sfnt_Table (face
, ft_sfnt_post
);
54 lily_cookie_fprintf (out
, "%%%%VMUsage: %d %d\n", 0, 0);
56 lily_cookie_fprintf (out
, "%d dict begin\n", 11);
57 lily_cookie_fprintf (out
, "/FontName /%s def\n",
58 FT_Get_Postscript_Name (face
));
60 lily_cookie_fprintf (out
, "/Encoding StandardEncoding def\n");
61 lily_cookie_fprintf (out
, "/PaintType 0 def\n");
62 lily_cookie_fprintf (out
, "/FontMatrix [1 0 0 1 0 0] def\n");
65 = (TT_Header
*)FT_Get_Sfnt_Table (face
, ft_sfnt_head
);
67 lily_cookie_fprintf (out
, "/FontBBox [%lf %lf %lf %lf] def\n",
68 float (ht
->xMin
) / ht
->Units_Per_EM
,
69 float (ht
->yMin
) / ht
->Units_Per_EM
,
70 float (ht
->xMax
) / ht
->Units_Per_EM
,
71 float (ht
->yMax
) / ht
->Units_Per_EM
);
73 lily_cookie_fprintf (out
, "/FontType 42 def\n");
74 lily_cookie_fprintf (out
, "/FontInfo 8 dict dup begin\n");
75 lily_cookie_fprintf (out
, "/version (%.3f) def\n",
76 ht
->Font_Revision
/ 65536.0);
81 lily_cookie_fprintf (out
, "/Notice (");
82 fputpss (strings
[0], out
);
83 lily_cookie_fprintf (out
, ") def\n");
87 lily_cookie_fprintf (out
, "/FullName (");
88 fputpss (strings
[4], out
);
89 lily_cookie_fprintf (out
, ") def\n");
93 lily_cookie_fprintf (out
, "/FamilyName (");
94 fputpss (strings
[1], out
);
95 lily_cookie_fprintf (out
, ") def\n");
99 lily_cookie_fprintf (out
, "/isFixedPitch %s def\n",
100 pt
->isFixedPitch
? "true" : "false");
101 lily_cookie_fprintf (out
, "/UnderlinePosition %lf def\n",
102 float (pt
->underlinePosition
) / ht
->Units_Per_EM
);
103 lily_cookie_fprintf (out
, "/UnderlineThickness %lf def\n",
104 float (pt
->underlineThickness
) / ht
->Units_Per_EM
);
105 lily_cookie_fprintf (out
, "end readonly def\n");
108 #define CHUNKSIZE 65534
110 const FT_ULong
FT_ENC_TAG (glyf_tag
, 'g', 'l', 'y', 'f');
111 const FT_ULong
FT_ENC_TAG (head_tag
, 'h', 'e', 'a', 'd');
112 const FT_ULong
FT_ENC_TAG (loca_tag
, 'l', 'o', 'c', 'a');
115 void t42_write_table (void *out
, FT_Face face
, unsigned char const *buffer
,
116 size_t s
, bool is_glyf
,
117 FT_ULong head_length
, FT_ULong loca_length
)
119 vector
<FT_UShort
> chunks
;
123 /* compute chunk sizes */
124 unsigned char *head_buf
= new unsigned char[head_length
];
125 FT_Error error
= FT_Load_Sfnt_Table (face
, head_tag
, 0, head_buf
, NULL
);
127 programming_error ("FT_Load_Sfnt_Table (): error.");
129 /* we access the lower byte of indexToLocFormat */
130 bool long_offsets
= head_buf
[4*4 + 2*2 + 2*8 + 4*2 + 3*2 + 1] == 1;
134 unsigned char *loca_buf
= new unsigned char[loca_length
];
135 error
= FT_Load_Sfnt_Table (face
, loca_tag
, 0, loca_buf
, NULL
);
137 programming_error ("FT_Load_Sfnt_Table (): error.");
139 unsigned char *p
= loca_buf
;
140 unsigned char *endp
= loca_buf
+ loca_length
;
142 FT_ULong offset
= 0, last_offset
= 0, last_chunk
= 0;
147 offset
= (p
[0] << 24) | (p
[1] << 16) | (p
[2] << 8) | p
[3];
152 offset
= ((p
[0] << 8) | p
[1]) << 1;
155 if (offset
> last_offset
+ CHUNKSIZE
)
157 if (last_chunk
!= last_offset
)
158 chunks
.push_back (last_offset
- last_chunk
);
160 a single glyph with more than 64k data
161 is a pathological case but...
163 FT_ULong rest
= offset
- last_offset
;
164 while (rest
> CHUNKSIZE
)
166 chunks
.push_back (CHUNKSIZE
);
169 chunks
.push_back (rest
);
172 else if (offset
> last_chunk
+ CHUNKSIZE
)
174 chunks
.push_back (last_offset
- last_chunk
);
175 last_chunk
= last_offset
;
178 last_offset
= offset
;
180 chunks
.push_back (s
- last_chunk
);
184 else if (s
> CHUNKSIZE
)
187 while (rest
> CHUNKSIZE
)
189 chunks
.push_back (CHUNKSIZE
);
192 chunks
.push_back (rest
);
195 chunks
.push_back (CHUNKSIZE
);
197 lily_cookie_fprintf (out
, "\n"
201 static char xdigits
[] = "0123456789ABCDEF";
203 int cur_chunk_idx
= 0;
204 for (size_t j
= 0; j
< s
; j
++)
206 if (l
>= chunks
[cur_chunk_idx
])
208 lily_cookie_fprintf (out
, "\n"
216 lily_cookie_fprintf (out
, "\n"
219 /* lily_cookie_fprintf (out,"%02X",(int)buffer[j]) is too slow */
220 lily_cookie_putc (xdigits
[(buffer
[j
] & 0xF0) >> 4], out
);
221 lily_cookie_putc (xdigits
[buffer
[j
] & 0x0F], out
);
226 /* pad to four-byte boundary */
227 while ((s
++) % 4 != 0)
228 lily_cookie_fprintf (out
, "00");
230 lily_cookie_fprintf (out
, "\n"
236 print_body (void *out
, FT_Face face
)
239 FT_ULong head_length
= 0, loca_length
= 0;
240 FT_ULong tag
, length
;
241 vector
<FT_ULong
> lengths
, tags
;
244 we must build our own TTF header -- the original font
245 might be a TTC where tables are not contiguous, or the font
246 contains tables which aren't indexed at all
248 while (FT_Sfnt_Table_Info (face
, idx
, &tag
, &length
)
249 != FT_Err_Table_Missing
)
251 lengths
.push_back (length
);
252 tags
.push_back (tag
);
254 head_length
= length
;
255 else if (tag
== loca_tag
)
256 loca_length
= length
;
260 FT_ULong hlength
= 12 + 16 * idx
;
262 unsigned char *hbuf
= new unsigned char[hlength
];
265 hbuf
[0] = 0x00; /* version */
269 hbuf
[4] = (idx
& 0xFF00) >> 8; /* numTables */
270 hbuf
[5] = idx
& 0x00FF;
272 FT_UInt searchRange
, entrySelector
, rangeShift
;
274 for (i
= 1, j
= 2; j
<= idx
; i
++, j
<<= 1)
276 entrySelector
= i
- 1;
277 searchRange
= 0x10 << entrySelector
;
278 rangeShift
= (idx
<< 4) - searchRange
;
280 hbuf
[6] = (searchRange
& 0xFF00) >> 8;
281 hbuf
[7] = searchRange
& 0x00FF;
282 hbuf
[8] = (entrySelector
& 0xFF00) >> 8;
283 hbuf
[9] = entrySelector
& 0x00FF;
284 hbuf
[10] = (rangeShift
& 0xFF00) >> 8;
285 hbuf
[11] = rangeShift
& 0x00FF;
289 FT_ULong checksum
, font_checksum
= 0;
291 FT_ULong offset
= hlength
; /* first table offset */
293 for (FT_UInt i
= 0; i
< idx
; i
++)
295 /* here, the buffer length must be a multiple of 4 */
296 FT_ULong len
= (lengths
[i
] + 3) & ~3;
297 unsigned char *buf
= new unsigned char[len
];
299 buf
[len
- 1] = 0x00; /* assure padding with zeros */
303 FT_Error error
= FT_Load_Sfnt_Table (face
, tags
[i
], 0, buf
, NULL
);
305 programming_error ("FT_Load_Sfnt_Table (): error.");
310 first pass of computing the font checksum
311 needs checkSumAdjustment = 0
320 unsigned char *endq
= buf
+ len
;
321 for (unsigned char *q
= buf
; q
< endq
; q
+= 4)
322 checksum
+= (q
[0] << 24) | (q
[1] << 16) | (q
[2] << 8) | q
[3];
323 font_checksum
+= checksum
;
327 *(p
++) = (tags
[i
] & 0xFF000000UL
) >> 24;
328 *(p
++) = (tags
[i
] & 0x00FF0000UL
) >> 16;
329 *(p
++) = (tags
[i
] & 0x0000FF00UL
) >> 8;
330 *(p
++) = tags
[i
] & 0x000000FFUL
;
332 *(p
++) = (checksum
& 0xFF000000UL
) >> 24;
333 *(p
++) = (checksum
& 0x00FF0000UL
) >> 16;
334 *(p
++) = (checksum
& 0x0000FF00UL
) >> 8;
335 *(p
++) = checksum
& 0x000000FFUL
;
337 *(p
++) = (offset
& 0xFF000000UL
) >> 24;
338 *(p
++) = (offset
& 0x00FF0000UL
) >> 16;
339 *(p
++) = (offset
& 0x0000FF00UL
) >> 8;
340 *(p
++) = offset
& 0x000000FFUL
;
342 *(p
++) = (lengths
[i
] & 0xFF000000UL
) >> 24;
343 *(p
++) = (lengths
[i
] & 0x00FF0000UL
) >> 16;
344 *(p
++) = (lengths
[i
] & 0x0000FF00UL
) >> 8;
345 *(p
++) = lengths
[i
] & 0x000000FFUL
;
347 /* offset must be a multiple of 4 */
348 offset
+= (lengths
[i
] + 3) & ~3;
351 /* add checksum of TTF header */
353 for (unsigned char *q
= hbuf
; q
< p
; q
+= 4)
354 checksum
+= (q
[0] << 24) | (q
[1] << 16) | (q
[2] << 8) | q
[3];
355 font_checksum
+= checksum
;
356 font_checksum
= 0xB1B0AFBAUL
- font_checksum
;
359 see Adobe technical note 5012.Type42_Spec.pdf for details how
360 the /sfnts array must be constructed
362 lily_cookie_fprintf (out
, "/sfnts [");
363 t42_write_table (out
, face
, hbuf
, hlength
, false,
364 head_length
, loca_length
);
369 while (FT_Sfnt_Table_Info (face
, idx
, &tag
, &length
)
370 != FT_Err_Table_Missing
)
372 unsigned char *buf
= new unsigned char[length
];
373 FT_Error error
= FT_Load_Sfnt_Table (face
, tag
, 0, buf
, NULL
);
375 programming_error ("FT_Load_Sfnt_Table (): error.");
379 /* in the second pass simply store the computed font checksum */
380 buf
[8] = (font_checksum
& 0xFF000000UL
) >> 24;
381 buf
[9] = (font_checksum
& 0x00FF0000UL
) >> 16;
382 buf
[10] = (font_checksum
& 0x0000FF00UL
) >> 8;
383 buf
[11] = font_checksum
& 0x000000FFUL
;
386 bool is_glyf_table
= tag
== glyf_tag
&& length
> CHUNKSIZE
;
387 t42_write_table (out
, face
, buf
, length
, is_glyf_table
,
388 head_length
, loca_length
);
393 lily_cookie_fprintf (out
, "\n] def\n");
397 print_trailer (void *out
,
400 const int GLYPH_NAME_LEN
= 256;
401 char glyph_name
[GLYPH_NAME_LEN
];
404 = (TT_MaxProfile
*)FT_Get_Sfnt_Table (face
, ft_sfnt_maxp
);
406 lily_cookie_fprintf (out
, "/CharStrings %d dict dup begin\n", mp
->numGlyphs
);
408 Index_to_charcode_map
ic_map (make_index_to_charcode_map (face
));
410 int output_count
= 0;
411 for (int i
= 0; i
< mp
->numGlyphs
; i
++)
414 if (face
->face_flags
& FT_FACE_FLAG_GLYPH_NAMES
)
416 FT_Error error
= FT_Get_Glyph_Name (face
, i
, glyph_name
,
420 programming_error ("FT_Get_Glyph_Name (): error.");
425 if (!glyph_name
[0] && ic_map
.find (i
) != ic_map
.end ())
427 FT_ULong ucode
= ic_map
[i
];
428 get_unicode_name (glyph_name
, ucode
);
432 sprintf (glyph_name
, ".notdef");
433 else if (glyph_name
== string (".notdef"))
434 glyph_name
[0] = '\0';
437 get_glyph_index_name (glyph_name
, i
);
441 lily_cookie_fprintf (out
, "/%s %d def ", glyph_name
, i
);
445 programming_error (to_string ("no name for glyph %d", i
));
447 if (! (output_count
% 5))
448 lily_cookie_fprintf (out
, "\n");
451 lily_cookie_fprintf (out
, "end readonly def\n");
452 lily_cookie_fprintf (out
, "FontName currentdict end definefont pop\n");
456 create_type42_font (void *out
, string name
)
458 FT_Face face
= open_ft_face (name
);
460 print_header (out
, face
);
461 print_body (out
, face
);
462 print_trailer (out
, face
);
468 LY_DEFINE (ly_ttf_ps_name
, "ly:ttf-ps-name",
469 1, 0, 0, (SCM ttf_file_name
),
470 "Extract the PostScript name from a TrueType font.")
472 LY_ASSERT_TYPE (scm_is_string
, ttf_file_name
, 1);
473 string file_name
= ly_scm2string (ttf_file_name
);
474 if (be_verbose_global
)
475 progress_indication ("[" + file_name
);
477 FT_Face face
= open_ft_face (file_name
);
478 char const *ps_name_str0
= FT_Get_Postscript_Name (face
);
479 SCM ps_name
= scm_from_locale_string (ps_name_str0
? ps_name_str0
: "");
483 if (be_verbose_global
)
484 progress_indication ("]");
491 LY_DEFINE (ly_ttf_2_pfa
, "ly:ttf->pfa",
492 1, 0, 0, (SCM ttf_file_name
),
493 "Convert the contents of a TTF file to Type42 PFA, returning it as"
496 LY_ASSERT_TYPE (scm_is_string
, ttf_file_name
, 1);
498 string file_name
= ly_scm2string (ttf_file_name
);
499 if (be_verbose_global
)
500 progress_indication ("[" + file_name
);
502 Memory_out_stream stream
;
504 create_type42_font (&stream
, file_name
);
505 SCM asscm
= scm_from_locale_stringn (stream
.get_string (),
506 stream
.get_length ());
508 if (be_verbose_global
)
509 progress_indication ("]");