Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
pdf-output.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Provide a capypdf exporter for Inkscape
4 *
5 * Authors:
6 * Martin Owens <doctormo@geek-2.com>
7 *
8 * Copyright (C) 2024 Authors
9 *
10 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
11 */
12
13#include "pdf-output.h"
14
15#include "build-document.h"
16#include "build-page.h"
17#include "document.h"
18#include "extension/db.h"
20#include "extension/output.h"
21#include "extension/system.h"
22#include "inkscape-version.h"
23#include "object/sp-page.h"
24#include "object/sp-root.h"
25#include "page-manager.h"
26#include "path-chemistry.h"
27#include "rdf.h"
28
30
32{
33 return Inkscape::Extension::db.get("org.inkscape.output.pdf.capypdf");
34}
35
39void PdfOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, char const *filename)
40{
41 capypdf::DocumentProperties opt;
42
43 auto root = doc->getRoot();
44 if (!root) {
45 g_error("Couldn't save PDF, no document root");
46 return;
47 }
48
49 if (char const *title = rdf_get_work_entity(doc, rdf_find_entity("title"))) {
50 opt.set_title(title);
51 }
52 if (char const *author = rdf_get_work_entity(doc, rdf_find_entity("creator"))) {
53 opt.set_author(author);
54 }
55 if (char const *subject = rdf_get_work_entity(doc, rdf_find_entity("description"))) {
56 // Nothing to set yet.
57 }
58 if (char const *keywords = rdf_get_work_entity(doc, rdf_find_entity("subject"))) {
59 // Nothing to set yet.
60 }
61 if (char const *copyright = rdf_get_work_entity(doc, rdf_find_entity("rights"))) {
62 // Nothing to set yet.
63 }
64
65 auto creator =
66 Glib::ustring::compose("Inkscape %1 (https://inkscape.org)", Inkscape::version_string_without_revision);
67 opt.set_creator(creator.c_str());
68
69 // TODO: This API currently doesn't work well for us
70 // opt.set_colorspace(CAPY_DEVICE_CS_CMYK);
71 // opt.set_device_profile(DEVICE_COLORSPACE, icc_profile);
72
73 auto pdf = PdfBuilder::Document(filename, opt);
74 if (mod->get_param_bool("blurToBitmap")) {
75 pdf.set_filter_resolution(mod->get_param_int("resolution"));
76 }
77 if (mod->get_param_optiongroup_is("textToPath", "paths")) {
79 } else if (mod->get_param_optiongroup_is("textToPath", "LaTeX")) {
80 pdf.set_text_enabled(false);
81 if (!latex_render_document_text_to_file(doc, filename, true)) {
83 }
84 }
85
86 // Step 1. Render EVERYTHING in the document out to a single PDF TransparencyGroup
87 // This allows the page "positions" to be stored by the offset of the group.
88 auto group_ctx = PdfBuilder::ItemContext(pdf, root);
89 auto drawing_id = pdf.add_group(group_ctx);
90
91 // FUTURE: If in the future we want PDF files where the items on a page are rendered only
92 // in the group for that page, then we have two mechanisms for page separation.
93 // a. Find out if two pages share the same objects, and if they do, use the same root-group
94 // b. Find out if an object is shared by two pages and force it to use a transparency group
95 // at the most useful level. i.e. all children are shared thus share the parent group.
96
97 // Step 2. Enable pages for this document. It SHOULD be a copy by this stage
98 auto &pm = doc->getPageManager();
99 pm.enablePages();
100
101 uint32_t page = 0;
102 // Step 3. Tell the PDF where to draw that whole plate on the PDF pages
103 for (auto const &svg_page : pm.getPages()) {
104 auto pdf_page = PdfBuilder::PageContext(pdf, svg_page);
105
106 if (!svg_page->isBarePage()) {
107 pdf_page.set_pagebox(CAPY_BOX_BLEED, svg_page->getDocumentRect());
108 pdf_page.set_pagebox(CAPY_BOX_TRIM, svg_page->getDocumentRect());
109 pdf_page.set_pagebox(CAPY_BOX_ART, svg_page->getDocumentMargin());
110 }
111
112 if (auto label = svg_page->label()) {
113 pdf.set_label(page, label);
114 }
115
116 if (drawing_id) {
117 pdf_page.paint_drawing(*drawing_id, doc->getRoot()->c2p);
118 }
119 // Page links / anchors / annotations are added in post processing.
120 pdf_page.add_anchors_for_page(svg_page);
121 pdf.add_page(pdf_page);
122 page++;
123 }
124 try {
125 pdf.write();
126 } catch (std::exception &ex) {
127 g_warning("Couldn't save pdf file: %s", ex.what());
128 }
129}
130
131#include "../clear-n_.h"
132
134{
135 // clang-format off
137 "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
138 "<name>Portable Document Format</name>\n"
139 "<id>org.inkscape.output.pdf.capypdf</id>\n"
140 "<param name=\"PDFversion\" gui-text=\"" N_("Restrict to PDF version:") "\" type=\"optiongroup\" appearance=\"combo\" >\n"
141 "<option value='PDF-1.7'>" N_("PDF 1.7") "</option>\n"
142 // No other value is supported at the moment
143 "</param>\n"
144 "<param name=\"textToPath\" gui-text=\"" N_("Text output options:") "\" type=\"optiongroup\" appearance=\"radio\">\n"
145 "<option value=\"embed\">" N_("Embed fonts") "</option>\n"
146 "<option value=\"paths\">" N_("Convert text to paths") "</option>\n"
147 "<option value=\"LaTeX\">" N_("Omit text in PDF and create LaTeX file") "</option>\n"
148 "</param>\n"
149 "<param name=\"blurToBitmap\" gui-text=\"" N_("Rasterize filter effects") "\" type=\"bool\">true</param>\n"
150 "<param name=\"resolution\" gui-text=\"" N_("Resolution for rasterization (dpi):") "\" type=\"int\" min=\"1\" max=\"10000\">96</param>\n"
151 "<output is_exported='true' priority='4'>\n"
152 "<extension>.pdf</extension>\n"
153 "<mimetype>application/pdf</mimetype>\n"
154 "<filetypename>PDF (*.pdf)</filetypename>\n"
155 "<filetypetooltip>PDF File</filetypetooltip>\n"
156 "</output>\n"
157 "</inkscape-extension>", std::make_unique<PdfOutput>());
158 // clang-format on
159}
160
161} // namespace Inkscape::Extension::Internal
void pdf_page(int page)
uint64_t page
Definition canvas.cpp:171
Extension * get(const gchar *key) const
This function looks up a Inkscape::Extension::Extension by using its unique id. It then returns a ref...
Definition db.cpp:101
The object that is the basis for the Extension system.
Definition extension.h:133
bool check(Inkscape::Extension::Extension *module) override
Verify any dependencies.
void save(Inkscape::Extension::Output *mod, SPDocument *doc, char const *filename) override
Save the PDF file.
Generic failure for an undescribed reason.
Definition output.h:34
void enablePages()
Enables multi page support by turning the document viewBox into the first page.
Typed SVG document implementation.
Definition document.h:101
SPRoot * getRoot()
Returns our SPRoot.
Definition document.h:200
Inkscape::PageManager & getPageManager()
Definition document.h:162
Geom::Affine c2p
Definition viewbox.h:43
RootCluster root
Mini static library that contains the version of Inkscape.
Declaration of LaTeXTextRenderer, used for rendering the accompanying LaTeX file when exporting to PD...
Glib::ustring label
bool latex_render_document_text_to_file(SPDocument *doc, gchar const *filename, bool pdflatex)
This method is called by the PDF, EPS and PS output extensions.
DB db
This is the actual database object.
Definition db.cpp:32
void build_from_mem(gchar const *buffer, std::unique_ptr< Implementation::Implementation > in_imp)
Create a module from a buffer holding an XML description.
Definition system.cpp:459
char const * version_string_without_revision
version string excluding revision and date
void convert_text_to_curves(SPDocument *)
Convert all text in the document to path, in-place.
struct rdf_work_entity_t * rdf_find_entity(gchar const *name)
Retrieves a known RDF/Work entity by name.
Definition rdf.cpp:364
const gchar * rdf_get_work_entity(SPDocument const *doc, struct rdf_work_entity_t *entity)
Retrieves a known RDF/Work entity's contents from the document XML by name.
Definition rdf.cpp:885
headers for RDF types
SPPage – a page object.
SPRoot: SVG <svg> implementation.