changeset 10854:d5a7db05d591

Add PS and PDF output for the fltk backend.
author Ben Abbott <bpabbott@mac.com>
date Wed, 04 Aug 2010 20:32:49 -0400
parents c3813056f94f
children 5162c67c949e
files scripts/ChangeLog scripts/plot/__fltk_print__.m scripts/plot/__gnuplot_print__.m scripts/plot/__print_parse_opts__.m scripts/plot/print.m scripts/plot/private/__ghostscript__.m
diffstat 6 files changed, 400 insertions(+), 220 deletions(-) [+]
line wrap: on
line diff
--- a/scripts/ChangeLog
+++ b/scripts/ChangeLog
@@ -3,6 +3,13 @@
 	* general/sortrows.m: Don't actually permute the rows if not
 	requested.
 
+2010-08-04  Ben Abbott <bpabbott@mac.com>
+
+	* /plot/print.m, plot/__print_parse_opts__.m, plot/__gnuplot_print__.m, 
+	plot/private/__ghostscript__.m: plot/__fltk_print__.m: Add ps and pdf
+	output for fltk backend, improved use of ghostscript, and minor
+	improvements.
+
 2010-08-01  Rik <octave@nomad.inbox5.com>
 
 	* deprecated/intwarning.m, general/arrayfun.m, general/cplxpair.m,
--- a/scripts/plot/__fltk_print__.m
+++ b/scripts/plot/__fltk_print__.m
@@ -23,11 +23,14 @@
 
 function __fltk_print__ (opts)
 
-  if (opts.debug)
-    fprintf ("FLTK backend: output file = '%s' for device '%s'\n", opts.name, opts.devopt);
+  file2unlink = "";
+
+  if (! isempty (opts.fig2dev_binary))
+    fig2dev_devices = {"pstex", "mf", "emf"};
+  else
+    ## If no fig2dev is present, support emf using pstoedit.
+    fig2dev_devices = {"pstex", "mf"};
   endif
-  
-  file2unlink = "";
 
   switch lower (opts.devopt)
   case {"eps", "eps2", "epsc", "epsc2"}
@@ -44,41 +47,66 @@
   case {"tikz"}
     ## FIXME - format GL2PS_PGF if not implemented
     drawnow ("pgf", opts.name);
-  case {"ps", "ps2", "psc", "psc2"}
-    ## FIXME - format GL2PS_PS if not implemented
-    drawnow ("ps", opts.name);
-  case {"pdf"}
-    ## FIXME - format GL2PS_PDF if not implemented
-    drawnow ("pdf", opts.name);
+  case {"ps", "ps2", "psc", "psc2", "pdf"}
+    opts.ghostscript.source = strcat (tmpnam (), ".eps");
+    file2unlink = opts.ghostscript.source;
+    if (strcmp (opts.devopt, "pdf"))
+      opts.ghostscript.device = "pdfwrite";
+    else
+      opts.ghostscript.device = "pswrite";
+    endif
+    opts.ghostscript.output = opts.name;
+    drawnow ("eps", opts.ghostscript.source);
+    if (opts.tight_flag)
+      __tight_eps_bbox__ (opts, opts.ghostscript.source);
+    endif
   case {"svg"}
     ## FIXME - format GL2PS_SVG if not implemented
     drawnow ("svg", opts.name);
-  case {"gif", "jpeg", "png", "pbm"}
-    opts.ghostscript_device = opts.devopt;
-    opts.ghostscript_output = opts.name;
-    opts.name = strcat (tmpnam (), ".eps");
-    file2unlink = opts.name;
-    opts.devopt = "epsc";
-    drawnow ("eps", opts.name);
+  case {"jpeg", "pbm", "pbmraw", "pcx24b", "pcx256", "pcx16", ...
+        "pgm", "pgmraw", "png", "ppm", "ppmraw", "pdfwrite", ...
+        "tiff", "tiffn"}
+    switch opts.devopt
+    case "png"
+      opts.ghostscript.device = "png256";
+    case {"tiff", "tiffn"}
+      opts.ghostscript.device = "tiff24nc";
+    otherwise
+      opts.ghostscript.device = opts.devopt;
+    endswitch
+    opts.ghostscript.output = opts.name;
+    opts.ghostscript.source = strcat (tmpnam (), ".eps");
+    opts.ghostscript.epscrop = true;
+    file2unlink = opts.ghostscript.source;
+    drawnow ("eps", opts.ghostscript.source)
     if (opts.tight_flag)
-      __tight_eps_bbox__ (opts, opts.name);
+      __tight_eps_bbox__ (opts, opts.ghostscript.source);
     endif
-  case {"aifm", "dxf", "emf", "fig", "hpgl"}
-    status = __pstoedit__ (opts);
-  case {"pstex", "mf", "emf"}
+  case fig2dev_devices
     tmp_figfile = strcat (tmpnam (), ".fig");
     file2unlink = tmp_figfile;
     status = __pstoedit__ (opts, "fig", tmp_figfile);
     if (status == 0)
       status = __fig2dev__ (opts, tmp_figfile);
     endif
+  case {"aifm", "dxf", "emf", "fig", "hpgl"};
+    status = __pstoedit__ (opts);
   otherwise
-    error ("print:unavailabledevice", 
-    "print.m: device '%s' is unavailable for the fltk backend.", opts.devopt)
+    ## various ghostscript devices for printers
+    opts.ghostscript.device = opts.devopt;
+    opts.ghostscript.output = opts.name;
+    opts.ghostscript.epscrop = false;
+    opts.ghostscript.source = strcat (tmpnam (), ".eps");
+    file2unlink = opts.ghostscript.source;
+    drawnow ("eps", opts.ghostscript.source)
+    if (opts.tight_flag)
+      __tight_eps_bbox__ (opts, opts.ghostscript.source);
+    endif
   endswitch
 
-  if (! isempty (opts.ghostscript_device))
-    __ghostscript__ (opts);
+  ## FIXME - warning: unrecognized escape sequence `\P' -- converting to `P'
+  if (! isempty (opts.ghostscript.device))
+    status = __ghostscript__ (opts.ghostscript);
   endif
 
   if (! isempty (file2unlink))
--- a/scripts/plot/__gnuplot_print__.m
+++ b/scripts/plot/__gnuplot_print__.m
@@ -25,13 +25,12 @@
 ## Author: Daniel Heiserer <Daniel.heiserer@physik.tu-muenchen.de>
 ## Adapted-By: jwe
 
-function __gnuplot_print__ (varargin)
+function __gnuplot_print__ (opts)
 
   persistent warn_on_inconsistent_orientation = true
 
   old_fig = get (0, "currentfigure");
   unwind_protect
-    opts = __print_parse_opts__ (varargin{:});
     have_ghostscript = ! isempty (opts.ghostscript_binary);
 
     doprint = isempty (opts.name);
@@ -255,7 +254,7 @@
         options = "";
       end
       if (! isempty (opts.canvas_size))
-        options = cstrcat (options, " size ", opts.canvas_size);
+        options = sprintf ("%s size %d, %d", options, opts.canvas_size);
       endif
 
     elseif (any (strcmp (dev, {"dxf", "mf", "hpgl"})))
@@ -395,7 +394,7 @@
         ## render an image the size of the paperposition box.
         ## Trigger the listener to convert all paper props to inches.
         if (! isempty (opts.canvas_size))
-          size_in_pixels = sscanf (opts.canvas_size ,"%d, %d");
+          size_in_pixels = opts.canvas_size;
           size_in_pixels = reshape (size_in_pixels, [1, numel(size_in_pixels)]);
           papersize_in_inches = size_in_pixels ./ opts.resolution;
           paperposition_in_inches = [0, 0, papersize_in_inches];
--- a/scripts/plot/__print_parse_opts__.m
+++ b/scripts/plot/__print_parse_opts__.m
@@ -26,9 +26,8 @@
 
 function arg_st = __print_parse_opts__ (varargin)
 
-  ## FIXME - change to numeric values: `canvas_size', `resolution', `fontsize'
   arg_st.append_to_file = false;
-  arg_st.canvas_size = "";
+  arg_st.canvas_size = [];
   arg_st.debug = false;
   arg_st.debug_file = "octave-print-commands.log";
   arg_st.devopt = "";
@@ -37,14 +36,18 @@
   arg_st.fontsize = "";
   arg_st.font = "";
   arg_st.force_solid = 0; # 0=default, -1=dashed, +1=solid
-  arg_st.ghostscript_binary = __ghostscript_binary__ ();
-  arg_st.ghostscript_device = ""; # gs converts eps/ps to this format/printer-language
-  arg_st.ghostscript_output = ""; # gs converts arg_st.name to arg_st.ghostscript_output
+  arg_st.ghostscript.binary = __ghostscript_binary__ ();
+  arg_st.ghostscript.device = "";
+  arg_st.ghostscript.output = "";
+  arg_st.ghostscript.papersize = "";
+  arg_st.ghostscript.pageoffset = [];
+  arg_st.ghostscript.debug = false;
+  arg_st.ghostscript.epscrop = false;
+  arg_st.ghostscript.resolution = 150;
+  arg_st.orientation = "";
   arg_st.pstoedit_binary = __find_binary__ ("pstoedit");
-  arg_st.name = ""; # This is the file produced by the backend
-  arg_st.orientation = "";
+  arg_st.name = "";
   arg_st.printer = "";
-  arg_st.resolution = num2str (get (0, "screenpixelsperinch"));
   arg_st.special_flag = "textnormal";
   arg_st.tight_flag = false;
   arg_st.use_color = 0; # 0=default, -1=mono, +1=color
@@ -73,9 +76,9 @@
         arg_st.force_solid = 1;
       elseif (strcmp (arg, "-dashed"))
         arg_st.force_solid = -1;
-      elseif (strcmp (arg, "-portrait"))
+      elseif (strncmp (arg, "-portrait", numel (arg)))
         arg_st.orientation = "portrait";
-      elseif (strcmp (arg, "-landscape"))
+      elseif (strncmp (arg, "-landscape", numel (arg)))
         arg_st.orientation = "landscape";
       elseif (strcmp (arg, "-tight"))
         arg_st.tight_flag = true;
@@ -83,6 +86,7 @@
         arg_st.special_flag = "textspecial";
       elseif (strncmp (arg, "-debug", 6))
         arg_st.debug = true;
+        arg_st.ghostscript.debug = true;
         if (length (arg) > 7)
           arg_st.debug_file = arg(8:end);
         endif
@@ -91,25 +95,25 @@
       elseif (length (arg) > 2 && arg(1:2) == "-P")
         arg_st.printer = arg;
       elseif ((length (arg) > 2) && arg(1:2) == "-G")
-        arg_st.ghostscript_binary = arg(3:end);
-        if (exist (arg_st.ghostscript_binary, "file") != 2)
-          arg_st.ghostscript_binary = file_in_path (EXEC_PATH, arg_st.ghostscript_binary);
+        arg_st.ghostscript.binary = arg(3:end);
+        if (exist (arg_st.ghostscript.binary, "file") != 2)
+          arg_st.ghostscript.binary = file_in_path (EXEC_PATH, arg_st.ghostscript.binary);
         endif
-        if (isempty (arg_st.ghostscript_binary))
+        if (isempty (arg_st.ghostscript.binary))
           error ("print: Ghostscript binary ""%s"" could not be located", arg(3:end))
         endif
       elseif (length (arg) > 2 && arg(1:2) == "-F")
         idx = rindex (arg, ":");
         if (idx)
           arg_st.font = arg(3:idx-1);
-          arg_st.fontsize = arg(idx+1:length(arg));
+          arg_st.fontsize = str2num (arg(idx+1:end));
         else
-          arg_st.font = arg(3:length(arg));
+          arg_st.font = arg(3:end);
         endif
       elseif (length (arg) > 2 && arg(1:2) == "-S")
-        arg_st.canvas_size = arg(3:length(arg));
+        arg_st.canvas_size = str2num (arg(3:end));
       elseif (length (arg) > 2 && arg(1:2) == "-r")
-        arg_st.resolution = arg(3:length(arg));
+        arg_st.ghostscript.resolution = arg(3:end);
       elseif (length (arg) > 2 && arg(1:2) == "-f")
         arg_st.figure = str2num (arg(3:end));
       elseif (length (arg) >= 1 && arg(1) == "-")
@@ -124,17 +128,22 @@
     endif
   endfor
 
+  if (arg_st.ghostscript.resolution == 0)
+    ## Do as Matlab does.
+    arg_st.ghostscript.resolution = num2str (get (0, "screenpixelsperinch"));
+  endif
+
   if (isempty (arg_st.orientation))
     if (isfigure (arg_st.figure))
       arg_st.orientation = get (arg_st.figure, "paperorientation");
     else
       ## Allows tests to be run without error.
-      arg_st.orientation = get (0, "defaultfigurepaperorientation");
+      arg_st.orientation = get (0, "portrait");
     endif
   endif
 
-  if (isempty (arg_st.ghostscript_binary))
-    arg_st.ghostscript_binary = __ghostscript_binary__ ();
+  if (isempty (arg_st.ghostscript.binary))
+    arg_st.ghostscript.binary = __ghostscript_binary__ ();
   endif
 
   dot = rindex (arg_st.name, ".");
@@ -146,8 +155,8 @@
     endif
   endif
 
-  if (any (strcmp ({"ps", "ps2", "eps", "eps2"}, arg_st.devopt))
-      || (! isempty (strfind (arg_st.devopt, "tex")) && arg_st.use_color == 0))
+  if ((any (strcmp ({"ps", "ps2", "eps", "eps2"}, arg_st.devopt))
+      || (! isempty (strfind (arg_st.devopt, "tex")))) && arg_st.use_color == 0)
     ## Mono is the default for ps, eps, and the tex/latex, devices
     arg_st.use_color = -1;
   elseif (arg_st.use_color == 0)
@@ -155,14 +164,20 @@
   endif
 
   if (arg_st.append_to_file)
-    if (any (strcmpi (arg_st.devopt, {"ps", "ps2", "psc", "psc2", "pdf"})))
+    if (isempty (arg_st.name))
+      arg_st.append_to_file = false;
+    elseif (any (strcmpi (arg_st.devopt, {"eps", "eps2", "epsc", "epsc2", ...
+                                          "ps", "ps2", "psc", "psc2", "pdf"})))
       have_ghostscript = ! isempty (__ghostscript_binary__ ());
       if (have_ghostscript)
         file_exists = ((numel (dir (arg_st.name)) == 1) && (! isdir (arg_st.name)));
         if (! file_exists)
           arg_st.append_to_file = false;
         end
-      end
+      else
+        arg_st.append_to_file = false;
+        warning ("print.m: appended output requires ghostscript to be installed.")
+      endif
     else
       warning ("print.m: appended output is not supported for device '%s'", arg_st.devopt)
       arg_st.append_to_file = false;
@@ -189,16 +204,22 @@
   endif
 
   dev_list = {"aifm", "corel", "fig", "png", "jpeg", ...
-              "gif", "pbm", "dxf", "mf", "svg", "hpgl", ...
-              "ps", "ps2", "psc", "psc2", "eps", "eps2", ...
-              "epsc", "epsc2", "emf", "pdf", "pslatex", ...
-              "epslatex", "epslatexstandalone", "pstex", "tikz"};
+              "gif", "pbm", "pbmraw", "dxf", "mf", ...
+              "svg", "hpgl", "ps", "ps2", "psc", ...
+              "psc2", "eps", "eps2", "epsc", "epsc2", ...
+              "emf", "pdf", "pslatex", "epslatex", "epslatexstandalone", ...
+              "pstex", "tiff", "tiffn" "tikz", "pcxmono", ...
+              "pcx24b", "pcx256", "pcx16", "pgm", "pgmraw", ...
+              "ppm", "ppmraw"};
 
   suffixes = {"ai", "cdr", "fig", "png", "jpg", ...
-              "gif", "pbm", "dxf", "mf", "svg", "hpgl", ...
-              "ps", "ps", "ps", "ps", "eps", "eps", ...
-              "eps", "eps", "emf", "pdf", "tex", ...
-              "tex", "tex", "tex", "tikz"};
+              "gif", "pbm", "pbm", "dxf", "mf", ...
+              "svg", "hpgl", "ps", "ps", "ps", ...
+              "ps", "eps", "eps", "eps", "eps", ...
+              "emf", "pdf", "tex", "tex", "tex", ...
+              "tex", "tiff", "tiff", "tikz", "pcx", ...
+              "pcx", "pcx", "pcx", "pgm", "pgm", ...
+              "ppm", "ppm"};
 
   match = strcmpi (dev_list, arg_st.devopt);
   if (any (match))
@@ -220,34 +241,29 @@
   endif
 
   if (all (! strcmp (arg_st.devopt, dev_list)))
-    arg_st.ghostscript_device = arg_st.devopt;
-    arg_st.ghostscript_output = arg_st.name;
-    ## FIXME - This will not work correctly if GS is used to produce a print
-    ##         stream that is saved to a file and not sent to the printer.
-    if (arg_st.send_to_printer)
-      arg_st.devopt = "psc";
-      arg_st.name = strcat (tmpnam (), ".ps");
-      arg_st.unlink{end+1} = arg_st.name;
-    else
-      ## Assume the user desires only the figuure. This is useful for producing
-      ## pdf figures for pdflatex
-      ## octave:#> print -f1 -dpdfwrite figure1.pdf
-      arg_st.devopt = "epsc";
-      arg_st.name = strcat (tmpnam (), ".eps");
-      arg_st.unlink{end+1} = arg_st.name;
-    endif
+    arg_st.ghostscript.device = arg_st.devopt;
+    arg_st.ghostscript.output = arg_st.name;
   endif
 
-  if (any (strncmp (arg_st.devopt(1:2), {"ps", "pdf"}, 2)))
-    arg_st.paperoutput = true;
+  if (isempty (arg_st.canvas_size))
+    if (isfigure (arg_st.figure))
+      [arg_st.ghostscript.papersize, paperposition] = gs_papersize (arg_st.figure,
+                                                               arg_st.orientation);
+    else
+      ## allows tests to be run
+      arg_st.ghostscript.papersize = "letter";
+      paperposition = [0.25, 2.50, 8.00, 6.00] * 72;
+    endif
+    arg_st.canvas_size = paperposition(3:4);
+    arg_st.ghostscript.pageoffset = paperposition(1:2);
   else
-    arg_st.paperoutput = false;
+    ## Canvas size in points.
+    arg_st.canvas_size = arg_st.canvas_size * 72 / arg_st.ghostscript.resolution;
+    arg_st.ghostscript.papersize = arg_st.canvas_size;
+    arg_st.ghostscript.epscrop = true;
+    arg_st.ghostscript.pageoffset = [0, 0];
   endif
 
-  if (arg_st.debug)
-    disp ("Printing options");
-    disp (arg_st)
-  endif
 endfunction
 
 %!test
@@ -255,20 +271,25 @@
 %! assert (opts.devopt, "psc");
 %! assert (opts.use_color, 1);
 %! assert (opts.send_to_printer, true);
-%! assert (opts.paperoutput, true);
 %! assert (opts.name, opts.unlink{1})
+%! assert (opts.canvas_size, [576, 432]);
+%! assert (opts.ghostscript.device, "")
 %! for n = 1:numel(opts.unlink)
 %!   unlink (opts.unlink{n});
 %! endfor
 
 %!test
+%! opts = __print_parse_opts__ ("test.pdf", "-SX640,Y480");
+%! assert (opts.canvas_size, [307.2, 230.4], 0.1);
+
+%!test
 %! opts = __print_parse_opts__ ("-dpsc", "-append");
 %! assert (opts.devopt, "psc");
 %! assert (opts.name(end+(-2:0)), ".ps");
 %! assert (opts.send_to_printer, true);
 %! assert (opts.use_color, 1);
 %! assert (opts.append_to_file, false);
-%! assert (opts.paperoutput, true);
+%! assert (opts.ghostscript.device, "")
 %! for n = 1:numel(opts.unlink)
 %!   unlink (opts.unlink{n});
 %! endfor
@@ -277,9 +298,9 @@
 %! opts = __print_parse_opts__ ("-deps", "-tight");
 %! assert (opts.name, opts.unlink{1})
 %! assert (opts.tight_flag, true);
-%! assert (opts.paperoutput, false)
 %! assert (opts.send_to_printer, true);
 %! assert (opts.use_color, -1);
+%! assert (opts.ghostscript.device, "")
 %! for n = 1:numel(opts.unlink)
 %!   unlink (opts.unlink{n});
 %! endfor
@@ -288,31 +309,29 @@
 %! opts = __print_parse_opts__ ("-djpg", "foobar", "-mono");
 %! assert (opts.devopt, "jpeg")
 %! assert (opts.name, "foobar.jpg")
-%! assert (opts.ghostscript_device, "")
+%! assert (opts.ghostscript.device, "")
 %! assert (opts.send_to_printer, false);
 %! assert (opts.printer, "");
-%! assert (opts.paperoutput, false)
 %! assert (opts.use_color, -1);
+%! assert (opts.ghostscript.device, "")
 
 %!test
 %! opts = __print_parse_opts__ ("-ddeskjet", "foobar", "-mono", "-Pmyprinter");
-%! assert (opts.ghostscript_output, "foobar.deskjet")
-%! assert (opts.ghostscript_device, "deskjet")
-%! assert (opts.devopt, "psc")
+%! assert (opts.ghostscript.output, "foobar.deskjet")
+%! assert (opts.ghostscript.device, "deskjet")
+%! assert (opts.devopt, "deskjet")
 %! assert (opts.send_to_printer, true);
 %! assert (opts.printer, "-Pmyprinter");
-%! assert (opts.paperoutput, true)
 %! assert (opts.use_color, -1);
 
 %!test
 %! opts = __print_parse_opts__ ("-f5", "-dljet3");
-%! assert (opts.name, opts.unlink{2})
-%! assert (opts.ghostscript_output, opts.unlink{1})
-%! assert (strfind (opts.ghostscript_output, ".ljet3"))
-%! assert (strfind (opts.name, ".ps"))
-%! assert (opts.devopt, "psc")
+%! assert (opts.name, opts.unlink{1})
+%! assert (opts.ghostscript.output, opts.unlink{1})
+%! assert (opts.ghostscript.device, "ljet3")
+%! assert (strfind (opts.ghostscript.output, ".ljet3"))
+%! assert (opts.devopt, "ljet3")
 %! assert (opts.send_to_printer, true);
-%! assert (opts.paperoutput, true)
 %! assert (opts.figure, 5)
 %! for n = 1:numel(opts.unlink)
 %!   unlink (opts.unlink{n});
@@ -393,4 +412,79 @@
 
 endfunction
 
+function [papersize, paperposition] = gs_papersize (hfig, paperorientation)
+  persistent papertypes papersizes
 
+  if (isempty (papertypes))
+    papertypes = {"usletter", "uslegal",     "a0",     "a1", ...
+                        "a2",      "a3",     "a4",     "a5", ...
+                        "b0",      "b1",     "b2",     "b3", ...
+                        "b4",      "b5", "arch-a", "arch-b", ...
+                    "arch-c",  "arch-d", "arch-e",      "a", ...
+                         "b",       "c",      "d",      "e", ...
+                   "tabloid"};
+    papersizes = [ 8.5, 11.0;  8.5, 14.0; 33.1, 46.8; 23.4, 33.1;
+                  16.5, 23.4; 11.7, 16.5;  8.3, 11.7;  5.8,  8.3;
+                  39.4, 55.7; 27.8, 39.4; 19.7, 27.8; 13.9, 19.7;
+                   9.8, 13.9;  6.9,  9.8;  9.0, 12.0; 12.0, 18.0;
+                  18.0, 24.0; 24.0, 36.0; 36.0, 48.0;  8.5, 11.0;
+                  11.0, 17.0; 18.0, 24.0; 24.0, 36.0; 36.0, 48.0;
+                  11.0, 17.0] * 72;
+  endif
+
+  papertype = get (hfig, "papertype");
+  paperunits = get (hfig, "paperunits");
+  paperposition = get (hfig, "paperposition");
+  if (strcmp (papertype, "<custom>"))
+    papersize = get (hfig, "papersize");
+    papersize = convert2points (papersize , paperunits);
+  else
+    papersize = papersizes (strcmp (papertypes, papertype), :);
+  endif
+
+  if (strcmp (paperunits, "normalized"))
+    paperposition = paperposition .* papersize([1,2,1,2]);
+  else
+    paperposition = convert2points (paperposition, paperunits);
+  endif
+
+  ## FIXME - This will be obsoleted by listeners for paper properties.
+  ## Papersize is tall when portrait,and wide when landscape.
+  if ((papersize(1) > papersize(2) && strcmpi (paperorientation, "portrait"))
+      || (papersize(1) < papersize(2) && strcmpi (paperorientation, "landscape")))
+    papersize = papersize ([2,1]);
+    paperposition = paperposition([2,1,4,3]);
+  endif
+
+  if ((! strcmp (papertype, "<custom>")) && (strcmp (paperorientation, "portrait")))
+    ## For portrait use the ghostscript name
+    papersize = papertype;
+    papersize(papersize=="-") = "";
+    papersize = strrep (papersize, "us", "");
+    switch papersize
+    case "a"
+      papersize = "letter";
+    case {"b", "tabloid"}
+      papersize = "11x17";
+    case {"c", "d", "e"}
+      papersize = strcat ("arch", papersize);
+    endswitch
+    if (strncmp (papersize, "arch", 4))
+      papersize(end) = upper (papersize(end));
+    endif
+  endif
+
+endfunction
+
+function value = convert2points (value, units)
+    switch units
+    case {"inches"}
+      value = value * 72;
+    case {"centimeters"}
+      value = value * 72 / 25.4;
+    case {"normalized"}
+      error ("print:customnormalized",
+             "print.m: papersize=='<custom>' and paperunits='normalized' may not be combined.")
+    endswitch
+endfunction
+
--- a/scripts/plot/print.m
+++ b/scripts/plot/print.m
@@ -21,42 +21,46 @@
 ## @deftypefnx {Function File} {} print (@var{options})
 ## @deftypefnx {Function File} {} print (@var{filename}, @var{options})
 ## @deftypefnx {Function File} {} print (@var{h}, @var{filename}, @var{options})
-## Print a plot, or save it to a file.
+## Print a graph, or save it to a file
 ##
-## @var{filename} specifies the name of the output file.  If the
-## file name has no suffix, then one is inferred from the specified
+## @var{filename} defines the file name of the output file.  If the
+## file name has no suffix, one is inferred from the specified
 ## device and appended to the file name.  If no
-## filename is specified the output is sent to the printer.
+## filename is specified, the output is sent to the printer.
 ##
-## @var{h} specifies the figure handle to print.  If no handle is specified
+## @var{h} specifies the figure handle.  If no handle is specified
 ## the handle for the current figure is used.
 ##
 ## @var{options}:
 ##
 ## @table @code
 ## @item -f@var{h}
-##   Specify the handle, @var{h}, of the figure to be printed.  The
-## default is the current figure.
+##   Specify the handle, @var{h}, of the figure to be printed. The
+##   default is the current figure.
 ##
 ## @item -P@var{printer}
-##   Set the @var{printer} name to which the plot is sent when no
-## @var{filename} is specified.
+##   Set the @var{printer} name to which the graph is sent if no
+##   @var{filename} is specified.
 ##
 ## @item -G@var{ghostscript_command}
-##   Specify the command for invoking Ghostscript.  The defaults for Unix and
-## Windows are 'gs' and 'gswin32c' respectively.
+##   Specify the command for calling Ghostscript.  For Unix and Windows,
+## the defaults are 'gs' and 'gswin32c', respectively.
 ##
 ## @item -color
 ## @itemx -mono
-##   Print monochrome or color lines.
+##   Monochrome or color output.
 ##
 ## @item -solid
 ## @itemx -dashed
-##   Print solid or dashed lines.
+##   Forces all lines to be solid or dashed, respectively.
 ##
 ## @item -portrait
 ## @itemx -landscape
-##   Specify the orientation of the plot for printed output.
+##   Specify the orientation of the plot for printed output. For
+## non-printed output the aspect ratio of the output corresponds to
+## the plot area defined by the "paperposition" property in the
+## orientation specified. This options is equivalent to changing
+## the figure's "paperorientation" property.
 ##
 ## @item -d@var{device}
 ##   Output device, where @var{device} is one of:
@@ -65,13 +69,15 @@
 ##   @itemx ps2
 ##   @itemx psc
 ##   @itemx psc2
-##     Postscript (level 1 and 2, mono and color)
+##     Postscript (level 1 and 2, mono and color). The FLTK backend
+## generates Postscript level 3.0.
 ##
 ##   @item eps
 ##   @itemx eps2
 ##   @itemx epsc
 ##   @itemx epsc2
-##     Encapsulated postscript (level 1 and 2, mono and color)
+##     Encapsulated postscript (level 1 and 2, mono and color). The FLTK backend
+## generates Postscript level 3.0.
 ##
 ##   @item tex
 ##   @itemx epslatex
@@ -103,10 +109,10 @@
 ##     Microsoft Enhanced Metafile
 ##
 ##   @item fig
-##     XFig.  If this format is selected the additional options
-## @option{-textspecial} or @option{-textnormal} can be used to control
-## whether the special flag should be set for the text in
-## the figure (default is @option{-textnormal}). 
+##     XFig.  For the Gnuplot backend, the additional options
+##     @option{-textspecial} or @option{-textnormal} can be used to control
+##     whether the special flag should be set for the text in
+##     the figure (default is @option{-textnormal}). 
 ##
 ##   @item hpgl
 ##     HP plotter language
@@ -122,7 +128,7 @@
 ##     JPEG image
 ##
 ##   @item gif
-##     GIF image
+##     GIF image (only available for the Gnuplot backend)
 ##
 ##   @item pbm
 ##     PBMplus
@@ -138,8 +144,8 @@
 ## or if there is no filename it is sent to the printer as postscript.
 ##
 ## @item -d@var{ghostscript_device}
-##   Specify an output device supported by Ghostscript.
-## Some examples are:
+##   Additional devices are supported by Ghostscript.
+## Some examples are;
 ##
 ##   @table @code
 ##   @item ljet2p 
@@ -164,46 +170,44 @@
 ##     Portable Pixel Map file format
 ##
 ##   @item pdfwrite
-##     Converts ps or eps to pdf
+##     Produces pdf output from eps
 ##   @end table
 ##
-##   For a complete list of available formats and devices type
-##   @samp{system ("gs -h")}.
+##   For a complete list, type `system ("gs -h")' to see what formats
+## and devices are available.
 ##
 ##   When Ghostscript output is sent to a printer the size is determined
 ## by the figure's "papersize" property.  When the output 
-## is sent to a file the size is determined by the figure's
-## "paperposition" property.
+## is sent to a file the size is determined by the plot box defined by
+## the figure's "paperposition" property.
 ##
-## @item -append
-##   Append the output to a pre-existing file.  Only PDF
-## and Postscript files are currently supported.
+## @itemx -append
+##   Appends the PS, PDF, or EPS output to a pre-existing file of the 
+## same type.
 ##
-## @item -r@var{NUM}
+## @itemx -r@var{NUM}
 ##   Resolution of bitmaps in pixels per inch.  For both metafiles and 
-## SVG the default is the screen resolution, for others it is 150 dpi.
+## SVG the default is the screen resolution, for other it is 150 dpi.
 ## To specify screen resolution, use "-r0".
 ##
 ## @item -tight
-##   Force a tight bounding box for eps-files.  Because the Ghostscript
-## devices are conversions of an eps-file, this option works for those
+##   Forces a tight bounding box for eps-files.  Since Ghostscript
+## is used to produce other devices, this option works for those
 ## devices as well.
 ##
 ## @item -S@var{xsize},@var{ysize}
-##   Specify plot size in pixels for EMF, GIF, JPEG, PBM, PNG and SVG@.  If
-## using the command form of the print function, the  @var{xsize},@var{ysize}
-## option must be quoted.  For example, by writing
-## @w{@code{"-S640,480"}}.  The size defaults to that specified by the
-## figure's paperposition property.
+##   Plot size in pixels for EMF, GIF, JPEG, PBM, PNG and SVG. For
+## PS, EPS, PDF, and other vector formats the plot size is in points.
+## This option is equivalent to changing the size of the plot box
+## associated with "paperposition" property. Using the command form of
+## the print function, you must quote the @var{xsize},@var{ysize}
+## option.  For example, by writing @w{@code{"-S640,480"}}.
 ##
-## @item  -F@var{fontname}
+## @item -F@var{fontname}
 ## @itemx -F@var{fontname}:@var{size}
 ## @itemx -F:@var{size}
-##   Set the postscript font to @var{fontname} (for use with postscript,
-## aifm, @nospell{corel} and fig).  By default, 'Helvetica' is set for PS/aifm,
-## and 'SwitzerlandLight' for Corel.  It can also be 'Times-Roman'.
-## @var{size} is given in points.  @var{fontname} is ignored for the
-## fig device.
+##   Associates all text with the @var{fontname} and/or @var{fontsize}.
+## @var{fontname} is ignored for some devices; dxf, fig, hpgl, etc.
 ## @end table
 ##
 ## The filename and options can be given in any order.
@@ -225,25 +229,34 @@
   if (strcmp (backend, "gnuplot"))
     ## FIXME - this can be removed when __gnuplot_print__ has been modified
     ##         to work consistently with __fltk_print__
-    __gnuplot_print__ (varargin{:});
+    opts.ghostscript_binary = opts.ghostscript.binary;
+    opts.resolution = opts.ghostscript.resolution;
+    opts.canvas_size = opts.canvas_size * opts.resolution / 72;
+    opts.resolution = sprintf ("%d", opts.resolution);
+    opts.fontsize = sprintf ("%d", opts.fontsize);
+    if (strcmp (opts.devopt, "tiff"))
+      error ("print:notiffoutput",
+             "print.m: TIFF output is not available for the Gnuplot backend.")
+    endif
+    __gnuplot_print__ (opts);
     return
+  else
+    if (strcmp (opts.devopt, "gif"))
+      error ("print:notiffoutput",
+             "print.m: GIF output is not available for the FLTK backend.")
+    endif
   endif
 
-  ## FIXME - this can be moved to __print_parse_opts__ when __gnuplot_print__
-  ##         has been modified to work consistently with __fltk_print__
-  if (! isempty (opts.canvas_size) && ischar (opts.resolution))
-    opts.canvas_size = str2num (strrep (strrep (opts.canvas_size, "X", ""), "Y", ""));
-  endif
-  if (! isempty (opts.resolution) && ischar (opts.resolution))
-    opts.resolution = str2num (opts.resolution);
-  endif
-  if (! isempty (opts.fontsize) && ischar (opts.fontsize))
-    opts.fontsize = str2num (opts.fontsize);
+  if (opts.append_to_file && ! (strncmp (opts.devopt, "pdf", 3)
+         || strncmp (opts.devopt(1:2), "ps", 2)))
+    warning ("print:cannotappendfile", 
+             "print.m: Cannot append files of type '%s'.", opts.devopt)
+    opts.append_to_file = false;
   endif
 
   if (opts.append_to_file)
     saved_original_file = strcat (tmpnam (), ".", opts.devopt);
-    opts.unlink(end+1) = {save_original_file};
+    opts.unlink(end+1) = {saved_original_file};
     movefile (opts.name, saved_original_file);
   endif
 
@@ -251,41 +264,13 @@
   ## FIXME - need an unwind_protect block
   props = [];
 
-  if ((! isempty (opts.canvas_size))
-      || (! strcmpi (get (opts.figure, "paperorientation"), opts.orientation)))
-    m = numel (props);
-    props(m+1).h = opts.figure;
-    props(m+1).name = "paperposition";
-    props(m+1).value = {get(opts.figure, "paperposition")};
-    props(m+2).h = opts.figure;
-    props(m+2).name = "paperunits";
-    props(m+2).value = {get(opts.figure, "paperunits")};
-    props(m+3).h = opts.figure;
-    props(m+3).name = "papersize";
-    props(m+3).value = {get(opts.figure, "papersize")};
-    props(m+4).h = opts.figure;
-    props(m+4).name = "paperorientation";
-    props(m+4).value = {get(opts.figure, "paperorientation")};
-    props(m+5).h = opts.figure;
-    props(m+5).name = "papertype";
-    props(m+5).value = {get(opts.figure, "papertype")};
-    if (! isempty (opts.canvas_size))
-      ## canvas_size is in pixels/points
-      set (opts.figure, "paperorientation", "portrait");
-      set (opts.figure, "paperposition", [0, 0, opts.canvas_size]);
-      set (opts.figure, "paperunits", "points");
-      set (opts.figure, "papersize", opts.canvas_size);
-      fpos = get (opts.figure, "position");
-      props(m+6).h = opts.figure;
-      props(m+6).name = "position";
-      props(m+6).value = {fpos};
-      fpos(3:4) = opts.canvas_size;
-      set (opts.figure, "position", fpos);
-    elseif (opts.paperoutput)
-      ## FIXME - should the backend handle this?
-      orient (opts.orientation)
-    endif
-  endif
+  ## backend tranlates figure position to eps bbox in points
+  fpos = get (opts.figure, "position");
+  props(1).h = opts.figure;
+  props(1).name = "position";
+  props(1).value = {fpos};
+  fpos(3:4) = opts.canvas_size;
+  set (opts.figure, "position", fpos)
 
   if (opts.force_solid != 0)
     h = findobj (opts.figure, "-property", "linestyle");
@@ -364,10 +349,10 @@
 
   ## Send to the printer
   if (opts.send_to_printer)
-    if (isempty (opts.ghostscript_output))
+    if (isempty (opts.ghostscript.output))
       prn_datafile = opts.name;
     else
-      prn_datafile = opts.ghostscript_output;
+      prn_datafile = opts.ghostscript.output;
     endif
     if (isempty (opts.printer))
       prn_cmd = sprintf ("lpr %s '%s' 2>&1", opts.lpr_options, prn_datafile);
@@ -377,6 +362,8 @@
     endif
     if (opts.debug)
       fprintf ("lpr command: %s\n", prn_cmd)
+      [status, output] = system ("lpq");
+      disp (output)
     endif
     [status, output] = system (prn_cmd);
     if (status != 0)
@@ -387,16 +374,21 @@
 
   ## Append to file using GS
   if (opts.append_to_file)
-    if (strcmp (opts.devopt, "pdf"))
+    if (strncmp (opts.devopt, "pdf", 3))
       suffix = "pdf";
-    elseif (strcmp (opts.devopt(1:2), "ps"))
+      device = suffix;
+    elseif (strncmp (opts.devopt(1:2), "ps", 2))
+      ## FIXME - For FLTK the fonts get mangled
+      ##         See the seciton "How to concatenate several PS files" at the link,
+      ##         http://en.wikibooks.org/wiki/PostScript_FAQ
       suffix = "ps";
+      device = suffix;
     endif
     tmp_combined_file = strcat (tmpnam (), ".", suffix);
     opts.unlink{end+1} = tmp_combined_file;
-    gs_opts = "-q -dNOPAUSE -dBATCH";
+    gs_opts = "-dQUIET -dNOPAUSE -dBATCH -dSAFER -dFIXEDMEDIA";
     gs_cmd = sprintf ("%s %s -sDEVICE=%swrite -sOutputFile=%s %s %s", 
-             opts.ghostscript_binary, gs_opts, suffix, tmp_combined_file,
+             opts.ghostscript.binary, gs_opts, device, tmp_combined_file,
              saved_original_file, opts.name);
     [status, output] = system (gs_cmd);
     if (opts.debug)
@@ -405,9 +397,9 @@
     if (status != 0)
       warning ("print:failedtoappendfile", 
                "print.m: failed to append output to file '%s'.", opts.name)
-      movefile (saved_original_file, opts.name);
+      copyfile (saved_original_file, opts.name);
     else
-      movefile (tmp_combined_file, opts.name);
+      copyfile (tmp_combined_file, opts.name);
     endif
   endif
 
@@ -416,7 +408,7 @@
     [status, output] = unlink (opts.unlink{n});
     if (status != 0)
       disp (output)
-      warning ("print.m: failed to delete temporay file, '%s'.", opts.name)
+      warning ("print.m: failed to delete temporay file, '%s'.", opts.unlink{n})
     endif
   endfor
 
--- a/scripts/plot/private/__ghostscript__.m
+++ b/scripts/plot/private/__ghostscript__.m
@@ -22,29 +22,87 @@
 ## Author: Ben Abbott <bpabbott@mac.com>
 ## Created: 2010-07-26
 
-function status = __ghostscript__ (opts, varargin);
+function status = __ghostscript__ (varargin);
 
-  if (nargin > 1)
-    opts.name = varargin{1};
+  opts.binary = "";
+  opts.source = "";
+  opts.output = "";
+  opts.device = "";
+  opts.epscrop = false;
+  opts.antialiasing  = false;
+  opts.resolution = 150;
+  opts.papersize = "";
+  opts.pageoffset = [0 0];
+  opts.debug = false;
+
+  offsetfile = "";
+
+  args = varargin;
+  n = find (cellfun (@isstruct, args));
+  if (! isempty (n))
+    f = fieldnames (args{n});
+    for m = 1:numel(f)
+      opts.(f{m}) = args{n}.(f{m});
+    endfor
+    args(n) = [];
   endif
-  if (nargin > 2)
-    opts.ghostscript_device = varargin{2};
-  endif
-  if (nargin > 3)
-    opts.ghostscript_output = varargin{3};
+  for n = 1:2:numel(args)
+    opts.(args{n}) = args{n+1};
+  endfor
+
+  gs_opts = sprintf ("-dQUIET -dNOPAUSE -dBATCH -dSAFER -sDEVICE=%s", opts.device);
+  if (opts.antialiasing)
+    gs_opts = sprintf ("%s -dTextAlphaBits=4 -dGraphicsAlphaBits=4", gs_opts);
+    gs_opts = sprintf ("%s -r%dx%d", gs_opts, [1, 1] * opts.resolution);
+  elseif (any (strcmp (opts.device, {"pswrite", "ps2write", "pdfwrite"})))
+    gs_opts = sprintf ("%s -dEmbedAllFonts=true", gs_opts);
+    if (strcmp (opts.device, "pdfwrite"))
+      ## Optimize for loading
+      gs_opts = sprintf ("%s -dOptimize=true", gs_opts);
+    endif
   endif
 
-  if (strncmp (opts.devopt, "eps", 3))
-    ## "eps" files
-    gs_opts = "-q -dNOPAUSE -dBATCH -dSAFER -dEPSCrop";
-  else
-    ## "ps" or "pdf" files
-    gs_opts = "-q -dNOPAUSE -dBATCH -dSAFER";
+  if (opts.epscrop)
+    ## papersize is specified by the eps bbox
+    gs_opts = sprintf ("%s -dEPSCrop", gs_opts);
+  elseif (! isempty (opts.papersize))
+    if (ischar (opts.papersize))
+      gs_opts = sprintf ("%s -sPAPERSIZE=%s", gs_opts, opts.papersize);
+    elseif (isnumeric (opts.papersize) && numel (opts.papersize) == 2)
+      gs_opts = sprintf ("%s -dDEVICEWIDTHPOINTS=%d -dDEVICEHEIGHTPOINTS=%d", gs_opts, opts.papersize);
+      if (opts.papersize(1) > opts.papersize(2))
+        ## Lanscape mode: This option will result in automatic rotation of the document page if the
+        ##                requested page size matches one of the default page sizes
+        gs_opts = sprintf ("%s -dNORANGEPAGESIZE", gs_opts);
+      endif
+    else
+      error ("print:badpapersize", "__ghostscript__.m: invalid 'papersize'")
+    endif
+    gs_opts = sprintf ("%s -dFIXEDMEDIA", gs_opts);
+    offsetfile = strcat (tmpnam (), ".ps");
+    fid = fopen (offsetfile, "w");
+    if (fid == -1)
+      error ("print:fopenfailed", "__ghostscript__.m: fopen() failed.");
+    endif
+    fprintf (fid, "%s\n", "%!PS-Adobe-3.0")
+    fprintf (fid, "%s [%d %d] %s\n", "<< /Margins [0 0] /.HWMargins [0 0 0 0] /PageOffset",
+             opts.pageoffset, ">> setpagedevice");
+    fprintf (fid, "%%EOF");
+    status = fclose (fid);
+    if (status == -1)
+      error ("print:fclosefailed", "__ghostscript__.m: fclose() failed.");
+    endif
+    if (opts.debug)
+      [~,output] = system (sprintf ("cat %s", offsetfile));
+      fprintf ("---- begin %s ----\n", offsetfile)
+      disp (output)
+      fprintf ("----- end %s -----\n", offsetfile)
+    endif
   endif
 
-  cmd = sprintf ("%s %s -sDEVICE=%s -r%d -sOutputFile=%s %s", 
-                 opts.ghostscript_binary, gs_opts, opts.ghostscript_device,
-                 opts.resolution, opts.ghostscript_output, opts.name);
+  cmd = sprintf ("%s %s -sOutputFile=%s %s %s", 
+                 opts.binary, gs_opts,
+                 opts.output, offsetfile, opts.source);
 
   if (opts.debug)
     fprintf ("Ghostscript command: %s\n", cmd);
@@ -54,7 +112,9 @@
 
   if (status != 0)
     warning ("print:ghostscripterror", 
-             "print.m: gs failed to convert output to file '%s'.", opts.ghostscript_output)
+             "print.m: ghostscript failed to convert output to file '%s'.", opts.output)
   endif
 
 endfunction
+
+