summaryrefslogtreecommitdiffstats
path: root/src/ui/dialog/print.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/ui/dialog/print.cpp262
1 files changed, 262 insertions, 0 deletions
diff --git a/src/ui/dialog/print.cpp b/src/ui/dialog/print.cpp
new file mode 100644
index 0000000..0cbc49c
--- /dev/null
+++ b/src/ui/dialog/print.cpp
@@ -0,0 +1,262 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/**
+ * @file
+ * Print dialog.
+ */
+/* Authors:
+ * Kees Cook <kees@outflux.net>
+ * Abhishek Sharma
+ * Patrick McDermott
+ *
+ * Copyright (C) 2007 Kees Cook
+ * Copyright (C) 2017 Patrick McDermott
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include <cmath>
+
+#include <gtkmm.h>
+
+#include "inkscape.h"
+#include "preferences.h"
+#include "print.h"
+
+#include "extension/internal/cairo-render-context.h"
+#include "extension/internal/cairo-renderer.h"
+#include "document.h"
+
+#include "util/units.h"
+#include "helper/png-write.h"
+#include "svg/svg-color.h"
+
+#include <glibmm/i18n.h>
+
+
+namespace Inkscape {
+namespace UI {
+namespace Dialog {
+
+Print::Print(SPDocument *doc, SPItem *base) :
+ _doc (doc),
+ _base (base)
+{
+ g_assert (_doc);
+ g_assert (_base);
+
+ _printop = Gtk::PrintOperation::create();
+
+ // set up dialog title, based on document name
+ const Glib::ustring jobname = _doc->getDocumentName() ? _doc->getDocumentName() : _("SVG Document");
+ Glib::ustring title = _("Print");
+ title += " ";
+ title += jobname;
+ _printop->set_job_name(title);
+
+ _printop->set_unit(Gtk::UNIT_POINTS);
+ Glib::RefPtr<Gtk::PageSetup> page_setup = Gtk::PageSetup::create();
+
+ // Default to a custom paper size, in case we can't find a more specific size
+ gdouble doc_width = _doc->getWidth().value("pt");
+ gdouble doc_height = _doc->getHeight().value("pt");
+ page_setup->set_paper_size(
+ Gtk::PaperSize("custom", "custom", doc_width, doc_height, Gtk::UNIT_POINTS));
+
+ // Some print drivers, like the EPSON's ESC/P-R CUPS driver, don't accept custom
+ // page sizes, so we'll try to find a known page size.
+ // GTK+'s known paper sizes always have a longer height than width, so we'll rotate
+ // the page and set its orientation to landscape as necessary in order to match a paper size.
+ // Unfortunately, some printers, like Epilog laser cutters, don't understand landscape
+ // mode.
+ // As a compromise, we'll only rotate the page if we actually find a matching paper size,
+ // since laser cutter beds tend to be custom sizes.
+ Gtk::PageOrientation orientation = Gtk::PAGE_ORIENTATION_PORTRAIT;
+ if (_doc->getWidth().value("pt") > _doc->getHeight().value("pt")) {
+ orientation = Gtk::PAGE_ORIENTATION_REVERSE_LANDSCAPE;
+ std::swap(doc_width, doc_height);
+ }
+
+ // attempt to match document size against known paper sizes
+ std::vector<Gtk::PaperSize> known_sizes = Gtk::PaperSize::get_paper_sizes(false);
+ for (auto& size : known_sizes) {
+ if (fabs(size.get_width(Gtk::UNIT_POINTS) - doc_width) >= 1.0) {
+ // width (short edge) doesn't match
+ continue;
+ }
+ if (fabs(size.get_height(Gtk::UNIT_POINTS) - doc_height) >= 1.0) {
+ // height (short edge) doesn't match
+ continue;
+ }
+ // size matches
+ page_setup->set_paper_size(size);
+ page_setup->set_orientation(orientation);
+ break;
+ }
+
+ _printop->set_default_page_setup(page_setup);
+ _printop->set_use_full_page(true);
+
+ // set up signals
+ _workaround._doc = _doc;
+ _workaround._base = _base;
+ _workaround._tab = &_tab;
+ _printop->signal_create_custom_widget().connect(sigc::mem_fun(*this, &Print::create_custom_widget));
+ _printop->signal_begin_print().connect(sigc::mem_fun(*this, &Print::begin_print));
+ _printop->signal_draw_page().connect(sigc::mem_fun(*this, &Print::draw_page));
+
+ // build custom preferences tab
+ _printop->set_custom_tab_label(_("Rendering"));
+}
+
+void Print::draw_page(const Glib::RefPtr<Gtk::PrintContext>& context, int /*page_nr*/)
+{
+ // TODO: If the user prints multiple copies we render the whole page for each copy
+ // It would be more efficient to render the page once (e.g. in "begin_print")
+ // and simply print this result as often as necessary
+
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ //printf("%s %d\n",__FUNCTION__, page_nr);
+
+ if (_workaround._tab->as_bitmap()) {
+ // Render as exported PNG
+ prefs->setBool("/dialogs/printing/asbitmap", true);
+ gdouble width = (_workaround._doc)->getWidth().value("px");
+ gdouble height = (_workaround._doc)->getHeight().value("px");
+ gdouble dpi = _workaround._tab->bitmap_dpi();
+ prefs->setDouble("/dialogs/printing/dpi", dpi);
+
+ std::string tmp_png;
+ std::string tmp_base = "inkscape-print-png-XXXXXX";
+
+ int tmp_fd;
+ if ( (tmp_fd = Glib::file_open_tmp(tmp_png, tmp_base)) >= 0) {
+ close(tmp_fd);
+
+ guint32 bgcolor = 0x00000000;
+ Inkscape::XML::Node *nv = _workaround._doc->getReprNamedView();
+ if (nv && nv->attribute("pagecolor")){
+ bgcolor = sp_svg_read_color(nv->attribute("pagecolor"), 0xffffff00);
+ }
+ if (nv && nv->attribute("inkscape:pageopacity")){
+ double opacity = nv->getAttributeDouble("inkscape:pageopacity", 1.0);
+ bgcolor |= SP_COLOR_F_TO_U(opacity);
+ }
+
+ sp_export_png_file(_workaround._doc, tmp_png.c_str(), 0.0, 0.0,
+ width, height,
+ (unsigned long)(Inkscape::Util::Quantity::convert(width, "px", "in") * dpi),
+ (unsigned long)(Inkscape::Util::Quantity::convert(height, "px", "in") * dpi),
+ dpi, dpi, bgcolor, nullptr, nullptr, true, std::vector<SPItem*>());
+
+ // This doesn't seem to work:
+ //context->set_cairo_context ( Cairo::Context::create (Cairo::ImageSurface::create_from_png (tmp_png) ), dpi, dpi );
+ //
+ // so we'll use a surface pattern blat instead...
+ //
+ // but the C++ interface isn't implemented in cairomm:
+ //context->get_cairo_context ()->set_source_surface(Cairo::ImageSurface::create_from_png (tmp_png) );
+ //
+ // so do it in C:
+ {
+ auto png = Cairo::ImageSurface::create_from_png(tmp_png);
+ auto pattern = Cairo::SurfacePattern::create(png);
+ auto cr = context->get_cairo_context();
+ auto m = cr->get_matrix();
+ cr->scale(Inkscape::Util::Quantity::convert(1, "in", "pt") / dpi,
+ Inkscape::Util::Quantity::convert(1, "in", "pt") / dpi);
+ // FIXME: why is the origin offset??
+ cr->set_source(pattern);
+ cr->paint();
+ cr->set_matrix(m);
+ }
+
+ // Clean up
+ unlink (tmp_png.c_str());
+ }
+ else {
+ g_warning("%s", _("Could not open temporary PNG for bitmap printing"));
+ }
+ }
+ else {
+ // Render as vectors
+ prefs->setBool("/dialogs/printing/asbitmap", false);
+ Inkscape::Extension::Internal::CairoRenderer renderer;
+ Inkscape::Extension::Internal::CairoRenderContext *ctx = renderer.createContext();
+
+ // ctx->setPSLevel(CAIRO_PS_LEVEL_3);
+ ctx->setTextToPath(false);
+ ctx->setFilterToBitmap(true);
+ ctx->setBitmapResolution(72);
+
+ auto cr = context->get_cairo_context();
+ auto surface = cr->get_target();
+ auto ctm = cr->get_matrix();
+
+ bool ret = ctx->setSurfaceTarget(surface->cobj(), true, &ctm);
+ if (ret) {
+ ret = renderer.setupDocument (ctx, _workaround._doc, TRUE, 0., nullptr);
+ if (ret) {
+ renderer.renderItem(ctx, _workaround._base);
+ ctx->finish(false); // do not finish the cairo_surface_t - it's owned by our GtkPrintContext!
+ }
+ else {
+ g_warning("%s", _("Could not set up Document"));
+ }
+ }
+ else {
+ g_warning("%s", _("Failed to set CairoRenderContext"));
+ }
+
+ // Clean up
+ renderer.destroyContext(ctx);
+ }
+
+}
+
+Gtk::Widget *Print::create_custom_widget()
+{
+ //printf("%s\n",__FUNCTION__);
+ return &_tab;
+}
+
+void Print::begin_print(const Glib::RefPtr<Gtk::PrintContext>&)
+{
+ //printf("%s\n",__FUNCTION__);
+ _printop->set_n_pages(1);
+}
+
+Gtk::PrintOperationResult Print::run(Gtk::PrintOperationAction, Gtk::Window &parent_window)
+{
+ // Remember to restore the previous print settings
+ _printop->set_print_settings(SP_ACTIVE_DESKTOP->printer_settings._gtk_print_settings);
+
+ try {
+ Gtk::PrintOperationResult res = _printop->run(Gtk::PRINT_OPERATION_ACTION_PRINT_DIALOG, parent_window);
+
+ // Save printer settings (but only on success)
+ if (res == Gtk::PRINT_OPERATION_RESULT_APPLY) {
+ SP_ACTIVE_DESKTOP->printer_settings._gtk_print_settings = _printop->get_print_settings();
+ }
+
+ return res;
+ } catch (const Glib::Error &e) {
+ g_warning("Failed to print '%s': %s", _doc->getDocumentName(), e.what().c_str());
+ }
+
+ return Gtk::PRINT_OPERATION_RESULT_ERROR;
+}
+
+
+} // namespace Dialog
+} // namespace UI
+} // namespace Inkscape
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :