summaryrefslogtreecommitdiff
path: root/src/drivers/PostScript/Fl_PostScript.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'src/drivers/PostScript/Fl_PostScript.cxx')
-rw-r--r--src/drivers/PostScript/Fl_PostScript.cxx261
1 files changed, 260 insertions, 1 deletions
diff --git a/src/drivers/PostScript/Fl_PostScript.cxx b/src/drivers/PostScript/Fl_PostScript.cxx
index bee34703d..3b81789d0 100644
--- a/src/drivers/PostScript/Fl_PostScript.cxx
+++ b/src/drivers/PostScript/Fl_PostScript.cxx
@@ -1,7 +1,7 @@
//
// Classes Fl_PostScript_File_Device and Fl_PostScript_Graphics_Driver for the Fast Light Tool Kit (FLTK).
//
-// Copyright 2010-2022 by Bill Spitzak and others.
+// Copyright 2010-2024 by Bill Spitzak and others.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file. If this
@@ -21,11 +21,17 @@
#include <FL/fl_draw.H>
#include <stdio.h>
#include "Fl_PostScript_Graphics_Driver.H"
+#include <FL/Fl_PDF_File_Surface.H>
#include <FL/Fl_PostScript.H>
#include <FL/Fl_Image_Surface.H>
#include <FL/Fl_Native_File_Chooser.H>
#include "../../Fl_System_Driver.H"
+#include <FL/Fl_Choice.H>
+#include <FL/Fl_Button.H>
+#include <FL/Fl_Check_Button.H>
+#include <FL/Fl_Return_Button.H>
#include <FL/fl_string_functions.h>
+#include <FL/fl_callback_macros.H>
#include <FL/platform.H>
#include <stdarg.h>
#include <time.h>
@@ -33,6 +39,8 @@
#include <FL/math.h> // for M_PI
#include <pango/pangocairo.h>
#include <cairo/cairo-ps.h>
+#include <cairo/cairo-pdf.h>
+#include <FL/Fl_Preferences.H>
# if ! PANGO_VERSION_CHECK(1,10,0)
# error "Requires Pango 1.10 or higher"
# endif
@@ -150,6 +158,7 @@ Fl_PostScript_Graphics_Driver::Fl_PostScript_Graphics_Driver(void)
scale_x = scale_y = 1.;
#endif
ps_filename_ = NULL;
+ nPages = 0;
}
/** \brief The destructor. */
@@ -1461,6 +1470,30 @@ void Fl_PostScript_Graphics_Driver::ps_untranslate(void)
fprintf(output, "GR GR\n");
}
+#if defined(FLTK_USE_X11) || defined(FLTK_USE_WAYLAND)
+
+Fl_Paged_Device *Fl_PDF_File_Surface::new_platform_pdf_surface_(const char ***pfname) {
+ *pfname = NULL;
+ return new Fl_PostScript_File_Device;
+}
+
+int Fl_PDF_File_Surface::begin_job(const char* defaultfilename,
+ char **perr_message) {
+ if (perr_message) {
+ *perr_message = strdup("Class Fl_PDF_File_Surface requires PANGO to be usable.");
+ }
+ return 2;
+}
+
+int Fl_PDF_File_Surface::begin_document(const char* defaultfilename,
+ enum Fl_Paged_Device::Page_Format format,
+ enum Fl_Paged_Device::Page_Layout layout,
+ char **perr_message) {
+ return begin_job(NULL, perr_message);
+}
+
+#endif // defined(FLTK_USE_X11) || defined(FLTK_USE_WAYLAND)
+
# else // USE_PANGO
/* Cairo-based implementation of the PostScript graphics driver */
@@ -1552,6 +1585,232 @@ void Fl_PostScript_Graphics_Driver::transformed_draw(const char* str, int n, dou
check_status();
}
+
+// =======================================================
+
+
+class Fl_PDF_Pango_File_Surface : public Fl_PostScript_File_Device
+{
+public:
+ char *doc_fname;
+ Fl_PDF_Pango_File_Surface();
+ ~Fl_PDF_Pango_File_Surface() { if (doc_fname) free(doc_fname); }
+ int begin_job(const char *defaultname,
+ char **perr_message = NULL);
+ int begin_job(int, int*, int *, char **) FL_OVERRIDE {return 1;} // don't use
+ int begin_document(const char* outname,
+ enum Fl_Paged_Device::Page_Format format,
+ enum Fl_Paged_Device::Page_Layout layout,
+ char **perr_message);
+ int begin_page() FL_OVERRIDE;
+ void end_job() FL_OVERRIDE;
+};
+
+
+Fl_PDF_Pango_File_Surface::Fl_PDF_Pango_File_Surface() {
+ doc_fname = NULL;
+ driver()->output = NULL;
+}
+
+
+static Fl_Paged_Device::Page_Format menu_to_size[] = {Fl_Paged_Device::A3, Fl_Paged_Device::A4,
+ Fl_Paged_Device::A5, Fl_Paged_Device::B4, Fl_Paged_Device::B5, Fl_Paged_Device::EXECUTIVE,
+ Fl_Paged_Device::LEGAL, Fl_Paged_Device::LETTER, Fl_Paged_Device::TABLOID
+};
+static int size_count = sizeof(menu_to_size) / sizeof(menu_to_size[0]);
+
+
+static int update_format_layout(int rank, Fl_Paged_Device::Page_Layout layout,
+ bool &need_set_default_psize) {
+ int status = -1;
+ Fl_Window *modal = new Fl_Window(510, 90, Fl_PDF_File_Surface::format_dialog_title);
+ modal->begin();
+ Fl_Choice *psize = new Fl_Choice(140, 10, 110, 30, Fl_PDF_File_Surface::format_dialog_page_size);
+ psize->when(FL_WHEN_CHANGED);
+ for (int i = 0; i < size_count; i++) {
+ psize->add(Fl_Paged_Device::page_formats[menu_to_size[i]].name);
+ }
+ psize->value(rank);
+ Fl_Check_Button *default_size = new Fl_Check_Button(psize->x(), psize->y() + psize->h(),
+ psize->w(), psize->h(), Fl_PDF_File_Surface::format_dialog_default);
+ default_size->value(1);
+ default_size->user_data(&need_set_default_psize);
+ FL_INLINE_CALLBACK_2(psize, Fl_Choice*, choice, psize,
+ Fl_Check_Button*, check_but, default_size,
+ {
+ if (check_but->value() && choice->mvalue() && choice->prev_mvalue() &&
+ choice->prev_mvalue() != choice->mvalue()) {
+ check_but->value(0);
+ }
+ });
+ FL_INLINE_CALLBACK_2( modal, Fl_Window*, win, modal,
+ Fl_Check_Button*, check_but, default_size,
+ {
+ *((bool*)check_but->user_data()) = check_but->value();
+ win->hide();
+ } );
+ Fl_Choice *orientation = new Fl_Choice(psize->x() + psize->w() + 120, psize->y(), 130, psize->h(),
+ Fl_PDF_File_Surface::format_dialog_orientation);
+ orientation->add("PORTRAIT|LANDSCAPE");
+ orientation->value(layout == Fl_Paged_Device::PORTRAIT ? 0 : 1);
+ Fl_Return_Button *ok = new Fl_Return_Button(orientation->x() + orientation->w() - 55,
+ psize->y() + psize->h() + 10, 55, 30, fl_ok);
+ FL_INLINE_CALLBACK_4( ok, Fl_Widget*, b, ok,
+ int*, pstatus, &status,
+ Fl_Choice*, psize, psize,
+ Fl_Choice*, orientation, orientation,
+ {
+ *pstatus = menu_to_size[psize->value()] + 0x100 * orientation->value();
+ b->window()->do_callback();
+ } );
+ Fl_Button *cancel = new Fl_Button(ok->x() - 90, psize->y() + psize->h() + 10, 70, 30, fl_cancel);
+ FL_INLINE_CALLBACK_1( cancel, Fl_Widget*, wid, cancel, { wid->window()->do_callback(); } );
+ modal->end();
+ modal->set_modal();
+ modal->show();
+ while (modal->shown()) Fl::wait();
+ delete modal;
+ return status;
+}
+
+
+int Fl_PDF_Pango_File_Surface::begin_job(const char *defaultname, char **perr_message) {
+ static Page_Layout layout = PORTRAIT;
+
+ Fl_Preferences print_prefs(Fl_Preferences::CORE_USER, "fltk.org", "printers");
+ char *pref_format;
+ print_prefs.get("PDF/page_size", pref_format, "A4");
+ int rank = 1; // corresponds to A4
+ for (int i = 0; i < size_count; i++) {
+ if (strcmp(pref_format, Fl_Paged_Device::page_formats[menu_to_size[i]].name) == 0) {
+ rank = i;
+ break;
+ }
+ }
+ bool need_set_default_psize;
+ int status = update_format_layout(rank, layout, need_set_default_psize);
+ if (status == -1) return 1;
+ Page_Format format = (Page_Format)(status & 0xFF);
+ if (need_set_default_psize) print_prefs.set("PDF/page_size", Fl_Paged_Device::page_formats[format].name);
+
+ Fl_Native_File_Chooser ch(Fl_Native_File_Chooser::BROWSE_SAVE_FILE);
+ ch.preset_file(defaultname);
+ ch.filter("*.pdf");
+ ch.options(Fl_Native_File_Chooser::SAVEAS_CONFIRM);
+ int retval = ch.show();
+ if (retval) return (retval == -1 ? 2 : 1);
+
+ layout = (Page_Layout)(status & 0x100);
+ return begin_document(ch.filename(), format, layout, perr_message);
+}
+
+
+int Fl_PDF_Pango_File_Surface::begin_document(const char* outfname,
+ enum Fl_Paged_Device::Page_Format format,
+ enum Fl_Paged_Device::Page_Layout layout,
+ char **perr_message) {
+ int w = page_formats[format].width;
+ int h = page_formats[format].height;
+ if (layout == LANDSCAPE) {
+ int tmp = w;
+ w = h;
+ h = tmp;
+ }
+ Fl_PostScript_Graphics_Driver *dr = driver();
+ dr->output = fopen(outfname, "w");
+ cairo_status_t status = CAIRO_STATUS_WRITE_ERROR;
+ cairo_surface_t* cs = NULL;
+ if (dr->output) {
+ cs = cairo_pdf_surface_create_for_stream ( (cairo_write_func_t)write_to_cairo_stream,
+ dr->output, w, h);
+ status = cairo_surface_status(cs);
+ }
+ if (status != CAIRO_STATUS_SUCCESS) {
+ if (perr_message) {
+ const char *mess = cairo_status_to_string(status);
+ size_t l = strlen(mess) + strlen(outfname) + 100;
+ *perr_message = new char[l];
+ snprintf(*perr_message, l, "Error '%s' while attempting to create %s.", mess, outfname);
+ }
+ if (cs) cairo_surface_destroy(cs);
+ return 2;
+ }
+ cairo_pdf_surface_restrict_to_version(cs, CAIRO_PDF_VERSION_1_4);
+ cairo_t *cr = cairo_create(cs);
+ cairo_surface_destroy(cs);
+ dr->set_cairo(cr);
+ dr->pw_ = w;
+ dr->ph_ = h;
+ if (format == Fl_Paged_Device::A4) {
+ dr->left_margin = 18;
+ dr->top_margin = 18;
+ }
+ else {
+ dr->left_margin = 12;
+ dr->top_margin = 12;
+ }
+ doc_fname = strdup(outfname);
+ return 0;
+}
+
+
+int Fl_PDF_Pango_File_Surface::begin_page(void)
+{
+ Fl_PostScript_Graphics_Driver *ps = driver();
+ Fl_Surface_Device::push_current(this);
+ cairo_save(ps->cr());
+ cairo_translate(ps->cr(), ps->left_margin, ps->top_margin);
+ cairo_set_line_width(ps->cr(), 1);
+ cairo_set_source_rgb(ps->cr(), 1.0, 1.0, 1.0); // white background
+ cairo_save(ps->cr());
+ cairo_save(ps->cr());
+ ps->check_status();
+ x_offset = 0;
+ y_offset = 0;
+ ps->scale_x = ps->scale_y = 1.;
+ ps->angle = 0;
+ return 0;
+}
+
+
+void Fl_PDF_Pango_File_Surface::end_job() {
+ Fl_PostScript_Graphics_Driver *ps = driver();
+ int error = 0;
+ cairo_surface_t *s = cairo_get_target(ps->cr());
+ cairo_surface_finish(s);
+ error = cairo_surface_status(s);
+ int err2 = fclose(ps->output);
+ ps->output = NULL;
+ if (!error) error = err2;
+ cairo_destroy(ps->cr());
+ while (ps->clip_){
+ Fl_PostScript_Graphics_Driver::Clip * c= ps->clip_;
+ ps->clip_= ps->clip_->prev;
+ delete c;
+ }
+ if (error) fl_alert ("Error during PostScript data output.");
+}
+
+
+Fl_Paged_Device *Fl_PDF_File_Surface::new_platform_pdf_surface_(const char ***pfname) {
+ Fl_PDF_Pango_File_Surface *surf = new Fl_PDF_Pango_File_Surface();
+ *pfname = (const char**)&surf->doc_fname;
+ return surf;
+}
+
+int Fl_PDF_File_Surface::begin_job(const char* defaultfilename,
+ char **perr_message) {
+ return ((Fl_PDF_Pango_File_Surface*)platform_surface_)->begin_job(defaultfilename, perr_message);
+}
+
+
+int Fl_PDF_File_Surface::begin_document(const char* defaultfilename,
+ enum Fl_Paged_Device::Page_Format format,
+ enum Fl_Paged_Device::Page_Layout layout,
+ char **perr_message) {
+ return ((Fl_PDF_Pango_File_Surface*)platform_surface_)->begin_document(defaultfilename, format, layout, perr_message);
+}
+
#endif // USE_PANGO
/**