1 /*
2 * A quick hack to use the Cairo renderer to write out a file. This
3 * then makes 'save as...' PDF.
4 *
5 * Authors:
6 * Ted Gould <ted@gould.cx>
7 * Ulf Erikson <ulferikson@users.sf.net>
8 * Johan Engelen <goejendaagh@zonnet.nl>
9 * Jon A. Cruz <jon@joncruz.org>
10 * Abhishek Sharma
11 *
12 * Copyright (C) 2004-2010 Authors
13 *
14 * Released under GNU GPL, read the file 'COPYING' for more information
15 */
17 #ifdef HAVE_CONFIG_H
18 # include <config.h>
19 #endif
21 #ifdef HAVE_CAIRO_PDF
23 #include "cairo-renderer-pdf-out.h"
24 #include "cairo-render-context.h"
25 #include "cairo-renderer.h"
26 #include "latex-text-renderer.h"
27 #include <print.h>
28 #include "extension/system.h"
29 #include "extension/print.h"
30 #include "extension/db.h"
31 #include "extension/output.h"
32 #include "display/nr-arena.h"
33 #include "display/nr-arena-item.h"
35 #include "display/curve.h"
36 #include "display/canvas-bpath.h"
37 #include "sp-item.h"
38 #include "sp-root.h"
40 #include <2geom/matrix.h>
42 namespace Inkscape {
43 namespace Extension {
44 namespace Internal {
46 bool
47 CairoRendererPdfOutput::check (Inkscape::Extension::Extension * module)
48 {
49 if (NULL == Inkscape::Extension::db.get("org.inkscape.output.pdf.cairorenderer"))
50 return FALSE;
52 return TRUE;
53 }
55 static bool
56 pdf_render_document_to_file(SPDocument *doc, gchar const *filename, unsigned int level,
57 bool texttopath, bool omittext, bool filtertobitmap, int resolution,
58 const gchar * const exportId, bool exportDrawing, bool exportCanvas)
59 {
60 doc->ensureUpToDate();
62 /* Start */
64 SPItem *base = NULL;
66 bool pageBoundingBox = TRUE;
67 if (exportId && strcmp(exportId, "")) {
68 // we want to export the given item only
69 base = SP_ITEM(doc->getObjectById(exportId));
70 pageBoundingBox = exportCanvas;
71 }
72 else {
73 // we want to export the entire document from root
74 base = SP_ITEM(doc->getRoot());
75 pageBoundingBox = !exportDrawing;
76 }
78 if (!base) {
79 return false;
80 }
82 /* Create new arena */
83 NRArena *arena = NRArena::create();
84 nr_arena_set_renderoffscreen (arena);
85 unsigned dkey = SPItem::display_key_new(1);
86 base->invoke_show(arena, dkey, SP_ITEM_SHOW_DISPLAY);
88 /* Create renderer and context */
89 CairoRenderer *renderer = new CairoRenderer();
90 CairoRenderContext *ctx = renderer->createContext();
91 ctx->setPDFLevel(level);
92 ctx->setTextToPath(texttopath);
93 renderer->_omitText = omittext;
94 ctx->setFilterToBitmap(filtertobitmap);
95 ctx->setBitmapResolution(resolution);
97 bool ret = ctx->setPdfTarget (filename);
98 if(ret) {
99 /* Render document */
100 ret = renderer->setupDocument(ctx, doc, pageBoundingBox, base);
101 if (ret) {
102 renderer->renderItem(ctx, base);
103 ret = ctx->finish();
104 }
105 }
107 /* Release arena */
108 base->invoke_hide(dkey);
109 nr_object_unref((NRObject *) arena);
111 renderer->destroyContext(ctx);
112 delete renderer;
114 return ret;
115 }
117 /**
118 \brief This function calls the output module with the filename
119 \param mod unused
120 \param doc Document to be saved
121 \param filename Filename to save to (probably will end in .pdf)
123 The most interesting thing that this function does is just attach
124 an '>' on the front of the filename. This is the syntax used to
125 tell the printing system to save to file.
126 */
127 void
128 CairoRendererPdfOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *filename)
129 {
130 Inkscape::Extension::Extension * ext;
131 unsigned int ret;
133 ext = Inkscape::Extension::db.get("org.inkscape.output.pdf.cairorenderer");
134 if (ext == NULL)
135 return;
137 const gchar *new_level = NULL;
138 int level = 0;
139 try {
140 new_level = mod->get_param_enum("PDFversion");
141 if((new_level != NULL) && (g_ascii_strcasecmp("PDF-1.5", new_level) == 0))
142 level = 1;
143 }
144 catch(...) {
145 g_warning("Parameter <PDFversion> might not exist");
146 }
148 bool new_textToPath = FALSE;
149 try {
150 new_textToPath = mod->get_param_bool("textToPath");
151 }
152 catch(...) {
153 g_warning("Parameter <textToPath> might not exist");
154 }
156 bool new_textToLaTeX = FALSE;
157 try {
158 new_textToLaTeX = mod->get_param_bool("textToLaTeX");
159 }
160 catch(...) {
161 g_warning("Parameter <textToLaTeX> might not exist");
162 }
164 bool new_blurToBitmap = FALSE;
165 try {
166 new_blurToBitmap = mod->get_param_bool("blurToBitmap");
167 }
168 catch(...) {
169 g_warning("Parameter <blurToBitmap> might not exist");
170 }
172 int new_bitmapResolution = 72;
173 try {
174 new_bitmapResolution = mod->get_param_int("resolution");
175 }
176 catch(...) {
177 g_warning("Parameter <resolution> might not exist");
178 }
180 const gchar *new_exportId = NULL;
181 try {
182 new_exportId = mod->get_param_string("exportId");
183 }
184 catch(...) {
185 g_warning("Parameter <exportId> might not exist");
186 }
188 bool new_exportDrawing = FALSE;
189 try {
190 new_exportDrawing = mod->get_param_bool("areaDrawing");
191 }
192 catch(...) {
193 g_warning("Parameter <areaDrawing> might not exist");
194 }
196 bool new_exportCanvas = FALSE;
197 try {
198 new_exportCanvas = mod->get_param_bool("areaPage");
199 }
200 catch(...) {
201 g_warning("Parameter <exportCanvas> might not exist");
202 }
204 // Create PDF file
205 {
206 gchar * final_name;
207 final_name = g_strdup_printf("> %s", filename);
208 ret = pdf_render_document_to_file(doc, final_name, level,
209 new_textToPath, new_textToLaTeX, new_blurToBitmap, new_bitmapResolution,
210 new_exportId, new_exportDrawing, new_exportCanvas);
211 g_free(final_name);
213 if (!ret)
214 throw Inkscape::Extension::Output::save_failed();
215 }
217 // Create LaTeX file (if requested)
218 if (new_textToLaTeX) {
219 ret = latex_render_document_text_to_file(doc, filename, new_exportId, new_exportDrawing, new_exportCanvas, true);
221 if (!ret)
222 throw Inkscape::Extension::Output::save_failed();
223 }
224 }
226 #include "clear-n_.h"
228 /**
229 \brief A function allocate a copy of this function.
231 This is the definition of Cairo PDF out. This function just
232 calls the extension system with the memory allocated XML that
233 describes the data.
234 */
235 void
236 CairoRendererPdfOutput::init (void)
237 {
238 Inkscape::Extension::build_from_mem(
239 "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
240 "<name>Portable Document Format</name>\n"
241 "<id>org.inkscape.output.pdf.cairorenderer</id>\n"
242 "<param name=\"PDFversion\" gui-text=\"" N_("Restrict to PDF version:") "\" type=\"enum\" >\n"
243 #if (CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 10, 0))
244 "<_item value='PDF-1.5'>" N_("PDF 1.5") "</_item>\n"
245 #endif
246 "<_item value='PDF-1.4'>" N_("PDF 1.4") "</_item>\n"
247 "</param>\n"
248 "<param name=\"textToPath\" gui-text=\"" N_("Convert texts to paths") "\" type=\"boolean\">false</param>\n"
249 "<param name=\"textToLaTeX\" gui-text=\"" N_("PDF+LaTeX: Omit text in PDF, and create LaTeX file") "\" type=\"boolean\">false</param>\n"
250 "<param name=\"blurToBitmap\" gui-text=\"" N_("Rasterize filter effects") "\" type=\"boolean\">true</param>\n"
251 "<param name=\"resolution\" gui-text=\"" N_("Resolution for rasterization (dpi):") "\" type=\"int\" min=\"1\" max=\"10000\">90</param>\n"
252 "<param name=\"areaDrawing\" gui-text=\"" N_("Export area is drawing") "\" type=\"boolean\">false</param>\n"
253 "<param name=\"areaPage\" gui-text=\"" N_("Export area is page") "\" type=\"boolean\">false</param>\n"
254 "<param name=\"exportId\" gui-text=\"" N_("Limit export to the object with ID:") "\" type=\"string\"></param>\n"
255 "<output>\n"
256 "<extension>.pdf</extension>\n"
257 "<mimetype>application/pdf</mimetype>\n"
258 "<filetypename>Portable Document Format (*.pdf)</filetypename>\n"
259 "<filetypetooltip>PDF File</filetypetooltip>\n"
260 "</output>\n"
261 "</inkscape-extension>", new CairoRendererPdfOutput());
263 return;
264 }
266 } } } /* namespace Inkscape, Extension, Internal */
268 #endif /* HAVE_CAIRO_PDF */