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