]> git.donarmstrong.com Git - lilypond.git/blob - lily/pdf.cc
* lily/kpath.cc:
[lilypond.git] / lily / pdf.cc
1 /*
2   pdf.cc -- implement Pdf output routines.
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 2005 Han-Wen Nienhuys <hanwen@xs4all.nl>
7
8 */
9
10 #include "warn.hh"
11 #include "pdf.hh"
12 #include "ly-smobs.icc"
13
14 IMPLEMENT_SMOBS (Pdf_object);
15 IMPLEMENT_DEFAULT_EQUAL_P (Pdf_object);
16 IMPLEMENT_TYPE_P (Pdf_object, "pdf-object?");
17
18
19 Pdf_object::Pdf_object ()
20 {
21   object_number_ = 0;
22   value_ = SCM_BOOL_F;
23   written_ = false;
24   byte_count_ = 0;
25
26   smobify_self ();
27 }
28
29 Pdf_object::~Pdf_object ()
30 {
31
32 }
33
34 bool
35 Pdf_object::is_dict () const
36 {
37   return scm_is_pair (value_)
38     && scm_car (value_) == ly_symbol2scm ("dictionary");
39 }
40
41 bool
42 Pdf_object::is_indirect () const
43 {
44   return object_number_ > 0;
45 }
46
47
48 void
49 Pdf_object::typecheck (SCM val)
50 {
51   if (scm_is_pair (val))
52     {
53       SCM tag = scm_car (val);
54       if (tag == ly_symbol2scm ("null"))
55         val = SCM_UNDEFINED;
56       else if (tag == ly_symbol2scm ("dictionary"))
57         {
58           SCM alist = scm_cdr (val);
59           for (SCM s = alist; scm_is_pair (alist); s = scm_cdr (s))
60             {
61               Pdf_object *key = unsmob_pdf_object (scm_caar (s));
62               Pdf_object *val = unsmob_pdf_object (scm_cdar (s));
63
64               if (!key || !val)
65                 {
66                   ly_display_scm (scm_car (s));
67                   error ("key and value must be PDF objects.");
68                 }
69             }
70         }
71       else if (tag == ly_symbol2scm ("stream"))
72         {
73           if (!scm_is_string (scm_cdr (val)))
74             error ("stream argument should be string");
75         }
76       else
77         {
78           ly_display_scm (tag);
79           error ("unknown tag");
80         }
81     }
82   else if (scm_is_vector (val))
83     {
84       SCM vec = val;
85       int len = scm_c_vector_length (vec);
86       for (int i = 0; i < len; i++)
87         {
88           Pdf_object *val = unsmob_pdf_object (scm_c_vector_ref (vec, i));
89           if (!val)
90             {
91               ly_display_scm (scm_c_vector_ref (vec, i));
92               error ("array content should be PDF object");
93             }
94         }
95     }
96 }
97
98 void
99 Pdf_object::set_value (SCM val)
100 {
101   if (written_)
102     error ("Can't set value for written PDF object");
103
104   typecheck (val);
105
106   value_ = val;
107 }
108
109 SCM
110 Pdf_object::mark_smob (SCM smob)
111 {
112   Pdf_object *p = (Pdf_object*) SCM_CELL_WORD_1 (smob);
113   return p->value_;
114 }
115
116 int
117 Pdf_object::print_smob (SCM smob, SCM port, scm_print_state *)
118 {
119   Pdf_object *obj = (Pdf_object*) SCM_CELL_WORD_1 (smob);
120   scm_puts ("#<Pdf_object ", port);
121   scm_display (obj->value_, port);
122   scm_puts (">", port);
123   return 1;
124 }
125
126
127 void
128 Pdf_object::write_dict (FILE *file, SCM alist)
129 {
130   String str = "";
131
132   fputs ("<< " , file);
133   for (SCM s = alist; scm_is_pair (s); s = scm_cdr (s))
134     {
135       Pdf_object *key = unsmob_pdf_object (scm_caar (s));
136       Pdf_object *val = unsmob_pdf_object (scm_cdar (s));
137
138       assert (val && key);
139
140       key->write_to_file (file, false);
141       val->write_to_file (file, false);
142     }
143   fputs (">>\n" , file);
144 }
145
146 void
147 Pdf_object::write_vector (FILE *file, SCM vec)
148 {
149   String str = "";
150
151   fputs ("[ " , file);
152   int len = scm_c_vector_length (vec);
153   for (int i = 0; i < len; i++)
154     {
155       Pdf_object *val = unsmob_pdf_object (scm_c_vector_ref (vec, i));
156       assert (val);
157       val->write_to_file (file, false);
158     }
159   fputs ("]\n" , file);
160 }
161
162
163 void
164 Pdf_object::write_stream (FILE *file, SCM scmstr)
165 {
166   String str = ly_scm2string (scmstr);
167   fprintf (file, "<< /Length %d >>\nstream\n" , str.length ());
168   fwrite (str.get_bytes (), str.length (), sizeof (Byte), file);
169   fputs ("endstream" , file);
170 }
171
172 String
173 Pdf_object::escape_string (String str)
174 {
175   str.substitute_char ('\\', "\\\\");
176   str.substitute_char ('(', "\\(");
177   str.substitute_char (')', "\\)");
178   return str;
179 }
180
181 String
182 Pdf_object::to_string () const
183 {
184   if (value_ == SCM_BOOL_F)
185     return "false";
186   else if (value_ == SCM_UNDEFINED)
187     return "null";
188   else if (value_ == SCM_BOOL_T)
189     return "true";
190   else if (scm_is_integer (value_))
191     return ::to_string (scm_to_int (value_));
192   else if (scm_is_number (value_))
193     return ::to_string (scm_to_double (value_));
194   else if (scm_is_symbol (value_))
195     return "/" + ly_symbol2string (value_);
196   else if (scm_is_string (value_))
197     return "(" + escape_string (ly_scm2string (value_)) + ")";
198
199   assert (false);
200 }
201
202 void
203 Pdf_object::write_to_file (FILE* file, bool dump_definition) const
204 {
205   if (is_indirect () && !dump_definition)
206     {
207       fprintf (file, "%d 0 R", object_number_);
208       return;
209     }
210
211   if (scm_is_vector (value_))
212     write_vector (file, value_);
213   else if (scm_is_pair (value_))
214     {
215       SCM tag = scm_car (value_);
216       if (tag == ly_symbol2scm ("dictionary"))
217         write_dict (file, scm_cdr (value_));
218       else if (tag == ly_symbol2scm ("stream"))
219         write_stream (file, scm_cdr (value_));
220       else
221         assert (false);
222     }
223   else
224     {
225       String str = to_string ();
226       fwrite (str.get_bytes (), str.length (), sizeof (Byte), file);
227
228       fputc (dump_definition ? '\n' : ' ', file);
229       return;
230     }
231 }
232
233 bool
234 Pdf_object::is_stream () const
235 {
236   return scm_is_pair (value_) && scm_car (value_) == ly_symbol2scm ("stream");
237 }
238
239 /****************************************************************/
240
241
242 IMPLEMENT_SMOBS (Pdf_file);
243 IMPLEMENT_DEFAULT_EQUAL_P (Pdf_file);
244 IMPLEMENT_TYPE_P (Pdf_file, "pdf-file?");
245
246
247 Pdf_file::Pdf_file (String name)
248 {
249   char const *cp = name.to_str0 ();
250   root_object_ = NULL;
251   file_ = fopen (cp, "w");
252   if (!file_)
253     error (_f ("can't open file: `%s'", cp));
254   write_header ();
255   smobify_self ();
256 }
257
258 Pdf_file::~Pdf_file ()
259 {
260 }
261
262 void
263 Pdf_file::write_header ()
264 {
265   fputs ("%PDF-1.3\n", file_);
266 }
267
268 void
269 Pdf_file::make_indirect (Pdf_object *obj)
270 {
271   assert (!obj->is_indirect ());
272
273   /*
274     Skip 0 , the null object.
275   */
276   obj->object_number_ = indirect_objects_.size () + 1;
277   indirect_objects_.push (obj);
278 }
279
280 void
281 Pdf_file::write_object (Pdf_object *obj)
282 {
283   assert (!obj->written_);
284   if (obj->is_stream () && !obj->is_indirect ())
285     make_indirect (obj);
286
287   if (obj->is_indirect ())
288     {
289       obj->byte_count_ = ftell (file_);
290       fprintf (file_, "%d obj\n", obj->object_number_);
291     }
292
293   obj->write_to_file (file_, true);
294   obj->written_ = true;
295
296   if (obj->is_indirect ())
297     fprintf (file_, " \nendobj\n");
298 }
299
300 void
301 Pdf_file::terminate ()
302 {
303   for (int i = 0; i < indirect_objects_.size (); i++)
304     {
305       if (!indirect_objects_[i]->written_)
306         write_object (indirect_objects_[i]);
307     }
308
309   write_trailer ();
310   fclose (file_);
311   file_ = NULL;
312 }
313
314 void
315 Pdf_file::set_root_document (Pdf_object*obj)
316 {
317   if (root_object_)
318     error ("Can have only one root object");
319
320   root_object_ = obj;
321   if (!obj->is_indirect ())
322     make_indirect (obj);
323 }
324
325 void
326 Pdf_file::write_trailer ()
327 {
328   long xref_offset = ftell (file_);
329   fprintf (file_, "xref\n%d %d\n", 0, indirect_objects_.size () + 1);
330
331   char const *xref_entry = "%010d %05d %c \n";
332   fprintf (file_, xref_entry, 0, 65535, 'f');
333   for (int i = 0; i < indirect_objects_.size (); i++)
334     fprintf (file_, xref_entry, indirect_objects_[i]->byte_count_, 0, 'n');
335
336   fprintf (file_, "trailer\n<< /Size %d /Root %d 0 R >>",
337            indirect_objects_.size () + 1,
338            (root_object_) ? root_object_->object_number_ : 0);
339   fprintf (file_, "\nstartxref\n%d\n", xref_offset);
340   fputs ("%%EOF", file_);
341 }
342
343 SCM
344 Pdf_file::mark_smob (SCM f)
345 {
346   Pdf_file *pfile = (Pdf_file*) SCM_CELL_WORD_1 (f);
347   for (int i = 0; i < pfile->indirect_objects_.size (); i++)
348     scm_gc_mark (pfile->indirect_objects_[i]->self_scm ());
349   return SCM_BOOL_F;
350 }
351
352 int
353 Pdf_file::print_smob (SCM pdf, SCM port, scm_print_state*)
354 {
355   scm_puts ("#<PDF file>", port);
356   return 1;
357 }