Skip to content

Commit

Permalink
Implement and document new class Fl_PDF_File_Surface
Browse files Browse the repository at this point in the history
  • Loading branch information
ManoloFLTK committed Apr 30, 2024
1 parent b402b6a commit 9472ff5
Show file tree
Hide file tree
Showing 10 changed files with 733 additions and 59 deletions.
4 changes: 2 additions & 2 deletions CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ Changes in FLTK 1.4.0 Released: Feb ?? 2024
- New Fl_SVG_Image class: gives support of scalable vector graphics images
to FLTK using the nanosvg software.
- New Fl_ICO_Image class to read Windows .ico icon files.
- New classes Fl_SVG_File_Surface and Fl_EPS_File_Surface to save any FLTK
graphics to SVG or EPS files, respectively.
- New classes Fl_PDF_File_Surface, Fl_SVG_File_Surface and Fl_EPS_File_Surface
to save any FLTK graphics to PDF, SVG or EPS files, respectively.
- New member functions Fl_Window::maximize(), Fl_Window::un_maximize() and
Fl_Window::maximize_active() to programmatically manage window maximization.
- Fl_Button now supports a compact flag that visually groups closely set
Expand Down
10 changes: 0 additions & 10 deletions FL/Fl_Device.H
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,6 @@ class Fl_Image_Surface;
</ol>
For back-compatibility, it is also possible to use the Fl_Surface_Device::set_current() member function
to change the current drawing surface, once to the new surface, once to the previous one.
Class Fl_Surface_Device can also be derived to define new kinds of graphical output
usable with FLTK drawing functions.
An example would be to draw to a PDF file. This would require to create a new class,
say PDF_File_Surface, derived from class Fl_Surface_Device, and another new class,
say PDF_Graphics_Driver, derived from class Fl_Graphics_Driver.
Class PDF_Graphics_Driver should implement all virtual methods of the Fl_Graphics_Driver class
to support all FLTK drawing functions and have them draw into PDF files. Alternatively,
class PDF_Graphics_Driver could implement only some virtual methods, and only part of
the FLTK drawing API would be usable when drawing to PDF files.
*/
class FL_EXPORT Fl_Surface_Device {
/** The graphics driver in use by this surface. */
Expand Down
89 changes: 89 additions & 0 deletions FL/Fl_PDF_File_Surface.H
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
//
// Declaration of class Fl_PDF_File_Surface for the Fast Light Tool Kit (FLTK).
//
// Copyright 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
// file is missing or damaged, see the license at:
//
// https://www.fltk.org/COPYING.php
//
// Please see the following page on how to report bugs and issues:
//
// https://www.fltk.org/bugs.php
//

#ifndef PDF_FILE_SURFACE_H
#define PDF_FILE_SURFACE_H

#include <FL/Fl_Paged_Device.H>

/**
To send graphical output to a PDF file.
Class Fl_PDF_File_Surface is used exactly as the Fl_Printer class except for its 2 member functions begin_job() and begin_document().
<p><b>Platform notes:</b>
- Windows: requires "Microsoft Print to PDF" available in Windows 10 and later.
- Wayland/X11: requires the FLTK library was built with FLTK_USE_PANGO=1.
- macOS: requires macOS 10.9 or later.
<p>If the running platform doesn't fulfill the requirement above, the program runs but doesn't output any PDF.
*/
class FL_EXPORT Fl_PDF_File_Surface : public Fl_Paged_Device {
private:
const char **out_filename_;
Fl_Paged_Device *platform_surface_;
static Fl_Paged_Device *new_platform_pdf_surface_(const char ***);
public:
/** \name These attributes are useful for the Wayland/X11 platform only.
\{
*/
static const char * format_dialog_title;
static const char * format_dialog_page_size;
static const char * format_dialog_orientation;
static const char * format_dialog_default;
/** \} */
Fl_PDF_File_Surface();
~Fl_PDF_File_Surface();
/** Prepare to draw to a PDF document identified with a file chooser.
A dialog opens to select the location and name of the output PDF document
as well as its page format and orientation.
\param defaultfilename Default name for the PDF document
\param perr NULL or address of a string that receives a message in case of error.
To be deleted[] after use.
\return 0 for success, 1 when the user cancelled the operation, 2 when an error occurred.
*/
int begin_job(const char* defaultfilename, char **perr = NULL);
/** Don't use for this class */
int begin_job(int, int *, int *, char **) FL_OVERRIDE {return 1;}
/** Prepare to draw to a PDF document identified by its pathname.
\param pathname Path name for the PDF document
\param format The paper format for the PDF document
\param layout The orientation for the PDF document
\param perr NULL or address of a string that receives a message in case of error.
To be deleted[] after use.
\return 0 for success, 2 when an error occurred.
*/
int begin_document(const char* pathname,
enum Fl_Paged_Device::Page_Format format = Fl_Paged_Device::A4,
enum Fl_Paged_Device::Page_Layout layout = Fl_Paged_Device::PORTRAIT,
char **perr = NULL);
int printable_rect(int *w, int *h) FL_OVERRIDE { return platform_surface_->printable_rect(w,h); }
void margins(int *left, int *top, int *right, int *bottom) FL_OVERRIDE {
platform_surface_->margins(left,top,right,bottom);
}
void origin(int x, int y) FL_OVERRIDE {platform_surface_->origin(x, y);}
void origin(int *x, int *y) FL_OVERRIDE {platform_surface_->origin(x, y);}
void scale(float s_x, float s_y = 0) FL_OVERRIDE {platform_surface_->scale(s_x, s_y);}
void rotate(float angle) FL_OVERRIDE {platform_surface_->rotate(angle);}
void translate(int x, int y) FL_OVERRIDE {platform_surface_->translate(x, y);}
void untranslate() FL_OVERRIDE {platform_surface_->untranslate();};
int begin_page(void) FL_OVERRIDE {return platform_surface_->begin_page();}
int end_page(void) FL_OVERRIDE {return platform_surface_->end_page();}
void end_job(void) FL_OVERRIDE {return platform_surface_->end_job();}
/** Returns the name of the PDF document */
inline const char *pdf_filename() { return *out_filename_; }
void set_current() FL_OVERRIDE { if (platform_surface_) platform_surface_->set_current(); }
bool is_current() FL_OVERRIDE { return surface() == platform_surface_; }
};

#endif // PDF_FILE_SURFACE_H
32 changes: 31 additions & 1 deletion src/Fl_Device.cxx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//
// implementation of classes Fl_Surface_Device and Fl_Display_Device for the Fast Light Tool Kit (FLTK).
//
// Copyright 2010-2023 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
Expand Down Expand Up @@ -46,6 +46,11 @@
|
+- Fl_Posix_Printer_Driver: Fl_Printer uses that under Posix platforms
+- Fl_GTK_Printer_Driver: Fl_Printer uses that under Posix+GTK platforms
+- Fl_PDF_File_Surface: draw into a PDF file
+- Fl_PDF_GDI_File_Surface: Windows-specific helper class interfacing FLTK with PDF operations
+- Fl_PDF_Pango_File_Surface: Linux/Unix-specific helper class interfacing FLTK with PDF operations
+- Fl_PDF_Cocoa_File_Surface: macOS-specific helper class interfacing FLTK with PDF operations
+- Fl_Graphics_Driver -> directed to an Fl_Surface_Device object
|
Expand Down Expand Up @@ -154,3 +159,28 @@ Fl_Device_Plugin *Fl_Device_Plugin::opengl_plugin() {
}
return pi;
}

#if !defined(FL_NO_PRINT_SUPPORT)

#include <FL/Fl_PDF_File_Surface.H>

Fl_PDF_File_Surface::Fl_PDF_File_Surface() {
platform_surface_ = new_platform_pdf_surface_(&out_filename_);
driver(platform_surface_->driver());
}


Fl_PDF_File_Surface::~Fl_PDF_File_Surface() {
delete platform_surface_;
}

#endif // !defined(FL_NO_PRINT_SUPPORT)

/** Localizable text of the "PDF document settings" dialog */
const char * Fl_PDF_File_Surface::format_dialog_title = "PDF document settings";
/** Localizable text of the "PDF document settings" dialog */
const char * Fl_PDF_File_Surface::format_dialog_page_size = "Page Size:";
/** Localizable text of the "PDF document settings" dialog */
const char * Fl_PDF_File_Surface::format_dialog_default = "Set as default";
/** Localizable text of the "PDF document settings" dialog */
const char * Fl_PDF_File_Surface::format_dialog_orientation = "Orientation:";
140 changes: 138 additions & 2 deletions src/drivers/Cocoa/Fl_Cocoa_Printer_Driver.mm
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//
// Mac OS X-specific printing support (objective-c++) for the Fast Light Tool Kit (FLTK).
//
// Copyright 2010-2018 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
Expand All @@ -20,6 +20,7 @@
#include "../../Fl_Screen_Driver.H"
#include "../Quartz/Fl_Quartz_Graphics_Driver.H"
#include "../Darwin/Fl_Darwin_System_Driver.H"
#include <FL/Fl_PDF_File_Surface.H>
#include "Fl_Cocoa_Window_Driver.H"

#include <FL/Fl.H>
Expand Down Expand Up @@ -48,7 +49,7 @@ typedef OSStatus (*PMSessionBeginDocumentNoDialog_type)(
/** Support for printing on the Apple OS X platform */
class Fl_Cocoa_Printer_Driver : public Fl_Paged_Device {
friend class Fl_Printer;
private:
protected:
float scale_x;
float scale_y;
float angle; // rotation angle in radians
Expand Down Expand Up @@ -391,3 +392,138 @@ - (void)printPanelDidEnd:(NSPrintPanel *)printPanel returnCode:(NSInteger)return
{
Fl_Paged_Device::origin(x, y);
}


class Fl_PDF_Cocoa_File_Surface : public Fl_Cocoa_Printer_Driver
{
public:
char *doc_fname;
Fl_PDF_Cocoa_File_Surface();
~Fl_PDF_Cocoa_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);
};


Fl_PDF_Cocoa_File_Surface::Fl_PDF_Cocoa_File_Surface() {
driver(new Fl_Quartz_Graphics_Driver());
doc_fname = NULL;
}


int Fl_PDF_Cocoa_File_Surface::begin_job(const char* defaultfilename,
char **perr_message) {
OSStatus status = 0;
if (fl_mac_os_version < 100900) return 1;
Fl_Window *top = Fl::first_window();
NSWindow *main = (top ? (NSWindow*)fl_xid(top->top_window()) : nil);
if (!main) return 1;
Fl_Cocoa_Window_Driver::q_release_context();
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9 && defined(__BLOCKS__)
NSPDFInfo *pdf_info = [[NSPDFInfo alloc] init]; // 10.9
NSPDFPanel *pdf_panel = [NSPDFPanel panel]; // 10.9
char buf[FL_PATH_MAX];
strcpy(buf, defaultfilename);
fl_filename_setext(buf, sizeof(buf), NULL);
[pdf_panel setDefaultFileName:[NSString stringWithUTF8String:buf]];
[pdf_panel setOptions: NSPrintPanelShowsOrientation | NSPrintPanelShowsPaperSize];
NSInteger retval = -1;
__block NSInteger complete = -1;
[pdf_panel beginSheetWithPDFInfo:pdf_info
modalForWindow:main
completionHandler:^(NSInteger returnCode) {
// this block runs after OK or Cancel was triggered in file dialog
complete = returnCode;
}
];
while (complete == -1) Fl::wait(100); // loop until end of file dialog
retval = complete;
[main makeKeyAndOrderFront:nil];
if (retval != NSModalResponseOK) return 1;
NSURL *url = [pdf_info URL];
doc_fname = fl_strdup([url fileSystemRepresentation]);
NSPrintInfo *pr_info = [NSPrintInfo sharedPrintInfo];
[pr_info takeSettingsFromPDFInfo:pdf_info];
[pdf_info release];
printSession = (PMPrintSession)[pr_info PMPrintSession];
printSettings = (PMPrintSettings)[pr_info PMPrintSettings];
pageFormat = (PMPageFormat)[pr_info PMPageFormat];
status = PMSessionBeginCGDocumentNoDialog(printSession, printSettings, pageFormat);//from 10.4
#endif
if (status != noErr) {
if (perr_message) {
NSError *nserr = [NSError errorWithDomain:NSCocoaErrorDomain code:status userInfo:nil];
NSString *s = [nserr localizedDescription];
if (s) *perr_message = fl_strdup([s UTF8String]);
}
free(doc_fname);
doc_fname = NULL;
return 2;
}
y_offset = x_offset = 0;
return 0;
}


int Fl_PDF_Cocoa_File_Surface::begin_document(const char* outfname,
enum Fl_Paged_Device::Page_Format format,
enum Fl_Paged_Device::Page_Layout layout,
char **perr_message) {
OSStatus status = 0;
fl_open_display();
if (fl_mac_os_version < 100900) return 1;
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
NSPDFInfo *pdf_info = [[NSPDFInfo alloc] init]; // 10.9
doc_fname = fl_strdup(outfname);
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithUTF8String:doc_fname]];
[pdf_info setURL:url];
NSSize psize = {(CGFloat)Fl_Paged_Device::page_formats[format].width, (CGFloat)Fl_Paged_Device::page_formats[format].height};
[pdf_info setPaperSize:psize];
[pdf_info setOrientation:(layout == PORTRAIT ? NSPaperOrientationPortrait : NSPaperOrientationLandscape)];
NSPrintInfo *pr_info = [NSPrintInfo sharedPrintInfo];
[pr_info takeSettingsFromPDFInfo:pdf_info];
[pdf_info release];
printSession = (PMPrintSession)[pr_info PMPrintSession];
printSettings = (PMPrintSettings)[pr_info PMPrintSettings];
pageFormat = (PMPageFormat)[pr_info PMPageFormat];
status = PMSessionBeginCGDocumentNoDialog(printSession, printSettings, pageFormat);//from 10.4
#endif
if (status != noErr) {
if (perr_message) {
NSError *nserr = [NSError errorWithDomain:NSCocoaErrorDomain code:status userInfo:nil];
NSString *s = [nserr localizedDescription];
if (s) *perr_message = fl_strdup([s UTF8String]);
}
free(doc_fname);
doc_fname = NULL;
return 2;
}
y_offset = x_offset = 0;
return 0;
}


Fl_Paged_Device *Fl_PDF_File_Surface::new_platform_pdf_surface_(const char ***pfname) {
Fl_PDF_Cocoa_File_Surface *surf = new Fl_PDF_Cocoa_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_Cocoa_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_Cocoa_File_Surface*)platform_surface_)->begin_document(defaultfilename, format, layout, perr_message);
}
Loading

0 comments on commit 9472ff5

Please sign in to comment.