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