Code

Cleaned up more of the gboolean to bool janitorial task...great!
[inkscape.git] / src / extension / internal / pdf.cpp
1 #define __SP_PDF_C__\r
2 \r
3 /** \file\r
4  * PDF printing.\r
5  */\r
6 /*\r
7  * Authors:\r
8  *   Lauris Kaplinski <lauris@kaplinski.com>\r
9  *   bulia byak <buliabyak@users.sf.net>\r
10  *   Ulf Erikson <ulferikson@users.sf.net>\r
11  *\r
12  * Basic printing code, EXCEPT image and\r
13  * ascii85 filter is in public domain\r
14  *\r
15  * Image printing and Ascii85 filter:\r
16  *\r
17  * Copyright (C) 1995 Spencer Kimball and Peter Mattis\r
18  * Copyright (C) 1997-98 Peter Kirchgessner\r
19  * George White <aa056@chebucto.ns.ca>\r
20  * Austin Donnelly <austin@gimp.org>\r
21  *\r
22  * Licensed under GNU GPL\r
23  */\r
24 \r
25 /* Plain Print */\r
26 \r
27 #ifdef HAVE_CONFIG_H\r
28 # include "config.h"\r
29 #endif\r
30 \r
31 #include <signal.h>\r
32 #include <errno.h>\r
33 \r
34 #include <glib/gmem.h>\r
35 #include <libnr/n-art-bpath.h>\r
36 #include <libnr/nr-point-matrix-ops.h>\r
37 \r
38 #include <gtk/gtkstock.h>\r
39 #include <gtk/gtkvbox.h>\r
40 #include <gtk/gtkframe.h>\r
41 #include <gtk/gtkradiobutton.h>\r
42 #include <gtk/gtkcombo.h>\r
43 #include <gtk/gtklabel.h>\r
44 #include <gtk/gtkentry.h>\r
45 #include <gtk/gtktooltips.h>\r
46 \r
47 #include <glibmm/i18n.h>\r
48 #include "display/nr-arena-item.h"\r
49 #include "display/canvas-bpath.h"\r
50 #include "sp-item.h"\r
51 #include "style.h"\r
52 #include "sp-linear-gradient.h"\r
53 #include "sp-radial-gradient.h"\r
54 \r
55 #include "libnrtype/font-instance.h"\r
56 #include "libnrtype/font-style-to-pos.h"\r
57 \r
58 #include <unit-constants.h>\r
59 \r
60 #include "pdf.h"\r
61 #include "extension/system.h"\r
62 #include "extension/print.h"\r
63 \r
64 #include "io/sys.h"\r
65 \r
66 #include "pdf-mini.h"\r
67 \r
68 namespace Inkscape {\r
69 namespace Extension {\r
70 namespace Internal {\r
71 \r
72 PrintPDF::PrintPDF() :\r
73     _stream(NULL),\r
74     _dpi(72),\r
75     _bitmap(false)\r
76 {\r
77 }\r
78 \r
79 PrintPDF::~PrintPDF(void)\r
80 {\r
81     /* fixme: should really use pclose for popen'd streams */\r
82     if (_stream) fclose(_stream);\r
83 \r
84     /* restore default signal handling for SIGPIPE */\r
85 #if !defined(_WIN32) && !defined(__WIN32__)\r
86     (void) signal(SIGPIPE, SIG_DFL);\r
87 #endif\r
88 \r
89     return;\r
90 }\r
91 \r
92 unsigned int\r
93 PrintPDF::setup(Inkscape::Extension::Print * mod)\r
94 {\r
95     static gchar const *const pdr[] = {"72", "75", "100", "144", "150", "200", "300", "360", "600", "1200", "2400", NULL};\r
96 \r
97 #ifdef TED\r
98     Inkscape::XML::Node *repr = ((SPModule *) mod)->repr;\r
99 #endif\r
100 \r
101     unsigned int ret = FALSE;\r
102 \r
103     /* Create dialog */\r
104     GtkTooltips *tt = gtk_tooltips_new();\r
105     g_object_ref((GObject *) tt);\r
106     gtk_object_sink((GtkObject *) tt);\r
107 \r
108     GtkWidget *dlg = gtk_dialog_new_with_buttons(_("Print Destination"),\r
109 //            SP_DT_WIDGET(SP_ACTIVE_DESKTOP)->window,\r
110             NULL,\r
111             (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT),\r
112             GTK_STOCK_CANCEL,\r
113             GTK_RESPONSE_CANCEL,\r
114             GTK_STOCK_PRINT,\r
115             GTK_RESPONSE_OK,\r
116             NULL);\r
117 \r
118     gtk_dialog_set_default_response(GTK_DIALOG(dlg), GTK_RESPONSE_OK);\r
119 \r
120     GtkWidget *vbox = GTK_DIALOG(dlg)->vbox;\r
121     gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);\r
122     /* Print properties frame */\r
123     GtkWidget *f = gtk_frame_new(_("Print properties"));\r
124     gtk_box_pack_start(GTK_BOX(vbox), f, FALSE, FALSE, 4);\r
125     GtkWidget *vb = gtk_vbox_new(FALSE, 4);\r
126     gtk_container_add(GTK_CONTAINER(f), vb);\r
127     gtk_container_set_border_width(GTK_CONTAINER(vb), 4);\r
128     /* Print type */\r
129     bool const p2bm = mod->get_param_bool("bitmap");\r
130     GtkWidget *rb = gtk_radio_button_new_with_label(NULL, _("Print using PDF operators"));\r
131     gtk_tooltips_set_tip((GtkTooltips *) tt, rb,\r
132                          _("Use PDF vector operators. The resulting image is usually smaller "\r
133                            "in file size and can be arbitrarily scaled, but "\r
134                            "patterns will be lost."), NULL);\r
135     if (!p2bm) gtk_toggle_button_set_active((GtkToggleButton *) rb, TRUE);\r
136     gtk_box_pack_start(GTK_BOX(vb), rb, FALSE, FALSE, 0);\r
137     rb = gtk_radio_button_new_with_label(gtk_radio_button_get_group((GtkRadioButton *) rb), _("Print as bitmap"));\r
138     gtk_tooltips_set_tip((GtkTooltips *) tt, rb,\r
139                          _("Print everything as bitmap. The resulting image is usually larger "\r
140                            "in file size and cannot be arbitrarily scaled without quality loss, "\r
141                            "but all objects will be rendered exactly as displayed."), NULL);\r
142     if (p2bm) gtk_toggle_button_set_active((GtkToggleButton *) rb, TRUE);\r
143     gtk_box_pack_start(GTK_BOX(vb), rb, FALSE, FALSE, 0);\r
144     /* Resolution */\r
145     GtkWidget *hb = gtk_hbox_new(FALSE, 4);\r
146     gtk_box_pack_start(GTK_BOX(vb), hb, FALSE, FALSE, 0);\r
147     GtkWidget *combo = gtk_combo_new();\r
148     gtk_combo_set_value_in_list(GTK_COMBO(combo), FALSE, FALSE);\r
149     gtk_combo_set_use_arrows(GTK_COMBO(combo), TRUE);\r
150     gtk_combo_set_use_arrows_always(GTK_COMBO(combo), TRUE);\r
151     gtk_widget_set_size_request(combo, 64, -1);\r
152     gtk_tooltips_set_tip((GtkTooltips *) tt, GTK_COMBO(combo)->entry,\r
153                          _("Preferred resolution (dots per inch) of bitmap"), NULL);\r
154     /* Setup strings */\r
155     GList *sl = NULL;\r
156     for (unsigned i = 0; pdr[i] != NULL; i++) {\r
157         sl = g_list_prepend(sl, (gpointer) pdr[i]);\r
158     }\r
159     sl = g_list_reverse(sl);\r
160     gtk_combo_set_popdown_strings(GTK_COMBO(combo), sl);\r
161     g_list_free(sl);\r
162     if (1) {\r
163         gchar const *val = mod->get_param_string("resolution");\r
164         gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), val);\r
165     }\r
166     gtk_box_pack_end(GTK_BOX(hb), combo, FALSE, FALSE, 0);\r
167     GtkWidget *l = gtk_label_new(_("Resolution:"));\r
168     gtk_box_pack_end(GTK_BOX(hb), l, FALSE, FALSE, 0);\r
169 \r
170     /* Print destination frame */\r
171     f = gtk_frame_new(_("Print destination"));\r
172     gtk_box_pack_start(GTK_BOX(vbox), f, FALSE, FALSE, 4);\r
173     vb = gtk_vbox_new(FALSE, 4);\r
174     gtk_container_add(GTK_CONTAINER(f), vb);\r
175     gtk_container_set_border_width(GTK_CONTAINER(vb), 4);\r
176 \r
177     l = gtk_label_new(_("Printer name (as given by lpstat -p);\n"\r
178                         "leave empty to use the system default printer.\n"\r
179                         "Use '> filename' to print to file.\n"\r
180                         "Use '| prog arg...' to pipe to a program."));\r
181     gtk_box_pack_start(GTK_BOX(vb), l, FALSE, FALSE, 0);\r
182 \r
183     GtkWidget *e = gtk_entry_new();\r
184     if (1) {\r
185         gchar const *val = mod->get_param_string("destination");\r
186         gtk_entry_set_text(GTK_ENTRY(e), ( val != NULL\r
187                                            ? val\r
188                                            : "" ));\r
189     }\r
190     gtk_box_pack_start(GTK_BOX(vb), e, FALSE, FALSE, 0);\r
191 \r
192     // pressing enter in the destination field is the same as clicking Print:\r
193     gtk_entry_set_activates_default(GTK_ENTRY(e), TRUE);\r
194 \r
195     gtk_widget_show_all(vbox);\r
196 \r
197     int const response = gtk_dialog_run(GTK_DIALOG(dlg));\r
198 \r
199     g_object_unref((GObject *) tt);\r
200 \r
201     if (response == GTK_RESPONSE_OK) {\r
202         gchar const *fn;\r
203         char const *sstr;\r
204 \r
205         _bitmap = gtk_toggle_button_get_active((GtkToggleButton *) rb);\r
206         sstr = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(combo)->entry));\r
207         _dpi = (unsigned int) MAX((int)(atof(sstr)), 1);\r
208         /* Arrgh, have to do something */\r
209         fn = gtk_entry_get_text(GTK_ENTRY(e));\r
210         /* skip leading whitespace, bug #1068483 */\r
211         while (fn && *fn==' ') { fn++; }\r
212         /* g_print("Printing to %s\n", fn); */\r
213 \r
214         mod->set_param_bool("bitmap", _bitmap);\r
215         mod->set_param_string("resolution", (gchar *)sstr);\r
216         mod->set_param_string("destination", (gchar *)fn);\r
217         ret = TRUE;\r
218     }\r
219 \r
220     gtk_widget_destroy(dlg);\r
221 \r
222     return ret;\r
223 }\r
224 \r
225 unsigned int\r
226 PrintPDF::begin(Inkscape::Extension::Print *mod, SPDocument *doc)\r
227 {\r
228     bool epsexport = false;\r
229 \r
230     _latin1_encoded_fonts.clear();\r
231     _newlatin1font_proc_defined = false;\r
232 \r
233     FILE *osf = NULL;\r
234     FILE *osp = NULL;\r
235 \r
236     _pushed_alphas.clear();\r
237     _pushed_alphas.push_back(1.0);\r
238 \r
239     gsize bytesRead = 0;\r
240     gsize bytesWritten = 0;\r
241     GError *error = NULL;\r
242     gchar const *utf8_fn = mod->get_param_string("destination");\r
243     gchar *local_fn = g_filename_from_utf8( utf8_fn,\r
244                                             -1,  &bytesRead,  &bytesWritten, &error);\r
245     gchar const *fn = local_fn;\r
246 \r
247     /* TODO: Replace the below fprintf's with something that does the right thing whether in\r
248      * gui or batch mode (e.g. --print=blah).  Consider throwing an exception: currently one of\r
249      * the callers (sp_print_document_to_file, "ret = mod->begin(doc)") wrongly ignores the\r
250      * return code.\r
251      */\r
252     if (fn != NULL) {\r
253         if (*fn == '|') {\r
254             fn += 1;\r
255             while (isspace(*fn)) fn += 1;\r
256 #ifndef WIN32\r
257             osp = popen(fn, "wb");\r
258 #else\r
259             osp = _popen(fn, "wb");\r
260 #endif\r
261             if (!osp) {\r
262                 fprintf(stderr, "inkscape: popen(%s): %s\n",\r
263                         fn, strerror(errno));\r
264                 return 0;\r
265             }\r
266             _stream = osp;\r
267         } else if (*fn == '>') {\r
268             fn += 1;\r
269             epsexport = g_str_has_suffix(fn,".eps");\r
270             while (isspace(*fn)) fn += 1;\r
271             Inkscape::IO::dump_fopen_call(fn, "K");\r
272             osf = Inkscape::IO::fopen_utf8name(fn, "wb+");\r
273             if (!osf) {\r
274                 fprintf(stderr, "inkscape: fopen(%s): %s\n",\r
275                         fn, strerror(errno));\r
276                 return 0;\r
277             }\r
278             _stream = osf;\r
279         } else {\r
280             /* put cwd stuff in here */\r
281             gchar *qn = ( *fn\r
282                           ? g_strdup_printf("lpr -P %s", fn)  /* FIXME: quote fn */\r
283                           : g_strdup("lpr") );\r
284 #ifndef WIN32\r
285             osp = popen(qn, "wb");\r
286 #else\r
287             osp = _popen(qn, "wb");\r
288 #endif\r
289             if (!osp) {\r
290                 fprintf(stderr, "inkscape: popen(%s): %s\n",\r
291                         qn, strerror(errno));\r
292                 return 0;\r
293             }\r
294             g_free(qn);\r
295             _stream = osp;\r
296         }\r
297     }\r
298 \r
299     g_free(local_fn);\r
300 \r
301     if (_stream) {\r
302         /* fixme: this is kinda icky */\r
303 #if !defined(_WIN32) && !defined(__WIN32__)\r
304         (void) signal(SIGPIPE, SIG_IGN);\r
305 #endif\r
306     }\r
307 \r
308     pdf_file = new PdfFile(_stream);\r
309     doc_info = pdf_file->begin_document(1.4);\r
310     *doc_info << "  /Title(" << doc->name << ")\n";\r
311     *doc_info << "  /Author(" << g_get_real_name()  << ")\n";\r
312 //    *doc_info << "  /Subject(" << "?" << ")\n";\r
313 //    *doc_info << "  /Keywords(" << "?" << ")\n";\r
314     *doc_info << "  /Creator(" << "www.inkscape.org" << ")\n";\r
315     *doc_info << "  /Producer(" << "Inkscape " << PACKAGE_STRING << ")\n";\r
316         //the date should be in ISO/IEC 8824\r
317         GDate date;\r
318         GTimeVal ltime;\r
319         glong time_hh, time_mm, time_ss;\r
320 #if GLIB_CHECK_VERSION(2,9,0)\r
321         g_date_set_time_t (&date, time (NULL));\r
322 #else\r
323         g_date_set_time(&date, time (NULL));\r
324 #endif\r
325         gchar date_str[100], time_str[100];\r
326         g_date_strftime(date_str, 99, "%Y%m%d", &date);\r
327         g_get_current_time(&ltime);\r
328         time_hh=(ltime.tv_sec/3600)%24;\r
329         time_mm=(ltime.tv_sec/60)%60;\r
330         time_ss=(ltime.tv_sec)%60;\r
331         g_snprintf(time_str, 99, "%02ld%02ld%02ld", time_hh, time_mm, time_ss); \r
332         *doc_info << "  /CreationDate(D:" << date_str << time_str << "Z)\n";\r
333 //      *doc_info << "  /CreationDate(D:" << date_str << time_str << "OHH'mm')\n";\r
334 \r
335     /* flush this to test output stream as early as possible */\r
336     if (fflush(_stream)) {\r
337         /*g_print("caught error in sp_module_print_plain_begin\n");*/\r
338         if (ferror(_stream)) {\r
339             g_print("Error %d on output stream: %s\n", errno,\r
340                     g_strerror(errno));\r
341         }\r
342         g_print("Printing failed\n");\r
343         /* fixme: should use pclose() for pipes */\r
344         fclose(_stream);\r
345         _stream = NULL;\r
346         fflush(stdout);\r
347         return 0;\r
348     }\r
349 \r
350     // width and height in pt\r
351     _width = sp_document_width(doc) * PT_PER_PX;\r
352     _height = sp_document_height(doc) * PT_PER_PX;\r
353 \r
354     NRRect d;\r
355     bool   pageBoundingBox;\r
356     pageBoundingBox = mod->get_param_bool("pageBoundingBox");\r
357     // printf("Page Bounding Box: %s\n", pageBoundingBox ? "TRUE" : "FALSE");\r
358     if (pageBoundingBox) {\r
359         d.x0 = d.y0 = 0;\r
360         d.x1 = _width;\r
361         d.y1 = _height;\r
362     } else {\r
363         SPItem* doc_item = SP_ITEM(sp_document_root(doc));\r
364         sp_item_invoke_bbox(doc_item, &d, sp_item_i2r_affine(doc_item), TRUE);\r
365         // convert from px to pt\r
366         d.x0 *= PT_PER_PX;\r
367         d.x1 *= PT_PER_PX;\r
368         d.y0 *= PT_PER_PX;\r
369         d.y1 *= PT_PER_PX;\r
370     }\r
371 \r
372     page_stream = pdf_file->begin_page( d.x0, d.y0, d.x1, d.y1 );\r
373 \r
374     if (!_bitmap) {\r
375         Inkscape::SVGOStringStream os;\r
376         os.setf(std::ios::fixed);\r
377         os << PT_PER_PX << " 0 0 "\r
378            << -PT_PER_PX << " 0 " << (int) ceil(_height)\r
379            << " cm\n";\r
380         // from now on we can output px, but they will be treated as pt\r
381         pdf_file->puts(os);\r
382     }\r
383     \r
384     return 1;\r
385 }\r
386 \r
387 unsigned int\r
388 PrintPDF::finish(Inkscape::Extension::Print *mod)\r
389 {\r
390     if (!_stream) return 0;\r
391 \r
392     if (_bitmap) {\r
393         double const dots_per_pt = _dpi / PT_PER_IN;\r
394 \r
395         double const x0 = 0.0;\r
396         double const y0 = 0.0;\r
397         double const x1 = x0 + _width;\r
398         double const y1 = y0 + _height;\r
399 \r
400         /* Bitmap width/height in bitmap dots. */\r
401         int const width = (int) (_width * dots_per_pt + 0.5);\r
402         int const height = (int) (_height * dots_per_pt + 0.5);\r
403 \r
404         NRMatrix affine;\r
405         affine.c[0] = width / ((x1 - x0) * PX_PER_PT);\r
406         affine.c[1] = 0.0;\r
407         affine.c[2] = 0.0;\r
408         affine.c[3] = height / ((y1 - y0) * PX_PER_PT);\r
409         affine.c[4] = -affine.c[0] * x0;\r
410         affine.c[5] = -affine.c[3] * y0;\r
411 \r
412         nr_arena_item_set_transform(mod->root, &affine);\r
413 \r
414         guchar *const px = g_new(guchar, 4 * width * 64);\r
415 \r
416         for (int y = 0; y < height; y += 64) {\r
417             /* Set area of interest. */\r
418             NRRectL bbox;\r
419             bbox.x0 = 0;\r
420             bbox.y0 = y;\r
421             bbox.x1 = width;\r
422             bbox.y1 = MIN(height, y + 64);\r
423 \r
424             /* Update to renderable state. */\r
425             NRGC gc(NULL);\r
426             nr_matrix_set_identity(&gc.transform);\r
427             nr_arena_item_invoke_update(mod->root, &bbox, &gc, NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_NONE);\r
428             /* Render */\r
429             /* This should take guchar* instead of unsigned char*) */\r
430             NRPixBlock pb;\r
431             nr_pixblock_setup_extern(&pb, NR_PIXBLOCK_MODE_R8G8B8A8N,\r
432                                      bbox.x0, bbox.y0, bbox.x1, bbox.y1,\r
433                                      (guchar*)px, 4 * width, FALSE, FALSE);\r
434             memset(px, 0xff, 4 * width * 64);\r
435             nr_arena_item_invoke_render(mod->root, &bbox, &pb, 0);\r
436             /* Blitter goes here */\r
437             NRMatrix imgt;\r
438             imgt.c[0] = (bbox.x1 - bbox.x0) / dots_per_pt;\r
439             imgt.c[1] = 0.0;\r
440             imgt.c[2] = 0.0;\r
441             imgt.c[3] = (bbox.y1 - bbox.y0) / dots_per_pt;\r
442             imgt.c[4] = 0.0;\r
443             imgt.c[5] = _height - y / dots_per_pt - (bbox.y1 - bbox.y0) / dots_per_pt;\r
444 \r
445             print_image(_stream, px, bbox.x1 - bbox.x0, bbox.y1 - bbox.y0, 4 * width, &imgt);\r
446         }\r
447 \r
448         g_free(px);\r
449     }\r
450 \r
451     pdf_file->end_page(page_stream);\r
452     pdf_file->end_document(doc_info);\r
453 \r
454     delete pdf_file;\r
455 \r
456     /* Flush stream to be sure. */\r
457     (void) fflush(_stream);\r
458 \r
459     /* fixme: should really use pclose for popen'd streams */\r
460     fclose(_stream);\r
461     _stream = 0;\r
462     _latin1_encoded_fonts.clear();\r
463 \r
464     return 1;\r
465 }\r
466 \r
467 unsigned int\r
468 PrintPDF::bind(Inkscape::Extension::Print *mod, NRMatrix const *transform, float opacity)\r
469 {\r
470     if (!_stream) return 0;  // XXX: fixme, returning -1 as unsigned.\r
471     if (_bitmap) return 0;\r
472 \r
473     Inkscape::SVGOStringStream os;\r
474     os.setf(std::ios::fixed);\r
475     \r
476     os << "q\n";\r
477     os << transform->c[0] << " "\r
478        << transform->c[1] << " "\r
479        << transform->c[2] << " "\r
480        << transform->c[3] << " "\r
481        << transform->c[4] << " "\r
482        << transform->c[5] << " cm\n";\r
483 \r
484     float alpha = opacity * _pushed_alphas.back();\r
485     _pushed_alphas.push_back(alpha);\r
486 \r
487     pdf_file->puts(os);\r
488     return 1;\r
489 }\r
490 \r
491 unsigned int\r
492 PrintPDF::release(Inkscape::Extension::Print *mod)\r
493 {\r
494     if (!_stream) return 0; // XXX: fixme, returning -1 as unsigned.\r
495     if (_bitmap) return 0;\r
496 \r
497     _pushed_alphas.pop_back();\r
498     g_assert( _pushed_alphas.size() > 0 );\r
499 \r
500     pdf_file->puts("Q\n");\r
501 \r
502     return 1;\r
503 }\r
504 \r
505 unsigned int\r
506 PrintPDF::comment(Inkscape::Extension::Print *mod, char const *comment)\r
507 {\r
508     if (!_stream) return 0; // XXX: fixme, returning -1 as unsigned.\r
509     if (_bitmap) return 0;\r
510  \r
511     return 1;\r
512 }\r
513 \r
514 void\r
515 PrintPDF::print_fill_alpha(SVGOStringStream &os, SPStyle const *const style, NRRect const *pbox)\r
516 {\r
517     g_return_if_fail( style->fill.type == SP_PAINT_TYPE_COLOR\r
518                       || ( style->fill.type == SP_PAINT_TYPE_PAINTSERVER\r
519                            && SP_IS_GRADIENT(SP_STYLE_FILL_SERVER(style)) ) );\r
520     \r
521     if (style->fill.type == SP_PAINT_TYPE_COLOR) {\r
522         float alpha = 1.0;\r
523         alpha *= SP_SCALE24_TO_FLOAT(style->fill_opacity.value);\r
524         alpha *= _pushed_alphas.back();\r
525 \r
526         if (alpha != 1.0) {\r
527             PdfObject *pdf_alpha = pdf_file->begin_resource(pdf_extgstate);\r
528             *pdf_alpha << "<< /Type /ExtGState\n";\r
529             *pdf_alpha << "   /ca " << alpha << "\n";\r
530             *pdf_alpha << "   /AIS false\n";\r
531             *pdf_alpha << ">>\n";\r
532             \r
533             os << pdf_alpha->get_name()\r
534                << " gs\n";\r
535 \r
536             pdf_file->end_resource(pdf_alpha);\r
537         }\r
538     } else {\r
539         g_assert( style->fill.type == SP_PAINT_TYPE_PAINTSERVER\r
540                   && SP_IS_GRADIENT(SP_STYLE_FILL_SERVER(style)) );\r
541         \r
542         if (SP_IS_LINEARGRADIENT (SP_STYLE_FILL_SERVER (style))) {\r
543             \r
544             SPLinearGradient *lg=SP_LINEARGRADIENT(SP_STYLE_FILL_SERVER (style));\r
545             sp_gradient_ensure_vector(SP_GRADIENT(lg)); // when exporting from commandline, vector is not built\r
546 \r
547             NR::Point p1 (lg->x1.computed, lg->y1.computed);\r
548             NR::Point p2 (lg->x2.computed, lg->y2.computed);\r
549             if (pbox && SP_GRADIENT(lg)->units == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX) {\r
550                 // convert to userspace\r
551                 NR::Matrix bbox2user(pbox->x1 - pbox->x0, 0, 0, pbox->y1 - pbox->y0, pbox->x0, pbox->y0);\r
552                 p1 *= bbox2user;\r
553                 p2 *= bbox2user;\r
554             }\r
555             \r
556             double alpha = 1.0;\r
557             for (gint i = 0; unsigned(i) < lg->vector.stops.size(); i++) {\r
558                 alpha *= lg->vector.stops[i].opacity;\r
559             }\r
560             \r
561             if (alpha != 1.0 || _pushed_alphas.back() != 1.0) {\r
562                 PdfObject *pdf_gstate = pdf_file->begin_resource(pdf_extgstate);\r
563                 *pdf_gstate << "<< /Type /ExtGState\n";\r
564                 \r
565                 if (_pushed_alphas.back() != 1.0) {\r
566                     *pdf_gstate << "   /ca " << _pushed_alphas.back() << "\n";\r
567                     *pdf_gstate << "   /AIS false\n";\r
568                 }\r
569                 \r
570                 if (alpha != 1.0) {\r
571                     PdfObject *pdf_alpha = pdf_file->begin_resource(pdf_shading);\r
572                     PdfObject *pdf_smask = pdf_file->begin_resource(pdf_none);\r
573                     PdfObject *pdf_xobj = pdf_file->begin_resource(pdf_none);\r
574 \r
575 \r
576                     *pdf_gstate << "   /SMask " << pdf_smask->get_id() << " 0 R\n";\r
577 \r
578             \r
579                     *pdf_alpha << "<<\n/ShadingType 2\n/ColorSpace /DeviceGray\n";\r
580                     *pdf_alpha << "/Coords [" << p1[NR::X] << " " << p1[NR::Y] << " " << p2[NR::X] << " " << p2[NR::Y] <<"]\n";\r
581                     *pdf_alpha << "/Extend [true true]\n";\r
582                     *pdf_alpha << "/Domain [0 1]\n";\r
583                     *pdf_alpha << "/Function <<\n/FunctionType 3\n/Functions\n[\n";\r
584 \r
585                     for (gint i = 0; unsigned(i) < lg->vector.stops.size() - 1; i++) {\r
586                         *pdf_alpha << "<<\n/FunctionType 2\n/Domain [0 1]\n";\r
587                         *pdf_alpha << "/C0 [" << lg->vector.stops[i].opacity << "]\n";\r
588                         *pdf_alpha << "/C1 [" << lg->vector.stops[i+1].opacity << "]\n";\r
589                         *pdf_alpha << "/N 1\n>>\n";\r
590                     }\r
591                     *pdf_alpha << "]\n/Domain [0 1]\n";\r
592                     *pdf_alpha << "/Bounds [ ";\r
593                     for (gint i=0;unsigned(i)<lg->vector.stops.size()-2;i++) {\r
594                         *pdf_alpha << lg->vector.stops[i+1].offset <<" ";\r
595                     }\r
596                     *pdf_alpha << "]\n";\r
597                     *pdf_alpha << "/Encode [ ";\r
598                     for (gint i=0;unsigned(i)<lg->vector.stops.size()-1;i++) {\r
599                         *pdf_alpha << "0 1 ";\r
600                     }\r
601                     *pdf_alpha << "]\n";\r
602                     *pdf_alpha << ">>\n>>\n";\r
603 \r
604                     \r
605                     *pdf_smask << "<< /Type /Mask\n";\r
606                     *pdf_smask << "   /S /Alpha\n";\r
607                     *pdf_smask << "   /BC [0.0]\n";\r
608                     *pdf_smask << "   /G " << pdf_xobj->get_id() << " 0 R\n";\r
609                     *pdf_smask << ">>\n";\r
610 \r
611                     \r
612                     *pdf_xobj << "<< /Type /XObject\n";\r
613                     *pdf_xobj << "   /Subtype /Form\n";\r
614                     *pdf_xobj << "   /FormType 1\n";\r
615                     *pdf_xobj << "   /BBox ["\r
616                               << pbox->x0 << " "\r
617                               << pbox->y0 << " "\r
618                               << pbox->x1 << " "\r
619                               << pbox->y1 << "]\n";\r
620                     *pdf_xobj << "   /Group\n";\r
621                     *pdf_xobj << "   << /Type /Group\n";\r
622                     *pdf_xobj << "      /S /Transparency\n";\r
623                     *pdf_xobj << "      /CS /DeviceGray \n";\r
624                     *pdf_xobj << "   >>\n";\r
625                     *pdf_xobj << "   /Resources\n";\r
626                     *pdf_xobj << "   <<\n";\r
627                     *pdf_xobj << "      /ProcSet [/PDF /Text /ImageB /ImageC /ImageI]\n";\r
628                     *pdf_xobj << "      /Shading << "\r
629                               << pdf_alpha->get_name() << " "\r
630                               << pdf_alpha->get_id() << " 0 R >>\n";\r
631                     *pdf_xobj << "   >>\n";\r
632                     \r
633                     Inkscape::SVGOStringStream os_tmp;\r
634                     os_tmp.setf(std::ios::fixed);\r
635                     \r
636                     os_tmp << "q\n"\r
637                            << pbox->x0 << " " << pbox->y0 << " m\n"\r
638                            << pbox->x1 << " " << pbox->y0 << " l\n"\r
639                            << pbox->x1 << " " << pbox->y1 << " l\n"\r
640                            << pbox->x0 << " " << pbox->y1 << " l\n"\r
641                            << pbox->x0 << " " << pbox->y0 << " l\n"\r
642                            << "h\n"\r
643                            << "W* n\n";\r
644                     \r
645                     SPGradient const *g = SP_GRADIENT(SP_STYLE_FILL_SERVER(style));\r
646                     if (g->gradientTransform_set) {\r
647                         os_tmp << g->gradientTransform[0] << " "\r
648                                << g->gradientTransform[1] << " "\r
649                                << g->gradientTransform[2] << " "\r
650                                << g->gradientTransform[3] << " "\r
651                                << g->gradientTransform[4] << " "\r
652                                << g->gradientTransform[5] << " cm\n"; \r
653                     }\r
654                     \r
655                     os_tmp << pdf_alpha->get_name() << " sh\n";\r
656                     os_tmp << "Q\n";\r
657                     *pdf_xobj << "   /Length " << os_tmp.str().length() << "\n";\r
658                     *pdf_xobj << ">>\n";\r
659                     *pdf_xobj << "stream\n";\r
660                     *pdf_xobj << os_tmp.str().c_str();\r
661                     *pdf_xobj << "endstream\n";\r
662 \r
663 \r
664                     pdf_file->end_resource(pdf_alpha);\r
665                     pdf_file->end_resource(pdf_smask);\r
666                     pdf_file->end_resource(pdf_xobj);\r
667                 }\r
668                 \r
669                 *pdf_gstate << ">>\n";\r
670 \r
671                 os << pdf_gstate->get_name() << " gs\n";\r
672                     \r
673                 pdf_file->end_resource(pdf_gstate);\r
674             }\r
675         } else if (SP_IS_RADIALGRADIENT (SP_STYLE_FILL_SERVER (style))) {\r
676 \r
677             SPRadialGradient *rg=SP_RADIALGRADIENT(SP_STYLE_FILL_SERVER (style));\r
678             sp_gradient_ensure_vector(SP_GRADIENT(rg)); // when exporting from commandline, vector is not built\r
679 \r
680             NR::Point c (rg->cx.computed, rg->cy.computed);\r
681             NR::Point f (rg->fx.computed, rg->fy.computed);\r
682             double r = rg->r.computed;\r
683 \r
684             NR::Coord const df = hypot(f[NR::X] - c[NR::X], f[NR::Y] - c[NR::Y]);\r
685             if (df >= r) {\r
686                 f[NR::X] = c[NR::X] + (f[NR::X] - c[NR::X] ) * r / (float) df;\r
687                 f[NR::Y] = c[NR::Y] + (f[NR::Y] - c[NR::Y] ) * r / (float) df;\r
688             }\r
689 \r
690             if (pbox && SP_GRADIENT(rg)->units == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX) {\r
691                 // convert to userspace\r
692                 NR::Matrix bbox2user(pbox->x1 - pbox->x0, 0, 0, pbox->y1 - pbox->y0, pbox->x0, pbox->y0);\r
693                 c *= bbox2user;\r
694                 f *= bbox2user;\r
695                 r *= bbox2user.expansion();\r
696             }\r
697             \r
698             double alpha = 1.0;\r
699             for (gint i = 0; unsigned(i) < rg->vector.stops.size(); i++) {\r
700                 alpha *= rg->vector.stops[i].opacity;\r
701             }\r
702 \r
703             if (alpha != 1.0 || _pushed_alphas.back() != 1.0) {\r
704                 PdfObject *pdf_gstate = pdf_file->begin_resource(pdf_extgstate);\r
705                 *pdf_gstate << "<< /Type /ExtGState\n";\r
706                 \r
707                 if (_pushed_alphas.back() != 1.0) {\r
708                     *pdf_gstate << "   /ca " << _pushed_alphas.back() << "\n";\r
709                     *pdf_gstate << "   /AIS false\n";\r
710                 }\r
711                 \r
712                 if (alpha != 1.0) {\r
713                     PdfObject *pdf_alpha = pdf_file->begin_resource(pdf_shading);\r
714                     PdfObject *pdf_smask = pdf_file->begin_resource(pdf_none);\r
715                     PdfObject *pdf_xobj = pdf_file->begin_resource(pdf_none);\r
716 \r
717 \r
718                     *pdf_gstate << "   /SMask " << pdf_smask->get_id() << " 0 R\n";\r
719 \r
720 \r
721                     *pdf_alpha << "<<\n/ShadingType 3\n/ColorSpace /DeviceGray\n";\r
722                     *pdf_alpha << "/Coords ["<< f[NR::X] <<" "<< f[NR::Y] <<" 0 "<< c[NR::X] <<" "<< c[NR::Y] <<" "<< r <<"]\n";\r
723                     *pdf_alpha << "/Extend [true true]\n";\r
724                     *pdf_alpha << "/Domain [0 1]\n";\r
725                     *pdf_alpha << "/Function <<\n/FunctionType 3\n/Functions\n[\n";\r
726 \r
727                     for (gint i = 0; unsigned(i) < rg->vector.stops.size() - 1; i++) {\r
728                         *pdf_alpha << "<<\n/FunctionType 2\n/Domain [0 1]\n";\r
729                         *pdf_alpha << "/C0 [" << rg->vector.stops[i].opacity << "]\n";\r
730                         *pdf_alpha << "/C1 [" << rg->vector.stops[i+1].opacity << "]\n";\r
731                         *pdf_alpha << "/N 1\n>>\n";\r
732                     }\r
733                     *pdf_alpha << "]\n/Domain [0 1]\n";\r
734                     *pdf_alpha << "/Bounds [ ";\r
735 \r
736                     for (gint i=0;unsigned(i)<rg->vector.stops.size()-2;i++) {\r
737                         *pdf_alpha << rg->vector.stops[i+1].offset <<" ";\r
738                     }\r
739                     *pdf_alpha << "]\n";\r
740                     *pdf_alpha << "/Encode [ ";\r
741                     for (gint i=0;unsigned(i)<rg->vector.stops.size()-1;i++) {\r
742                         *pdf_alpha << "0 1 ";\r
743                     }\r
744                     *pdf_alpha << "]\n";\r
745                     *pdf_alpha << ">>\n>>\n";\r
746                     \r
747                     \r
748                     *pdf_smask << "<< /Type /Mask\n";\r
749                     *pdf_smask << "   /S /Alpha\n";\r
750                     *pdf_smask << "   /BC [0.0]\n";\r
751                     *pdf_smask << "   /G " << pdf_xobj->get_id() << " 0 R\n";\r
752                     *pdf_smask << ">>\n";\r
753 \r
754                     \r
755                     *pdf_xobj << "<< /Type /XObject\n";\r
756                     *pdf_xobj << "   /Subtype /Form\n";\r
757                     *pdf_xobj << "   /FormType 1\n";\r
758                     *pdf_xobj << "   /BBox ["\r
759                               << pbox->x0 << " "\r
760                               << pbox->y0 << " "\r
761                               << pbox->x1 << " "\r
762                               << pbox->y1 << "]\n";\r
763                     *pdf_xobj << "   /Group\n";\r
764                     *pdf_xobj << "   << /Type /Group\n";\r
765                     *pdf_xobj << "      /S /Transparency\n";\r
766                     *pdf_xobj << "      /CS /DeviceGray \n";\r
767                     *pdf_xobj << "   >>\n";\r
768                     *pdf_xobj << "   /Resources\n";\r
769                     *pdf_xobj << "   <<\n";\r
770                     *pdf_xobj << "      /ProcSet [/PDF /Text /ImageB /ImageC /ImageI]\n";\r
771                     *pdf_xobj << "      /Shading << "\r
772                               << pdf_alpha->get_name() << " "\r
773                               << pdf_alpha->get_id() << " 0 R >>\n";\r
774                     *pdf_xobj << "   >>\n";\r
775                     \r
776                     Inkscape::SVGOStringStream os_tmp;\r
777                     os_tmp.setf(std::ios::fixed);\r
778                     \r
779                     os_tmp << "q\n"\r
780                            << pbox->x0 << " " << pbox->y0 << " m\n"\r
781                            << pbox->x1 << " " << pbox->y0 << " l\n"\r
782                            << pbox->x1 << " " << pbox->y1 << " l\n"\r
783                            << pbox->x0 << " " << pbox->y1 << " l\n"\r
784                            << pbox->x0 << " " << pbox->y0 << " l\n"\r
785                            << "h\n"\r
786                            << "W* n\n";\r
787                     \r
788                     SPGradient const *g = SP_GRADIENT(SP_STYLE_FILL_SERVER(style));\r
789                     if (g->gradientTransform_set) {\r
790                         os_tmp << g->gradientTransform[0] << " "\r
791                                << g->gradientTransform[1] << " "\r
792                                << g->gradientTransform[2] << " "\r
793                                << g->gradientTransform[3] << " "\r
794                                << g->gradientTransform[4] << " "\r
795                                << g->gradientTransform[5] << " cm\n"; \r
796                     }\r
797                     \r
798                     os_tmp << pdf_alpha->get_name() << " sh\n";\r
799                     os_tmp << "Q\n";\r
800                     *pdf_xobj << "   /Length " << os_tmp.str().length() << "\n";\r
801                     *pdf_xobj << ">>\n";\r
802                     *pdf_xobj << "stream\n";\r
803                     *pdf_xobj << os_tmp.str().c_str();\r
804                     *pdf_xobj << "endstream\n";\r
805 \r
806 \r
807                     pdf_file->end_resource(pdf_alpha);\r
808                     pdf_file->end_resource(pdf_smask);\r
809                     pdf_file->end_resource(pdf_xobj);\r
810                 }\r
811                 \r
812                 *pdf_gstate << ">>\n";\r
813                 \r
814                 os << pdf_gstate->get_name() << " gs\n";\r
815                 \r
816                 pdf_file->end_resource(pdf_gstate);\r
817             }\r
818         }\r
819     }\r
820 }\r
821 \r
822 void\r
823 PrintPDF::print_fill_style(SVGOStringStream &os, SPStyle const *const style, NRRect const *pbox)\r
824 {\r
825     g_return_if_fail( style->fill.type == SP_PAINT_TYPE_COLOR\r
826                       || ( style->fill.type == SP_PAINT_TYPE_PAINTSERVER\r
827                            && SP_IS_GRADIENT(SP_STYLE_FILL_SERVER(style)) ) );\r
828     \r
829     if (style->fill.type == SP_PAINT_TYPE_COLOR) {\r
830         float rgb[3];\r
831         sp_color_get_rgb_floatv(&style->fill.value.color, rgb);\r
832 \r
833         os << rgb[0] << " " << rgb[1] << " " << rgb[2] << " rg\n";\r
834     } else {\r
835         g_assert( style->fill.type == SP_PAINT_TYPE_PAINTSERVER\r
836                   && SP_IS_GRADIENT(SP_STYLE_FILL_SERVER(style)) );\r
837 \r
838         if (SP_IS_LINEARGRADIENT (SP_STYLE_FILL_SERVER (style))) {\r
839 \r
840             SPLinearGradient *lg=SP_LINEARGRADIENT(SP_STYLE_FILL_SERVER (style));\r
841             sp_gradient_ensure_vector(SP_GRADIENT(lg)); // when exporting from commandline, vector is not built\r
842 \r
843             NR::Point p1 (lg->x1.computed, lg->y1.computed);\r
844             NR::Point p2 (lg->x2.computed, lg->y2.computed);\r
845             if (pbox && SP_GRADIENT(lg)->units == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX) {\r
846                 // convert to userspace\r
847                 NR::Matrix bbox2user(pbox->x1 - pbox->x0, 0, 0, pbox->y1 - pbox->y0, pbox->x0, pbox->y0);\r
848                 p1 *= bbox2user;\r
849                 p2 *= bbox2user;\r
850             }\r
851 \r
852             PdfObject *pdf_shade = pdf_file->begin_resource(pdf_shading);\r
853 \r
854             *pdf_shade << "<<\n/ShadingType 2\n/ColorSpace /DeviceRGB\n";\r
855             *pdf_shade << "/Coords [" << p1[NR::X] << " " << p1[NR::Y] << " " << p2[NR::X] << " " << p2[NR::Y] <<"]\n";\r
856             *pdf_shade << "/Extend [true true]\n";\r
857             *pdf_shade << "/Domain [0 1]\n";\r
858             *pdf_shade << "/Function <<\n/FunctionType 3\n/Functions\n[\n";\r
859 \r
860             for (gint i = 0; unsigned(i) < lg->vector.stops.size() - 1; i++) {\r
861                 float rgb[3];\r
862                 sp_color_get_rgb_floatv(&lg->vector.stops[i].color, rgb);\r
863                 *pdf_shade << "<<\n/FunctionType 2\n/Domain [0 1]\n";\r
864                 *pdf_shade << "/C0 [" << rgb[0] << " " << rgb[1] << " " << rgb[2] << "]\n";\r
865                 sp_color_get_rgb_floatv(&lg->vector.stops[i+1].color, rgb);\r
866                 *pdf_shade << "/C1 [" << rgb[0] << " " << rgb[1] << " " << rgb[2] << "]\n";\r
867                 *pdf_shade << "/N 1\n>>\n";\r
868             }\r
869             *pdf_shade << "]\n/Domain [0 1]\n";\r
870             *pdf_shade << "/Bounds [ ";\r
871             for (gint i=0;unsigned(i)<lg->vector.stops.size()-2;i++) {\r
872                 *pdf_shade << lg->vector.stops[i+1].offset <<" ";\r
873             }\r
874             *pdf_shade << "]\n";\r
875             *pdf_shade << "/Encode [ ";\r
876             for (gint i=0;unsigned(i)<lg->vector.stops.size()-1;i++) {\r
877                 *pdf_shade << "0 1 ";\r
878             }\r
879             *pdf_shade << "]\n";\r
880             *pdf_shade << ">>\n>>\n";\r
881             os << pdf_shade->get_name() << " ";\r
882 \r
883             pdf_file->end_resource(pdf_shade);\r
884         } else if (SP_IS_RADIALGRADIENT (SP_STYLE_FILL_SERVER (style))) {\r
885 \r
886             SPRadialGradient *rg=SP_RADIALGRADIENT(SP_STYLE_FILL_SERVER (style));\r
887             sp_gradient_ensure_vector(SP_GRADIENT(rg)); // when exporting from commandline, vector is not built\r
888 \r
889             NR::Point c (rg->cx.computed, rg->cy.computed);\r
890             NR::Point f (rg->fx.computed, rg->fy.computed);\r
891             double r = rg->r.computed;\r
892 \r
893             NR::Coord const df = hypot(f[NR::X] - c[NR::X], f[NR::Y] - c[NR::Y]);\r
894             if (df >= r) {\r
895                 f[NR::X] = c[NR::X] + (f[NR::X] - c[NR::X] ) * r / (float) df;\r
896                 f[NR::Y] = c[NR::Y] + (f[NR::Y] - c[NR::Y] ) * r / (float) df;\r
897             }\r
898 \r
899             if (pbox && SP_GRADIENT(rg)->units == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX) {\r
900                 // convert to userspace\r
901                 NR::Matrix bbox2user(pbox->x1 - pbox->x0, 0, 0, pbox->y1 - pbox->y0, pbox->x0, pbox->y0);\r
902                 c *= bbox2user;\r
903                 f *= bbox2user;\r
904                 r *= bbox2user.expansion();\r
905             }\r
906 \r
907             PdfObject *pdf_shade = pdf_file->begin_resource(pdf_shading);\r
908 \r
909             *pdf_shade << "<<\n/ShadingType 3\n/ColorSpace /DeviceRGB\n";\r
910             *pdf_shade << "/Coords ["<< f[NR::X] <<" "<< f[NR::Y] <<" 0 "<< c[NR::X] <<" "<< c[NR::Y] <<" "<< r <<"]\n";\r
911             *pdf_shade << "/Extend [true true]\n";\r
912             *pdf_shade << "/Domain [0 1]\n";\r
913             *pdf_shade << "/Function <<\n/FunctionType 3\n/Functions\n[\n";\r
914 \r
915             for (gint i = 0; unsigned(i) < rg->vector.stops.size() - 1; i++) {\r
916                 float rgb[3];\r
917                 sp_color_get_rgb_floatv(&rg->vector.stops[i].color, rgb);\r
918                 *pdf_shade << "<<\n/FunctionType 2\n/Domain [0 1]\n";\r
919                 *pdf_shade << "/C0 [" << rgb[0] << " " << rgb[1] << " " << rgb[2] << "]\n";\r
920                 sp_color_get_rgb_floatv(&rg->vector.stops[i+1].color, rgb);\r
921                 *pdf_shade << "/C1 [" << rgb[0] << " " << rgb[1] << " " << rgb[2] << "]\n";\r
922                 *pdf_shade << "/N 1\n>>\n";\r
923             }\r
924             *pdf_shade << "]\n/Domain [0 1]\n";\r
925             *pdf_shade << "/Bounds [ ";\r
926 \r
927             for (gint i=0;unsigned(i)<rg->vector.stops.size()-2;i++) {\r
928                 *pdf_shade << rg->vector.stops[i+1].offset <<" ";\r
929             }\r
930             *pdf_shade << "]\n";\r
931             *pdf_shade << "/Encode [ ";\r
932             for (gint i=0;unsigned(i)<rg->vector.stops.size()-1;i++) {\r
933                 *pdf_shade << "0 1 ";\r
934             }\r
935             *pdf_shade << "]\n";\r
936             *pdf_shade << ">>\n>>\n";\r
937 \r
938             os << pdf_shade->get_name() << " ";\r
939 \r
940             pdf_file->end_resource(pdf_shade);\r
941         }\r
942     }\r
943 }\r
944 \r
945 void\r
946 PrintPDF::print_stroke_style(SVGOStringStream &os, SPStyle const *style)\r
947 {\r
948     float rgb[3];\r
949     \r
950     sp_color_get_rgb_floatv(&style->stroke.value.color, rgb);\r
951     os << rgb[0] << " " << rgb[1] << " " << rgb[2] << " RG\n";\r
952         \r
953     float alpha = 1.0;\r
954     alpha *= SP_SCALE24_TO_FLOAT(style->stroke_opacity.value);\r
955     alpha *= _pushed_alphas.back();\r
956 \r
957     if (alpha != 1.0) {\r
958         PdfObject *pdf_alpha = pdf_file->begin_resource(pdf_extgstate);\r
959         *pdf_alpha << "<< /Type /ExtGState\n";\r
960         *pdf_alpha << "   /CA " << alpha << "\n";\r
961         *pdf_alpha << "   /AIS false\n";\r
962         *pdf_alpha << ">>\n";\r
963         \r
964         os << pdf_alpha->get_name() << " gs\n";\r
965         \r
966         pdf_file->end_resource(pdf_alpha);\r
967     }\r
968 \r
969     // There are rare cases in which for a solid line stroke_dasharray_set is true. To avoid\r
970     // invalid PS-lines such as "[0.0000000 0.0000000] 0.0000000 setdash", which should be "[] 0 setdash",\r
971     // we first check if all components of stroke_dash.dash are 0.\r
972     bool LineSolid = true;\r
973     if (style->stroke_dash.n_dash   &&\r
974         style->stroke_dash.dash       )\r
975     {\r
976         int i = 0;\r
977         while (LineSolid && (i < style->stroke_dash.n_dash)) {\r
978                 if (style->stroke_dash.dash[i] > 0.00000001)\r
979                     LineSolid = false;\r
980                 i++;\r
981         }\r
982         if (!LineSolid) {\r
983             os << "[";\r
984             for (i = 0; i < style->stroke_dash.n_dash; i++) {\r
985                 if (i > 0) {\r
986                     os << " ";\r
987                 }\r
988                 os << style->stroke_dash.dash[i];\r
989             }\r
990             os << "] " << style->stroke_dash.offset << " d\n";\r
991         } else {\r
992             os << "[] 0 d\n";\r
993         }\r
994     } else {\r
995         os << "[] 0 d\n";\r
996     }\r
997 \r
998     os << style->stroke_width.computed << " w\n";\r
999     os << style->stroke_linejoin.computed << " j\n";\r
1000     os << style->stroke_linecap.computed << " J\n";\r
1001     os <<\r
1002         ( style->stroke_miterlimit.value > 1 ?\r
1003           style->stroke_miterlimit.value : 1 ) << " M\n";\r
1004 }\r
1005 \r
1006 \r
1007 unsigned int\r
1008 PrintPDF::fill(Inkscape::Extension::Print *mod, NRBPath const *bpath, NRMatrix const *ctm, SPStyle const *const style,\r
1009               NRRect const *pbox, NRRect const *dbox, NRRect const *bbox)\r
1010 {\r
1011     Inkscape::SVGOStringStream os;\r
1012     os.setf(std::ios::fixed);\r
1013 \r
1014     if (!_stream) return 0; // XXX: fixme, returning -1 as unsigned.\r
1015     if (_bitmap) return 0;\r
1016 \r
1017     if ( style->fill.type == SP_PAINT_TYPE_COLOR ) {\r
1018         os << "q\n";\r
1019         print_fill_style(os, style, pbox);\r
1020         print_fill_alpha(os, style, pbox);\r
1021         print_bpath(os, bpath->path);\r
1022         if (style->fill_rule.value == SP_WIND_RULE_EVENODD) {\r
1023             os << "f*\n";\r
1024         } else {\r
1025             os << "f\n";\r
1026         }\r
1027         os << "Q\n";\r
1028     }\r
1029     else if ( style->fill.type == SP_PAINT_TYPE_PAINTSERVER\r
1030               && SP_IS_GRADIENT(SP_STYLE_FILL_SERVER(style)) )\r
1031     {\r
1032         os << "q\n";\r
1033         print_bpath(os, bpath->path);\r
1034 \r
1035         if (style->fill_rule.value == SP_WIND_RULE_EVENODD) {\r
1036             g_assert( style->fill.type == SP_PAINT_TYPE_PAINTSERVER\r
1037                       && SP_IS_GRADIENT(SP_STYLE_FILL_SERVER(style)) );\r
1038             SPGradient const *g = SP_GRADIENT(SP_STYLE_FILL_SERVER(style));\r
1039             os << "W* n\n";\r
1040             print_fill_alpha(os, style, pbox);\r
1041             if (g->gradientTransform_set) {\r
1042                 os << "q\n";\r
1043                 os << g->gradientTransform[0] << " "\r
1044                    << g->gradientTransform[1] << " "\r
1045                    << g->gradientTransform[2] << " "\r
1046                    << g->gradientTransform[3] << " "\r
1047                    << g->gradientTransform[4] << " "\r
1048                    << g->gradientTransform[5] << " cm\n";\r
1049             }\r
1050             print_fill_style(os, style, pbox);\r
1051             os << "sh\n";\r
1052             if (g->gradientTransform_set) {\r
1053                 os << "Q\n";\r
1054             }\r
1055         } else {\r
1056             g_assert( style->fill.type == SP_PAINT_TYPE_PAINTSERVER\r
1057                       && SP_IS_GRADIENT(SP_STYLE_FILL_SERVER(style)) );\r
1058             SPGradient const *g = SP_GRADIENT(SP_STYLE_FILL_SERVER(style));\r
1059             os << "W n\n";\r
1060             print_fill_alpha(os, style, pbox);\r
1061             if (g->gradientTransform_set) {\r
1062                 os << "q\n";\r
1063                 os << g->gradientTransform[0] << " "\r
1064                    << g->gradientTransform[1] << " "\r
1065                    << g->gradientTransform[2] << " "\r
1066                    << g->gradientTransform[3] << " "\r
1067                    << g->gradientTransform[4] << " "\r
1068                    << g->gradientTransform[5] << " cm\n"; \r
1069             }\r
1070             print_fill_style(os, style, pbox);\r
1071             os << "sh\n";\r
1072             if (g->gradientTransform_set) {\r
1073                 os << "Q\n";\r
1074             }\r
1075         }\r
1076 \r
1077         os << "Q\n";\r
1078     }        \r
1079 \r
1080     pdf_file->puts(os);\r
1081     return 0;\r
1082 }\r
1083 \r
1084 \r
1085 unsigned int\r
1086 PrintPDF::stroke(Inkscape::Extension::Print *mod, NRBPath const *bpath, NRMatrix const *ctm, SPStyle const *style,\r
1087                 NRRect const *pbox, NRRect const *dbox, NRRect const *bbox)\r
1088 {\r
1089     if (!_stream) return 0; // XXX: fixme, returning -1 as unsigned.\r
1090     if (_bitmap) return 0;\r
1091 \r
1092     if (style->stroke.type == SP_PAINT_TYPE_COLOR) {\r
1093         Inkscape::SVGOStringStream os;\r
1094         os.setf(std::ios::fixed);\r
1095 \r
1096         os << "q\n";\r
1097 \r
1098         print_stroke_style(os, style);\r
1099         print_bpath(os, bpath->path);\r
1100         os << "S\n";\r
1101 \r
1102         os << "Q\n";\r
1103 \r
1104         pdf_file->puts(os);\r
1105     }\r
1106 \r
1107     return 0;\r
1108 }\r
1109 \r
1110 unsigned int\r
1111 PrintPDF::image(Inkscape::Extension::Print *mod, guchar *px, unsigned int w, unsigned int h, unsigned int rs,\r
1112                NRMatrix const *transform, SPStyle const *style)\r
1113 {\r
1114     if (!_stream) return 0; // XXX: fixme, returning -1 as unsigned.\r
1115     if (_bitmap) return 0;\r
1116     \r
1117     return print_image(_stream, px, w, h, rs, transform);\r
1118 }\r
1119 \r
1120 char const *\r
1121 PrintPDF::PSFontName(SPStyle const *style)\r
1122 {\r
1123     font_instance *tf = (font_factory::Default())->Face(style->text->font_family.value, font_style_to_pos(*style));\r
1124 \r
1125     char const *n;\r
1126     char name_buf[256];\r
1127 \r
1128     if (tf) {\r
1129         tf->PSName(name_buf, sizeof(name_buf));\r
1130         n = name_buf;\r
1131         tf->Unref();\r
1132     } else {\r
1133         // this system does not have this font, so just use the name from SVG in the hope that PS interpreter will make sense of it\r
1134         bool i = (style->font_style.value == SP_CSS_FONT_STYLE_ITALIC);\r
1135         bool o = (style->font_style.value == SP_CSS_FONT_STYLE_OBLIQUE);\r
1136         bool b = (style->font_weight.value == SP_CSS_FONT_WEIGHT_BOLD) ||\r
1137             (style->font_weight.value >= SP_CSS_FONT_WEIGHT_500 && style->font_weight.value <= SP_CSS_FONT_WEIGHT_900);\r
1138 \r
1139         n = g_strdup_printf("%s%s%s%s",\r
1140                             g_strdelimit(style->text->font_family.value, " ", '-'),\r
1141                             (b || i || o) ? "-" : "",\r
1142                             (b) ? "Bold" : "",\r
1143                             (i) ? "Italic" : ((o) ? "Oblique" : "") );\r
1144     }\r
1145 \r
1146     return g_strdup(n);\r
1147 }\r
1148 \r
1149 \r
1150 unsigned int\r
1151 PrintPDF::text(Inkscape::Extension::Print *mod, char const *text, NR::Point p,\r
1152               SPStyle const *const style)\r
1153 {\r
1154     if (!_stream) return 0; // XXX: fixme, returning -1 as unsigned.\r
1155     if (_bitmap) return 0;\r
1156 \r
1157     Inkscape::SVGOStringStream os;\r
1158     os.setf(std::ios::fixed);\r
1159 \r
1160     return 0;\r
1161     \r
1162     // Escape chars\r
1163     Inkscape::SVGOStringStream escaped_text;\r
1164     escaped_text.setf(std::ios::fixed);\r
1165     \r
1166     escaped_text << std::oct;\r
1167     for (gchar const *p_text = text ; *p_text ; p_text = g_utf8_next_char(p_text)) {\r
1168         gunichar const c = g_utf8_get_char(p_text);\r
1169         if (c == '\\' || c == ')' || c == '(')\r
1170             escaped_text << '\\' << static_cast<char>(c);\r
1171         else if (c >= 0x80)\r
1172             escaped_text << '\\' << c;\r
1173         else\r
1174             escaped_text << static_cast<char>(c);\r
1175     }\r
1176 \r
1177     os << "gsave\n";\r
1178 \r
1179     // set font\r
1180     char const *fn = PSFontName(style);\r
1181     if (_latin1_encoded_fonts.find(fn) == _latin1_encoded_fonts.end()) {\r
1182         if (!_newlatin1font_proc_defined) {\r
1183             // input: newfontname, existingfontname\r
1184             // output: new font object, also defined to newfontname\r
1185             os << "/newlatin1font "         // name of the proc\r
1186                   "{findfont dup length dict copy "     // load the font and create a copy of it\r
1187                   "dup /Encoding ISOLatin1Encoding put "     // change the encoding in the copy\r
1188                   "definefont} def\n";      // create the new font and leave it on the stack, define the proc\r
1189             _newlatin1font_proc_defined = true;\r
1190         }\r
1191         os << "/" << fn << "-ISOLatin1 /" << fn << " newlatin1font\n";\r
1192         _latin1_encoded_fonts.insert(fn);\r
1193     } else\r
1194         os << "/" << fn << "-ISOLatin1 findfont\n";\r
1195     os << style->font_size.computed << " scalefont\n";\r
1196     os << "setfont\n";\r
1197     g_free((void *) fn);\r
1198 \r
1199     if ( style->fill.type == SP_PAINT_TYPE_COLOR\r
1200          || ( style->fill.type == SP_PAINT_TYPE_PAINTSERVER\r
1201               && SP_IS_GRADIENT(SP_STYLE_FILL_SERVER(style)) ) )\r
1202     {\r
1203         // set fill style\r
1204         print_fill_style(os, style, NULL);\r
1205         // FIXME: we don't know the pbox of text, so have to pass NULL. This means gradients with\r
1206         // bbox units won't work with text. However userspace gradients don't work with text either\r
1207         // (text is black) for some reason.\r
1208 \r
1209         os << "newpath\n";\r
1210         os << p[NR::X] << " " << p[NR::Y] << " moveto\n";\r
1211         os << "(" << escaped_text.str() << ") show\n";\r
1212     }\r
1213 \r
1214     if (style->stroke.type == SP_PAINT_TYPE_COLOR) {\r
1215 \r
1216         // set stroke style\r
1217         print_stroke_style(os, style);\r
1218 \r
1219         // paint stroke\r
1220         os << "newpath\n";\r
1221         os << p[NR::X] << " " << p[NR::Y] << " moveto\n";\r
1222         os << "(" << escaped_text.str() << ") false charpath stroke\n";\r
1223     }\r
1224 \r
1225     os << "grestore\n";\r
1226 \r
1227     fprintf(_stream, "%s", os.str().c_str());\r
1228 \r
1229     return 0;\r
1230 }\r
1231 \r
1232 \r
1233 \r
1234 /* PDF helpers */\r
1235 \r
1236 void\r
1237 PrintPDF::print_bpath(SVGOStringStream &os, NArtBpath const *bp)\r
1238 {\r
1239     bool closed = false;\r
1240     while (bp->code != NR_END) {\r
1241         switch (bp->code) {\r
1242             case NR_MOVETO:\r
1243                 if (closed) {\r
1244                     os << "h\n";\r
1245                 }\r
1246                 closed = true;\r
1247                 os << bp->x3 << " " << bp->y3 << " m\n";\r
1248                 break;\r
1249             case NR_MOVETO_OPEN:\r
1250                 if (closed) {\r
1251                     os << "h\n";\r
1252                 }\r
1253                 closed = false;\r
1254                 os << bp->x3 << " " << bp->y3 << " m\n";\r
1255                 break;\r
1256             case NR_LINETO:\r
1257                 os << bp->x3 << " " << bp->y3 << " l\n";\r
1258                 break;\r
1259             case NR_CURVETO:\r
1260                 os << bp->x1 << " " << bp->y1 << " "\r
1261                    << bp->x2 << " " << bp->y2 << " "\r
1262                    << bp->x3 << " " << bp->y3 << " c\n";\r
1263                 break;\r
1264             default:\r
1265                 break;\r
1266         }\r
1267         bp += 1;\r
1268     }\r
1269     if (closed) {\r
1270         os << "h\n";\r
1271     }\r
1272 }\r
1273 \r
1274 /* The following code is licensed under GNU GPL.\r
1275 ** The packbits, ascii85 and imaging printing code\r
1276 ** is from the gimp's postscript.c.\r
1277 */\r
1278 \r
1279 /**\r
1280 * \param nin Number of bytes of source data.\r
1281 * \param src Source data.\r
1282 * \param nout Number of output bytes.\r
1283 * \param dst Buffer for output.\r
1284 */\r
1285 void\r
1286 PrintPDF::compress_packbits(int nin,\r
1287                            guchar *src,\r
1288                            int *nout,\r
1289                            guchar *dst)\r
1290 \r
1291 {\r
1292     register guchar c;\r
1293     int nrepeat, nliteral;\r
1294     guchar *run_start;\r
1295     guchar *start_dst = dst;\r
1296     guchar *last_literal = NULL;\r
1297 \r
1298     for (;;) {\r
1299         if (nin <= 0) break;\r
1300 \r
1301         run_start = src;\r
1302         c = *run_start;\r
1303 \r
1304         /* Search repeat bytes */\r
1305         if ((nin > 1) && (c == src[1])) {\r
1306             nrepeat = 1;\r
1307             nin -= 2;\r
1308             src += 2;\r
1309             while ((nin > 0) && (c == *src)) {\r
1310                 nrepeat++;\r
1311                 src++;\r
1312                 nin--;\r
1313                 if (nrepeat == 127) break; /* Maximum repeat */\r
1314             }\r
1315 \r
1316             /* Add two-byte repeat to last literal run ? */\r
1317             if ( (nrepeat == 1)\r
1318                  && (last_literal != NULL) && (((*last_literal)+1)+2 <= 128) )\r
1319             {\r
1320                 *last_literal += 2;\r
1321                 *(dst++) = c;\r
1322                 *(dst++) = c;\r
1323                 continue;\r
1324             }\r
1325 \r
1326             /* Add repeat run */\r
1327             *(dst++) = (guchar)((-nrepeat) & 0xff);\r
1328             *(dst++) = c;\r
1329             last_literal = NULL;\r
1330             continue;\r
1331         }\r
1332         /* Search literal bytes */\r
1333         nliteral = 1;\r
1334         nin--;\r
1335         src++;\r
1336 \r
1337         for (;;) {\r
1338             if (nin <= 0) break;\r
1339 \r
1340             if ((nin >= 2) && (src[0] == src[1])) /* A two byte repeat ? */\r
1341                 break;\r
1342 \r
1343             nliteral++;\r
1344             nin--;\r
1345             src++;\r
1346             if (nliteral == 128) break; /* Maximum literal run */\r
1347         }\r
1348 \r
1349         /* Could be added to last literal run ? */\r
1350         if ((last_literal != NULL) && (((*last_literal)+1)+nliteral <= 128)) {\r
1351             *last_literal += nliteral;\r
1352         } else {\r
1353             last_literal = dst;\r
1354             *(dst++) = (guchar)(nliteral-1);\r
1355         }\r
1356         while (nliteral-- > 0) *(dst++) = *(run_start++);\r
1357     }\r
1358     *nout = dst - start_dst;\r
1359 }\r
1360 \r
1361 void\r
1362 PrintPDF::ascii85_init(void)\r
1363 {\r
1364     ascii85_len = 0;\r
1365     ascii85_linewidth = 0;\r
1366 }\r
1367 \r
1368 void\r
1369 PrintPDF::ascii85_flush(SVGOStringStream &os)\r
1370 {\r
1371     char c[5];\r
1372     bool const zero_case = (ascii85_buf == 0);\r
1373     static int const max_linewidth = 75;\r
1374 \r
1375     for (int i = 4; i >= 0; i--) {\r
1376         c[i] = (ascii85_buf % 85) + '!';\r
1377         ascii85_buf /= 85;\r
1378     }\r
1379     /* check for special case: "!!!!!" becomes "z", but only if not\r
1380      * at end of data. */\r
1381     if (zero_case && (ascii85_len == 4)) {\r
1382         if (ascii85_linewidth >= max_linewidth) {\r
1383             os << '\n';\r
1384             ascii85_linewidth = 0;\r
1385         }\r
1386         os << 'z';\r
1387         ascii85_linewidth++;\r
1388     } else {\r
1389         for (int i = 0; i < ascii85_len+1; i++) {\r
1390             if ((ascii85_linewidth >= max_linewidth) && (c[i] != '%')) {\r
1391                 os << '\n';\r
1392                 ascii85_linewidth = 0;\r
1393             }\r
1394             os << c[i];\r
1395             ascii85_linewidth++;\r
1396         }\r
1397     }\r
1398 \r
1399     ascii85_len = 0;\r
1400     ascii85_buf = 0;\r
1401 }\r
1402 \r
1403 inline void\r
1404 PrintPDF::ascii85_out(guchar byte, SVGOStringStream &os)\r
1405 {\r
1406     if (ascii85_len == 4)\r
1407         ascii85_flush(os);\r
1408 \r
1409     ascii85_buf <<= 8;\r
1410     ascii85_buf |= byte;\r
1411     ascii85_len++;\r
1412 }\r
1413 \r
1414 void\r
1415 PrintPDF::ascii85_nout(int n, guchar *uptr, SVGOStringStream &os)\r
1416 {\r
1417     while (n-- > 0) {\r
1418         ascii85_out(*uptr, os);\r
1419         uptr++;\r
1420     }\r
1421 }\r
1422 \r
1423 void\r
1424 PrintPDF::ascii85_done(SVGOStringStream &os)\r
1425 {\r
1426     if (ascii85_len) {\r
1427         /* zero any unfilled buffer portion, then flush */\r
1428         ascii85_buf <<= (8 * (4-ascii85_len));\r
1429         ascii85_flush(os);\r
1430     }\r
1431 \r
1432     os << "~>\n";\r
1433 }\r
1434 \r
1435 unsigned int\r
1436 PrintPDF::print_image(FILE *ofp, guchar *px, unsigned int width, unsigned int height, unsigned int rs,\r
1437                      NRMatrix const *transform)\r
1438 {\r
1439     Inkscape::SVGOStringStream os;\r
1440     os.setf(std::ios::fixed);\r
1441 \r
1442     PdfObject *pdf_image = pdf_file->begin_resource(pdf_xobject);\r
1443     PdfObject *pdf_image_len = pdf_file->begin_resource(pdf_none);\r
1444     \r
1445     PdfObject *pdf_smask = pdf_file->begin_resource(pdf_xobject);\r
1446     PdfObject *pdf_smask_len = pdf_file->begin_resource(pdf_none);\r
1447 \r
1448 \r
1449     os << "q\n";\r
1450     os << transform->c[0] << " "\r
1451        << transform->c[1] << " "\r
1452        << transform->c[2] << " "\r
1453        << transform->c[3] << " "\r
1454        << transform->c[4] << " "\r
1455        << transform->c[5] << " cm\n";\r
1456     os << pdf_image->get_name() << " Do\n";\r
1457     os << "Q\n";\r
1458     pdf_file->puts(os);\r
1459 \r
1460 \r
1461     *pdf_image << "<< /Type /XObject\n";\r
1462     *pdf_image << "   /Subtype /Image\n";\r
1463     *pdf_image << "   /Width " << width << "\n";\r
1464     *pdf_image << "   /Height " << height << "\n";\r
1465     *pdf_image << "   /ColorSpace /DeviceRGB\n";\r
1466     *pdf_image << "   /BitsPerComponent 8\n";\r
1467     *pdf_image << "   /Length " << pdf_image_len->get_id() << " 0 R\n";\r
1468     *pdf_image << "   /Filter /ASCIIHexDecode\n";\r
1469     *pdf_image << "   /SMask " << pdf_smask->get_id() << " 0 R\n";\r
1470     *pdf_image << ">>\n";\r
1471 \r
1472     *pdf_image << "stream\n";\r
1473 \r
1474 \r
1475     *pdf_smask << "<< /Type /XObject\n";\r
1476     *pdf_smask << "   /Subtype /Image\n";\r
1477     *pdf_smask << "   /Width " << width << "\n";\r
1478     *pdf_smask << "   /Height " << height << "\n";\r
1479     *pdf_smask << "   /ColorSpace /DeviceGray\n";\r
1480     *pdf_smask << "   /BitsPerComponent 8\n";\r
1481     *pdf_smask << "   /Length " << pdf_smask_len->get_id() << " 0 R\n";\r
1482     *pdf_smask << "   /Filter /ASCIIHexDecode\n";\r
1483     *pdf_smask << ">>\n";\r
1484 \r
1485     *pdf_smask << "stream\n";\r
1486 \r
1487 \r
1488     unsigned long image_len = pdf_image->get_length();\r
1489     unsigned long smask_len = pdf_smask->get_length();\r
1490 \r
1491     int image_chars = 0;\r
1492     int smask_chars = 0;\r
1493 \r
1494     for (unsigned i = 0; i < height; i++) {\r
1495         guchar const *const src = px + i * rs;\r
1496 \r
1497         for (unsigned j = 0; j < width; j++) {\r
1498             char hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};\r
1499             guchar const *src_ptr = src + 4*j;\r
1500 \r
1501             /* Iterate over RGB */\r
1502             for (int rgb = 0; rgb < 3; rgb++) {\r
1503                 guchar val = *(src_ptr + rgb);\r
1504 \r
1505                 *pdf_image << hex[val / 16];\r
1506                 *pdf_image << hex[val % 16];\r
1507 \r
1508                 image_chars += 2;\r
1509                 if (image_chars >= 78) {\r
1510                     *pdf_image << "\n";\r
1511                     image_chars = 0;\r
1512                 }\r
1513             }\r
1514 \r
1515             guchar alpha = *(src_ptr + 3);\r
1516 \r
1517             *pdf_smask << hex[alpha / 16];\r
1518             *pdf_smask << hex[alpha % 16];\r
1519             \r
1520             smask_chars += 2;\r
1521             if (smask_chars >= 78) {\r
1522                 *pdf_smask << "\n";\r
1523                 smask_chars = 0;\r
1524             }\r
1525         }\r
1526     }\r
1527 \r
1528 \r
1529     *pdf_image << ">\n";\r
1530     image_len = pdf_image->get_length() - image_len;\r
1531 \r
1532     *pdf_image << "endstream\n";\r
1533     pdf_file->end_resource(pdf_image);\r
1534 \r
1535     *pdf_image_len << image_len << "\n";\r
1536     pdf_file->end_resource(pdf_image_len);\r
1537 \r
1538 \r
1539     *pdf_smask << ">\n";\r
1540     smask_len = pdf_smask->get_length() - smask_len;\r
1541 \r
1542     *pdf_smask << "endstream\n";\r
1543     pdf_file->end_resource(pdf_smask);\r
1544 \r
1545     *pdf_smask_len << smask_len << "\n";\r
1546     pdf_file->end_resource(pdf_smask_len);\r
1547 \r
1548 \r
1549     return 0;\r
1550 }\r
1551 \r
1552 bool\r
1553 PrintPDF::textToPath(Inkscape::Extension::Print * ext)\r
1554 {\r
1555     return ext->get_param_bool("textToPath");\r
1556 }\r
1557 \r
1558 #include "clear-n_.h"\r
1559 \r
1560 void\r
1561 PrintPDF::init(void)\r
1562 {\r
1563     /* PDF print */\r
1564     (void) Inkscape::Extension::build_from_mem(\r
1565         "<inkscape-extension>\n"\r
1566         "<name>" N_("PDF Print") "</name>\n"\r
1567         "<id>" SP_MODULE_KEY_PRINT_PDF "</id>\n"\r
1568         "<param name=\"bitmap\" type=\"boolean\">FALSE</param>\n"\r
1569         "<param name=\"resolution\" type=\"string\">72</param>\n"\r
1570         "<param name=\"destination\" type=\"string\">| lp</param>\n"\r
1571         "<param name=\"pageBoundingBox\" type=\"boolean\">TRUE</param>\n"\r
1572         "<param name=\"textToPath\" type=\"boolean\">TRUE</param>\n"\r
1573         "<print/>\n"\r
1574         "</inkscape-extension>", new PrintPDF());\r
1575 }\r
1576 \r
1577 \r
1578 }  /* namespace Internal */\r
1579 }  /* namespace Extension */\r
1580 }  /* namespace Inkscape */\r
1581 \r
1582 /* End of GNU GPL code */\r
1583 \r
1584 \r
1585 /*\r
1586   Local Variables:\r
1587   mode:c++\r
1588   c-file-style:"stroustrup"\r
1589   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))\r
1590   indent-tabs-mode:nil\r
1591   fill-column:99\r
1592   End:\r
1593 */\r
1594 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :\r