]> git.donarmstrong.com Git - lilypond.git/blob - lily/ttf.cc
use __attribute__ format(printf)
[lilypond.git] / lily / ttf.cc
1 /*
2   ttf.cc --  implement ttf -> pfa routine.
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 2005--2006 Han-Wen Nienhuys <hanwen@xs4all.nl>
7 */
8
9 #include "freetype.hh"
10
11 #include <freetype/tttables.h>
12
13 #include "lily-proto.hh"
14 #include "memory-stream.hh"
15 #include "warn.hh"
16 #include "lily-guile.hh"
17 #include "main.hh"
18 #include "open-type-font.hh"
19
20
21 Index_to_charcode_map
22 make_index_to_charcode_map (FT_Face face)
23 {
24   Index_to_charcode_map m;
25   FT_ULong charcode;
26   FT_UInt gindex;
27
28   FT_CharMap current_cmap = face->charmap;
29   FT_Select_Charmap(face, FT_ENCODING_UNICODE);
30
31   int j = 0;
32   for (charcode = FT_Get_First_Char (face, &gindex); gindex != 0;
33        charcode = FT_Get_Next_Char (face, charcode, &gindex))
34     {
35       m[gindex] = charcode;
36       j++;
37     }
38   FT_Set_Charmap (face, current_cmap);
39
40   
41   return m;
42 }
43
44 /*
45   Based on ttfps by Juliusz Chroboczek
46 */
47 static void
48 print_header (void *out, FT_Face face)
49 {
50   lily_cookie_fprintf (out, "%%!PS-TrueTypeFont\n");
51
52   TT_Postscript *pt
53     = (TT_Postscript *) FT_Get_Sfnt_Table (face, ft_sfnt_post);
54
55   if (pt->maxMemType42)
56     lily_cookie_fprintf (out, "%%%%VMUsage: %d %d\n", 0, 0);
57
58   lily_cookie_fprintf (out, "%d dict begin\n", 11);
59   lily_cookie_fprintf (out, "/FontName /%s def\n",
60                        FT_Get_Postscript_Name (face));
61
62   lily_cookie_fprintf (out, "/Encoding StandardEncoding def\n");
63   lily_cookie_fprintf (out, "/PaintType 0 def\n");
64   lily_cookie_fprintf (out, "/FontMatrix [1 0 0 1 0 0] def\n");
65
66   TT_Header *ht
67     = (TT_Header *)FT_Get_Sfnt_Table (face, ft_sfnt_head);
68
69   lily_cookie_fprintf (out, "/FontBBox [%ld %ld %ld %ld] def\n",
70                        ht->xMin *1000L / ht->Units_Per_EM,
71                        ht->yMin *1000L / ht->Units_Per_EM,
72                        ht->xMax *1000L / ht->Units_Per_EM,
73                        ht->yMax *1000L / ht->Units_Per_EM);
74
75   lily_cookie_fprintf (out, "/FontType 42 def\n");
76   lily_cookie_fprintf (out, "/FontInfo 8 dict dup begin\n");
77   lily_cookie_fprintf (out, "/version (%d.%d) def\n",
78                        int (ht->Font_Revision >> 16),
79                        int (ht->Font_Revision &((1 << 16) -1)));
80
81 #if 0
82   if (strings[0])
83     {
84       lily_cookie_fprintf (out, "/Notice (");
85       fputpss (strings[0], out);
86       lily_cookie_fprintf (out, ") def\n");
87     }
88   if (strings[4])
89     {
90       lily_cookie_fprintf (out, "/FullName (");
91       fputpss (strings[4], out);
92       lily_cookie_fprintf (out, ") def\n");
93     }
94   if (strings[1])
95     {
96       lily_cookie_fprintf (out, "/FamilyName (");
97       fputpss (strings[1], out);
98       lily_cookie_fprintf (out, ") def\n");
99     }
100 #endif
101
102   lily_cookie_fprintf (out, "/isFixedPitch %s def\n",
103                        pt->isFixedPitch ? "true" : "false");
104   lily_cookie_fprintf (out, "/UnderlinePosition %ld def\n",
105                        pt->underlinePosition *1000L / ht->Units_Per_EM);
106   lily_cookie_fprintf (out, "/UnderlineThickness %ld def\n",
107                        pt->underlineThickness *1000L / ht->Units_Per_EM);
108   lily_cookie_fprintf (out, "end readonly def\n");
109 }
110
111 #define CHUNKSIZE 65534
112
113 static void
114 print_body (void *out, string name)
115 {
116   FILE *fd = fopen (name.c_str (), "rb");
117
118   static char xdigits[] = "0123456789ABCDEF";
119
120   unsigned char *buffer;
121   int i, j;
122
123   buffer = new unsigned char[CHUNKSIZE];
124   lily_cookie_fprintf (out, "/sfnts [");
125   for (;;)
126     {
127       i = fread (buffer, 1, CHUNKSIZE, fd);
128       if (i == 0)
129         break;
130       lily_cookie_fprintf (out, "\n<");
131       for (j = 0; j < i; j++)
132         {
133           if (j != 0 && j % 36 == 0)
134             lily_cookie_putc ('\n', out);
135           /* lily_cookie_fprintf (out,"%02X",(int)buffer[j]) is too slow */
136           lily_cookie_putc (xdigits[ (buffer[j] & 0xF0) >> 4], out);
137           lily_cookie_putc (xdigits[buffer[j] & 0x0F], out);
138         }
139       lily_cookie_fprintf (out, "00>"); /* Adobe bug? */
140       if (i < CHUNKSIZE)
141         break;
142     }
143   lily_cookie_fprintf (out, "\n] def\n");
144   delete[] buffer;
145   fclose (fd);
146 }
147
148 static void
149 print_trailer (void *out,
150                FT_Face face)
151 {
152   const int GLYPH_NAME_LEN = 256;
153   char glyph_name[GLYPH_NAME_LEN];
154
155   TT_MaxProfile *mp
156     = (TT_MaxProfile *)FT_Get_Sfnt_Table (face, ft_sfnt_maxp);
157
158   lily_cookie_fprintf (out, "/CharStrings %d dict dup begin\n", mp->numGlyphs);
159
160   Index_to_charcode_map ic_map (make_index_to_charcode_map (face));
161
162   int output_count = 0;
163   for (int i = 0; i < mp->numGlyphs; i++)
164     {
165       glyph_name[0] = 0;
166       if (face->face_flags & FT_FACE_FLAG_GLYPH_NAMES)
167         {
168           FT_Error error = FT_Get_Glyph_Name (face, i, glyph_name,
169                                               GLYPH_NAME_LEN);
170           if (error)
171             {
172               programming_error ("print_trailer(): FT_Get_Glyph_Name() returned error");
173               glyph_name[0] = 0;
174             }
175         }
176
177       if (!glyph_name[0] && ic_map.find (i) != ic_map.end ())
178         {
179           FT_ULong ucode = ic_map[i];
180           get_unicode_name (glyph_name, ucode);
181         }
182
183       if (glyph_name == string (".notdef"))
184         glyph_name[0] = '\0';
185
186       
187       if (!glyph_name[0])
188         {
189           get_glyph_index_name (glyph_name, i);
190         }
191       
192       if (glyph_name[0])
193         {
194           lily_cookie_fprintf (out, "/%s %d def ", glyph_name, i);
195           output_count ++;
196         }
197       else
198         {
199           programming_error (to_string ("no name for glyph %d", i));
200         }
201                              
202       if (! (output_count % 5))
203         lily_cookie_fprintf (out, "\n");
204     }
205
206   lily_cookie_fprintf (out, "end readonly def\n");
207   lily_cookie_fprintf (out, "FontName currentdict end definefont pop\n");
208 }
209
210 static void
211 create_type42_font (void *out, string name)
212 {
213   FT_Face face = open_ft_face (name);
214
215   print_header (out, face);
216   print_body (out, name);
217   print_trailer (out, face);
218
219   FT_Done_Face (face);
220 }
221
222
223 LY_DEFINE (ly_ttf_ps_name, "ly:ttf-ps-name",
224            1, 0, 0, (SCM ttf_file_name),
225            "Extract the PostScript name from a TrueType font.")
226 {
227   SCM_ASSERT_TYPE (scm_is_string (ttf_file_name), ttf_file_name,
228                    SCM_ARG1, __FUNCTION__, "string");
229   string file_name = ly_scm2string (ttf_file_name);
230   if (be_verbose_global)
231     progress_indication ("[" + file_name);
232
233   FT_Face face = open_ft_face (file_name);
234   char const *ps_name_str0 = FT_Get_Postscript_Name (face);
235   SCM ps_name = scm_makfrom0str (ps_name_str0 ? ps_name_str0 : "");
236   
237   FT_Done_Face (face);
238   
239   if (be_verbose_global)
240     progress_indication ("]");
241   
242   return ps_name;
243 }
244
245
246
247 LY_DEFINE (ly_ttf_to_pfa, "ly:ttf->pfa",
248            1, 0, 0, (SCM ttf_file_name),
249            "Convert the contents of a TTF file to Type42 PFA, returning it as "
250            " a string.")
251 {
252   SCM_ASSERT_TYPE (scm_is_string (ttf_file_name), ttf_file_name,
253                    SCM_ARG1, __FUNCTION__, "string");
254
255   string file_name = ly_scm2string (ttf_file_name);
256   if (be_verbose_global)
257     progress_indication ("[" + file_name);
258
259   Memory_out_stream stream;
260
261   create_type42_font (&stream, file_name);
262   SCM asscm = scm_from_locale_stringn (stream.get_string (),
263                                        stream.get_length ());
264
265   if (be_verbose_global)
266     progress_indication ("]");
267
268   return asscm;
269 }