From: keescook Date: Mon, 10 Dec 2007 05:29:23 +0000 (+0000) Subject: Implement cross-architecture print dialog using cairo and PNG backends. X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=f8126a79cb9116058bdaaa62ee7fd203234ff897;p=inkscape.git Implement cross-architecture print dialog using cairo and PNG backends. --- diff --git a/configure.ac b/configure.ac index 4db01b5dd..4de46fdc8 100644 --- a/configure.ac +++ b/configure.ac @@ -594,11 +594,6 @@ if test "x$cairo_pdf" = "xyes"; then AC_DEFINE(HAVE_CAIRO_PDF, 1, [Whether the Cairo PDF backend is available]) fi -PKG_CHECK_MODULES(GTK_UNIX_PRINT, gtk+-unix-print-2.0, gtk_unix_print=yes, gtk_unix_print=no) -if test "x$gtk_unix_print" = "xyes"; then - AC_DEFINE(HAVE_GTK_UNIX_PRINT, 1, [Whether the GTK Unix printing backend is available]) -fi - dnl Shouldn't we test for libpng and libz? INKSCAPE_LIBS="$INKSCAPE_LIBS -lpng -lz" diff --git a/src/Makefile.am b/src/Makefile.am index 9eb9e1693..0c84fe7b8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -21,7 +21,6 @@ INCLUDES = \ $(INKBOARD_CFLAGS) \ $(LIBWPG_CFLAGS) \ $(XFT_CFLAGS) \ - $(GTK_UNIX_PRINT_CFLAGS) \ $(POPPLER_CFLAGS) \ $(POPPLER_GLIB_CFLAGS) \ -DPOTRACE=\"potrace\" \ diff --git a/src/extension/internal/cairo-render-context.cpp b/src/extension/internal/cairo-render-context.cpp index 8f106f55f..8511973e4 100644 --- a/src/extension/internal/cairo-render-context.cpp +++ b/src/extension/internal/cairo-render-context.cpp @@ -647,6 +647,10 @@ CairoRenderContext::addClippingRect(double x, double y, double width, double hei bool CairoRenderContext::setupSurface(double width, double height) { + // Is the surface already set up? + if (_is_valid) + return true; + if (_vector_based_target && _stream == NULL) return false; @@ -674,11 +678,12 @@ CairoRenderContext::setupSurface(double width, double height) } bool -CairoRenderContext::setSurface(cairo_surface_t *surface) +CairoRenderContext::setSurfaceTarget(cairo_surface_t *surface, bool is_vector) { if (_is_valid || !surface) return false; + _vector_based_target = is_vector; bool ret = _finishSurfaceSetup (surface); if (ret) cairo_surface_reference (surface); @@ -724,7 +729,7 @@ CairoRenderContext::finish(void) _is_valid = FALSE; - if (_vector_based_target) { + if (_vector_based_target && _stream) { /* Flush stream to be sure. */ (void) fflush(_stream); diff --git a/src/extension/internal/cairo-render-context.h b/src/extension/internal/cairo-render-context.h index ff7ebec7f..e3cbbad8a 100644 --- a/src/extension/internal/cairo-render-context.h +++ b/src/extension/internal/cairo-render-context.h @@ -83,13 +83,13 @@ public: bool setImageTarget(cairo_format_t format); bool setPdfTarget(gchar const *utf8_fn); bool setPsTarget(gchar const *utf8_fn); + /** Set the cairo_surface_t from an external source */ + bool setSurfaceTarget(cairo_surface_t *surface, bool is_vector); /** Creates the cairo_surface_t for the context with the given width, height and with the currently set target surface type. */ bool setupSurface(double width, double height); - /** Set the cairo_surface_t from an external source */ - bool setSurface(cairo_surface_t *surface); cairo_surface_t *getSurface(void); diff --git a/src/print.cpp b/src/print.cpp index 4252298a4..9fc1285a5 100644 --- a/src/print.cpp +++ b/src/print.cpp @@ -6,6 +6,7 @@ /* * Author: * Lauris Kaplinski + * Kees Cook * * This code is in public domain */ @@ -14,31 +15,15 @@ # include "config.h" #endif - - +#include "inkscape.h" +#include "desktop.h" #include "sp-item.h" #include "extension/print.h" #include "extension/system.h" #include "print.h" -#include +#include "ui/dialog/print.h" -#ifdef HAVE_GTK_UNIX_PRINT -# include -# include -# include -# include // close, unlink -# include -using std::fprintf; -#endif - -#if 0 -# include - -# ifdef WIN32 -# include -# endif -#endif /* Identity typedef */ @@ -137,164 +122,25 @@ sp_print_preview_document(SPDocument *doc) return; } -#ifdef HAVE_GTK_UNIX_PRINT -static void -unix_print_complete (GtkPrintJob */*print_job*/, - gpointer /*user_data*/, - GError *error) -{ - fprintf(stderr,"print job finished: %s\n",error ? error->message : "no error"); -} - -static void -unix_print_dialog (const gchar * ps_file, const gchar * jobname, gdouble doc_width, gdouble doc_height) -{ - Glib::ustring title = _("Print"); - title += " "; - title += jobname; - GtkWidget* dlg = gtk_print_unix_dialog_new(title.c_str(), NULL); - - // force output system to only handle our pre-generated PS output - gtk_print_unix_dialog_set_manual_capabilities (GTK_PRINT_UNIX_DIALOG(dlg), - GTK_PRINT_CAPABILITY_GENERATE_PS); - -/* - * It would be nice to merge the PrintPS::setup routine with a custom - * configuration dialog: - - gtk_print_unix_dialog_add_custom_tab (GtkPrintUnixDialog *dialog, - GtkWidget *child, - GtkWidget *tab_label); -*/ - - int const response = gtk_dialog_run(GTK_DIALOG(dlg)); - - if (response == GTK_RESPONSE_OK) { - GtkPrinter* printer = gtk_print_unix_dialog_get_selected_printer(GTK_PRINT_UNIX_DIALOG(dlg)); - - if (gtk_printer_accepts_ps (printer)) { - GtkPageSetup *page_setup = gtk_print_unix_dialog_get_page_setup(GTK_PRINT_UNIX_DIALOG(dlg)); - - //It's important to set the right paper size here, otherwise it will - //default to letter; if for example an A4 is printed as a letter, then - //part of it will be truncated even when printing on A4 paper - - //TODO: let the user decide upon the paper size, by enabling - //the drop down widget in the printing dialog. For now, we'll simply - //take the document's dimensions and communicate these to the printer - //driver - - GtkPaperSize *page_size = gtk_paper_size_new_custom("custom", "custom", doc_width, doc_height, GTK_UNIT_POINTS); - - gtk_page_setup_set_paper_size (page_setup, page_size); - - GtkPrintJob* job = gtk_print_job_new (jobname, printer, - gtk_print_unix_dialog_get_settings(GTK_PRINT_UNIX_DIALOG(dlg)), - page_setup); - - GtkPaperSize* tmp = gtk_page_setup_get_paper_size(gtk_print_unix_dialog_get_page_setup(GTK_PRINT_UNIX_DIALOG(dlg))); - (void)tmp; - - GError * error = NULL; - if ( gtk_print_job_set_source_file (job, ps_file, &error)) { - gtk_print_job_send (job, unix_print_complete, NULL, NULL); - } - else { - g_warning(_("Could not set print source: %s"),error ? error->message : _("unknown error")); - } - if (error) g_error_free(error); - } - else { - g_warning(_("Printer '%s' does not support PS output"), gtk_printer_get_name (printer)); - } - } - else if (response == GTK_RESPONSE_APPLY) { - // since we didn't include the Preview capability, - // this should never happen. - g_warning(_("Print Preview not available")); - } - - gtk_widget_destroy(dlg); -} -#endif // HAVE_GTK_UNIX_PRINT - - void sp_print_document(SPDocument *doc, unsigned int direct) { - Inkscape::Extension::Print *mod; - unsigned int ret; -#ifdef HAVE_GTK_UNIX_PRINT - Glib::ustring tmpfile = ""; -#endif - sp_document_ensure_up_to_date(doc); - if (direct) { - mod = Inkscape::Extension::get_print(SP_MODULE_KEY_PRINT_PS); - } else { - mod = Inkscape::Extension::get_print(SP_MODULE_KEY_PRINT_DEFAULT); - -#ifdef HAVE_GTK_UNIX_PRINT - // unix print dialog reads from the exported tempfile - gchar *filename = NULL; - GError *error = NULL; - gint tmpfd = g_file_open_tmp("inkscape-ps-XXXXXX", - &filename, - &error); - if (tmpfd<0) { - g_warning(_("Failed to create tempfile for printing: %s"), - error ? error->message : _("unknown error")); - if (error) g_error_free(error); - return; - } - tmpfile = filename; - g_free(filename); - close(tmpfd); - - Glib::ustring destination = ">" + tmpfile; - mod->set_param_string("destination", destination.c_str()); -#endif - } - - ret = mod->setup(); - - if (ret) { - SPPrintContext context; - context.module = mod; - - /* fixme: This has to go into module constructor somehow */ - /* Create new arena */ - mod->base = SP_ITEM(sp_document_root(doc)); - mod->arena = NRArena::create(); - mod->dkey = sp_item_display_key_new(1); - mod->root = sp_item_invoke_show(mod->base, mod->arena, mod->dkey, SP_ITEM_SHOW_DISPLAY); - /* Print document */ - ret = mod->begin(doc); - sp_item_invoke_print(mod->base, &context); - ret = mod->finish(); - /* Release arena */ - sp_item_invoke_hide(mod->base, mod->dkey); - mod->base = NULL; - nr_arena_item_unref(mod->root); - mod->root = NULL; - nr_object_unref((NRObject *) mod->arena); - mod->arena = NULL; - -#ifdef HAVE_GTK_UNIX_PRINT - // redirect output to new print dialog + // Build arena + SPItem *base = SP_ITEM(sp_document_root(doc)); + NRArena *arena = NRArena::create(); + unsigned int dkey = sp_item_display_key_new(1); + NRArenaItem *root = sp_item_invoke_show(base, arena, dkey, SP_ITEM_SHOW_DISPLAY); - // width and height in pt - gdouble width = sp_document_width(doc) * PT_PER_PX; - gdouble height = sp_document_height(doc) * PT_PER_PX; + // Run print dialog + Inkscape::UI::Dialog::Print printop(doc,base); + Gtk::PrintOperationResult res = printop.run(Gtk::PRINT_OPERATION_ACTION_PRINT_DIALOG); - unix_print_dialog(tmpfile.c_str(),doc->name ? doc->name : _("SVG Document"), width, height); - unlink(tmpfile.c_str()); - // end redirected new print dialog -#endif - } - - return; + // Release arena + sp_item_invoke_hide(base, dkey); + nr_arena_item_unref(root); + nr_object_unref((NRObject *) arena); } void diff --git a/src/ui/dialog/Makefile_insert b/src/ui/dialog/Makefile_insert index 64b8a3b04..f72838c7f 100644 --- a/src/ui/dialog/Makefile_insert +++ b/src/ui/dialog/Makefile_insert @@ -46,6 +46,8 @@ ui_dialog_libuidialog_a_SOURCES = \ ui/dialog/memory.h \ ui/dialog/messages.cpp \ ui/dialog/messages.h \ + ui/dialog/print.cpp \ + ui/dialog/print.h \ ui/dialog/scriptdialog.cpp \ ui/dialog/scriptdialog.h \ ui/dialog/text-properties.cpp \ diff --git a/src/ui/dialog/print.cpp b/src/ui/dialog/print.cpp new file mode 100644 index 000000000..979b0522d --- /dev/null +++ b/src/ui/dialog/print.cpp @@ -0,0 +1,170 @@ +/** + * \brief Print dialog + * + * Authors: + * Kees Cook + * + * Copyright (C) 2007 Kees Cook + * + * Released under GNU GPL. Read the file 'COPYING' for more information. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "print.h" + +#include "extension/internal/cairo-render-context.h" +#include "extension/internal/cairo-renderer.h" +#include "ui/widget/rendering-options.h" + +#include "unit-constants.h" +#include "helper/png-write.h" +#include "svg/svg-color.h" + +namespace Inkscape { +namespace UI { +namespace Dialog { + +void +Print::_draw_page (const Glib::RefPtr &context, + int page_nr) +{ + if (_tab.as_bitmap()) { + // Render as exported PNG + gdouble width = sp_document_width(_doc); + gdouble height = sp_document_height(_doc); + gdouble dpi = _tab.bitmap_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 = sp_repr_lookup_name (_doc->rroot, "sodipodi:namedview"); + if (nv && nv->attribute("pagecolor")) + bgcolor = sp_svg_read_color(nv->attribute("pagecolor"), 0xffffff00); + if (nv && nv->attribute("inkscape:pageopacity")) + bgcolor |= SP_COLOR_F_TO_U(sp_repr_get_double_attribute (nv, "inkscape:pageopacity", 1.0)); + + sp_export_png_file(_doc, tmp_png.c_str(), 0.0, 0.0, + width, height, + (unsigned long)width * dpi / PX_PER_IN, + (unsigned long)height * dpi / PX_PER_IN, + dpi, dpi, bgcolor, NULL, NULL, true, NULL); + + // 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: + { + Cairo::RefPtr png = Cairo::ImageSurface::create_from_png (tmp_png); + cairo_t *cr = context->get_cairo_context ()->cobj(); + // FIXME: why is the origin offset?? + cairo_set_source_surface(cr, png->cobj(), -20.0, -20.0); + } + context->get_cairo_context ()->paint (); + + // Clean up + unlink (tmp_png.c_str()); + } + else { + g_warning(_("Could not open temporary PNG for bitmap printing")); + } + } + else { + // Render as vectors + Inkscape::Extension::Internal::CairoRenderer renderer; + Inkscape::Extension::Internal::CairoRenderContext *ctx = renderer.createContext(); + bool ret = ctx->setSurfaceTarget (context->get_cairo_context ()->get_target ()->cobj(), true); + if (ret) { + ret = renderer.setupDocument (ctx, _doc); + if (ret) { + renderer.renderItem(ctx, _base); + ret = ctx->finish(); + } + else { + g_warning(_("Could not set up Document")); + } + } + else { + g_warning(_("Failed to set CairoRenderContext")); + } + + // Clean up + renderer.destroyContext(ctx); + } + +} + +Gtk::Widget * +Print::_create_custom_widget () +{ + return &_tab; +} + +void +Print::_custom_widget_apply (Gtk::Widget *widget) +{ + g_warning (_("custom widget apply")); +} + +Print::Print(SPDocument *doc, SPItem *base) : + _doc (doc), + _base (base), + _tab () +{ + g_assert (_doc); + g_assert (_base); + + _printop = Gtk::PrintOperation::create(); + + // set up dialog title, based on document name + gchar *jobname = _doc->name ? _doc->name : _("SVG Document"); + Glib::ustring title = _("Print"); + title += " "; + title += jobname; + _printop->set_job_name (title); + _printop->set_n_pages (1); + + // set up paper size to match the document size + Glib::RefPtr page_setup = Gtk::PageSetup::create(); + gdouble doc_width = sp_document_width(_doc) * PT_PER_PX; + gdouble doc_height = sp_document_height(_doc) * PT_PER_PX; + Gtk::PaperSize paper_size(Glib::ustring("custom"), Glib::ustring("custom"), + doc_width, doc_height, Gtk::UNIT_POINTS); + page_setup->set_paper_size (paper_size); + _printop->set_default_page_setup (page_setup); + + // build custom preferences tab + _printop->set_custom_tab_label (Glib::ustring(_("Rendering"))); + _printop->signal_create_custom_widget().connect(sigc::mem_fun(*this, &Print::_create_custom_widget)); +// _printop->signal_custom_widget_apply().connect(sigc::mem_fun(*this, &Print::_custom_widget_apply)); + + // register actual page surface drawing callback + _printop->signal_draw_page().connect(sigc::mem_fun(*this, &Print::_draw_page)); + +} + +Gtk::PrintOperationResult +Print::run(Gtk::PrintOperationAction action) +{ + Gtk::PrintOperationResult res; + res = _printop->run (action); + return res; +} + + +} // namespace Dialog +} // namespace UI +} // namespace Inkscape + diff --git a/src/ui/dialog/print.h b/src/ui/dialog/print.h new file mode 100644 index 000000000..d893efbf1 --- /dev/null +++ b/src/ui/dialog/print.h @@ -0,0 +1,66 @@ +/** + * \brief Print dialog + * + * Authors: + * Kees Cook + * + * Copyright (C) 2007 Kees Cook + * + * Released under GNU GPL. Read the file 'COPYING' for more information. + */ + +#ifndef INKSCAPE_UI_DIALOG_PRINT_H +#define INKSCAPE_UI_DIALOG_PRINT_H + +#include +#include // GtkMM +#include // Gtk + +#include "desktop.h" +#include "sp-item.h" + +#include "ui/widget/rendering-options.h" + + +namespace Inkscape { +namespace UI { +namespace Dialog { + +class Print { +public: + Print(SPDocument *doc, SPItem *base); + + Gtk::PrintOperationResult run(Gtk::PrintOperationAction action); + //GtkPrintOperationResult run(GtkPrintOperationAction action); + +protected: + Glib::RefPtr _printop; + //GtkPrintOperation *_printop; + + Gtk::Widget *_create_custom_widget (); + void _custom_widget_apply (Gtk::Widget *widget); + void _draw_page (const Glib::RefPtr &context, + int page_nr); + +private: + SPDocument *_doc; + SPItem *_base; + Inkscape::UI::Widget::RenderingOptions _tab; +}; + +} // namespace Dialog +} // namespace UI +} // namespace Inkscape + +#endif // INKSCAPE_UI_DIALOG_PRINT_H + +/* + 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:encoding=utf-8:textwidth=99 : diff --git a/src/ui/widget/Makefile_insert b/src/ui/widget/Makefile_insert index c5bde795a..cfe163681 100644 --- a/src/ui/widget/Makefile_insert +++ b/src/ui/widget/Makefile_insert @@ -52,6 +52,8 @@ ui_widget_libuiwidget_a_SOURCES = \ ui/widget/registered-enums.h \ ui/widget/registry.cpp \ ui/widget/registry.h \ + ui/widget/rendering-options.cpp \ + ui/widget/rendering-options.h \ ui/widget/rotateable.h \ ui/widget/rotateable.cpp \ ui/widget/ruler.cpp \ diff --git a/src/ui/widget/rendering-options.cpp b/src/ui/widget/rendering-options.cpp new file mode 100644 index 000000000..8a00bcc5d --- /dev/null +++ b/src/ui/widget/rendering-options.cpp @@ -0,0 +1,101 @@ +/** + * \brief Rendering options widget + * + * Author: + * Kees Cook + * + * Copyright (C) 2007 Kees Cook + * Copyright (C) 2004 Bryce Harrington + * + * Released under GNU GPL. Read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "unit-constants.h" +#include "rendering-options.h" + +namespace Inkscape { +namespace UI { +namespace Widget { + +/** + * Construct a Rendering Options widget + * + */ + +RenderingOptions::RenderingOptions () : + Gtk::VBox (), + //Labelled(label, tooltip, new Gtk::VBox(), suffix, icon, mnemonic), + _radio_cairo ( new Gtk::RadioButton () ), + //_radio_bitmap( new Gtk::RadioButton (_radio_cairo->get_group ()), + _radio_bitmap( new Gtk::RadioButton () ), + _widget_cairo( Glib::ustring(_("_Cairo")), + Glib::ustring(_("Render using Cairo vector operations. The resulting image is usually smaller in file " + "size and can be arbitrarily scaled, but some " + "filter effects will not be correctly rendered.")), + _radio_cairo, + Glib::ustring(""), Glib::ustring(""), + true), + _widget_bitmap(Glib::ustring(_("_Bitmap")), + Glib::ustring(_("Render everything as bitmap. The resulting image " + "is usually larger in file size and cannot be " + "arbitrarily scaled without quality loss, but all " + "objects will be rendered exactly as displayed.")), + _radio_bitmap, + Glib::ustring(""), Glib::ustring(""), + true), + _dpi( _("DPI"), Glib::ustring(_("Preferred resolution of rendering, in dots per inch.")), + 1, + Glib::ustring(""), Glib::ustring(""), + false) +{ + set_border_width(2); + + // default to cairo operations + _radio_cairo->set_active (true); + Gtk::RadioButtonGroup group = _radio_cairo->get_group (); + _radio_bitmap->set_group (group); + + // configure default DPI + _dpi.setRange(PT_PER_IN,2400.0); + _dpi.setValue(PT_PER_IN); + + // fill up container + add (_widget_cairo); + add (_widget_bitmap); + add (_dpi); + + show_all_children (); +} + +bool +RenderingOptions::as_bitmap () +{ + return _radio_bitmap->get_active(); +} + +double +RenderingOptions::bitmap_dpi () +{ + return _dpi.getValue(); +} + +} // namespace Widget +} // namespace UI +} // namespace Inkscape + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/ui/widget/rendering-options.h b/src/ui/widget/rendering-options.h new file mode 100644 index 000000000..41134b814 --- /dev/null +++ b/src/ui/widget/rendering-options.h @@ -0,0 +1,55 @@ +/** + * \brief Rendering Options Widget - A container for selecting rendering options + * + * Author: + * Kees Cook + * + * Copyright (C) 2007 Kees Cook + * Copyright (C) 2004 Bryce Harrington + * + * Released under GNU GPL. Read the file 'COPYING' for more information. + */ + +#ifndef INKSCAPE_UI_WIDGET_RENDERING_OPTIONS_H +#define INKSCAPE_UI_WIDGET_RENDERING_OPTIONS_H + +#include "labelled.h" +#include "scalar.h" + +namespace Inkscape { +namespace UI { +namespace Widget { + +class RenderingOptions : public Gtk::VBox +{ +public: + RenderingOptions(); + + bool as_bitmap(); // should we render as a bitmap? + double bitmap_dpi(); // at what DPI should we render the bitmap? + +protected: + // Radio buttons to select desired rendering + Gtk::RadioButton *_radio_cairo; + Gtk::RadioButton *_radio_bitmap; + Labelled _widget_cairo; + Labelled _widget_bitmap; + Scalar _dpi; // DPI of bitmap to render +}; + +} // namespace Widget +} // namespace UI +} // namespace Inkscape + +#endif // INKSCAPE_UI_WIDGET_RENDERING_OPTIONS_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :