# HG changeset patch
# User Pantxo Diribarne <pantxo.diribarne@gmail.com>
# Date 1519944112 -3600
#      Thu Mar 01 23:41:52 2018 +0100
# Node ID 240a73b15c2a794fb8bfd3003a10d44d4368b653
# Parent  735175432a20dcc373f30b0b09d149160d17e4b1
print.m: Implement "-opengl", "-painters" and "-RGBImage" options (bug #52866)

* __print_parse_opt__: add "rgb_ouput" and "renderer" fields to option
  structure. Handle "opengl" renderer and use it for all raster outputs
  supported by imwrite and for "-RGBImage" option.

* print.m (doc): Reorder options documentation and describe "-RGBImage". Use
  getframe and eventually imwrite when the renderer is "opengl".

* genpropdoc.m: Document "renderer" and "renderermode" figure properties.

diff -r 735175432a20 -r 240a73b15c2a doc/interpreter/genpropdoc.m
--- a/doc/interpreter/genpropdoc.m	Fri Mar 02 13:46:45 2018 +0100
+++ b/doc/interpreter/genpropdoc.m	Thu Mar 01 23:41:52 2018 +0100
@@ -516,10 +516,13 @@
         s.valid = valid_4elvec;
 
       case "renderer"
-        s.doc = doc_unused;
+        s.doc = "Renderering engine used for printing when @code{renderermode} \
+is \"manual\".  __modemsg__.";
 
       case "renderermode"
-        s.doc = doc_unused;
+        s.doc = "Control wheteher the renderering engine used for printing is \
+chosen automatically or specified by the @code{renderer} property.  \
+@xref{XREFprint, , @w{print function}}.";
 
       case "resize"
         s.doc = doc_unused;
diff -r 735175432a20 -r 240a73b15c2a scripts/plot/util/print.m
--- a/scripts/plot/util/print.m	Fri Mar 02 13:46:45 2018 +0100
+++ b/scripts/plot/util/print.m	Thu Mar 01 23:41:52 2018 +0100
@@ -21,20 +21,32 @@
 ## @deftypefnx {} {} print (@var{options})
 ## @deftypefnx {} {} print (@var{filename}, @var{options})
 ## @deftypefnx {} {} print (@var{h}, @var{filename}, @var{options})
-## Print a plot, or save it to a file.
-##
-## Both output formatted for printing (PDF and PostScript), and many bitmapped
-## and vector image formats are supported.
+## @deftypefnx {} {@var{rgb} = } print (@var{-RGBImage}, @dots{})
+## Format a figure and send it to a printer, save it to a file or
+## return an RGB image.
 ##
 ## @var{filename} defines the name of the output file.  If the filename has
 ## no suffix, one is inferred from the specified device and appended to the
-## filename.  If no filename is specified, the output is sent to the
-## printer.
+## filename.  In absence of a filename or "-RGBImage" option, the output is
+## sent to the printer.
+## The filename and options can be given in any order.
+##
+## Example: Print to a file using the pdf and jpeg formats.
+##
+## @example
+## @group
+## figure (1);
+## clf ();
+## surf (peaks);
+## print figure1.pdf   # The extension specifies the format
+## print -djpg figure1 # Will produce "figure1.jpg" file
+## @end group
+## @end example
 ##
 ## @var{h} specifies the handle of the figure to print.  If no handle is
 ## specified the current figure is used.
 ##
-## For output to a printer, PostScript file, or PDF file, the paper size is
+## For outputs to paged formats, PostScript and PDF, the paper size is
 ## specified by the figure's @code{papersize} property.  The location and
 ## size of the image on the page are specified by the figure's
 ## @code{paperposition} property.  The orientation of the page is specified
@@ -50,21 +62,47 @@
 ##   Specify the handle, @var{h}, of the figure to be printed.  The default
 ## is the current figure.
 ##
+## Example: Print figure 1.
+##
+## @example
+## @group
+## figure (1);
+## clf ();
+## surf (peaks);
+## figure (2);
+## print -f1 figure1.pdf
+## ## Equivalent functional form:
+## print (1, "figure1.pdf")
+## @end group
+## @end example
+##
 ## @item -P@var{printer}
 ##   Set the @var{printer} name to which the plot is sent if no
 ## @var{filename} is specified.
 ##
-## @item -G@var{ghostscript_command}
-##   Specify the command for calling Ghostscript.  For Unix and Windows the
-## defaults are @qcode{"gs"} and @qcode{"gswin32c"}, respectively.
+## Example: Print to printer named PS_printer using ps format.
 ##
-## @item  -color
-## @itemx -mono
-##   Color or monochrome output.
+## @example
+## @group
+## clf ();
+## surf (peaks);
+## print -dpswrite -PPS_printer
+## @end group
+## @end example
 ##
-## @item  -solid
-## @itemx -dashed
-##   Force all lines to be solid or dashed, respectively.
+## @item -RGBImage
+##   Return an M-by-N-by-3 RGB image of the figure. The size of the image
+## depends on the formating options.
+##
+## Example: Get the pixels of a figure image.
+##
+## @example
+## @group
+## clf ();
+## surf (peaks);
+## rgb = print ("-RGBImage");
+## @end group
+## @end example
 ##
 ## @item  -portrait
 ## @itemx -landscape
@@ -74,13 +112,74 @@
 ## orientation specified.  This option is equivalent to changing the figure's
 ## @qcode{"paperorientation"} property.
 ##
-## @item  -TextAlphaBits=@var{n}
-## @itemx -GraphicsAlphaBits=@var{n}
-##   Octave is able to produce output for various printers, bitmaps, and
-## vector formats by using Ghostscript.  For bitmap and printer output
-## anti-aliasing is applied using Ghostscript's TextAlphaBits and
-## GraphicsAlphaBits options.  The default number of bits are 4 and 1
-## respectively.  Allowed values for @var{N} are 1, 2, or 4.
+## @item -append
+##   Append PostScript or PDF output to a pre-existing file of the same type.
+##
+## @item -r@var{NUM}
+##   Resolution of bitmaps in pixels per inch.  For both metafiles and SVG
+## the default is the screen resolution; for other formats it is 150 dpi.  To
+## specify screen resolution, use @qcode{"-r0"}.
+##
+## Example: Get high resolution raster output.
+##
+## @example
+## @group
+## clf ();
+## surf (peaks);
+## light
+## print ("-r600", "lit_peaks.png");
+## @end group
+## @end example
+##
+## @item -S@var{xsize},@var{ysize}
+##   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 the @qcode{"paperposition"} property.  When using the command form of
+## the print function you must quote the @var{xsize},@var{ysize} option.  For
+## example, by writing @w{"-S640,480"}.
+##
+## @item  -painters
+## @itemx -opengl
+##   For raster formats, specifies which of the opengl (pixel based) or painters
+## (vector based) renderers is used.  This is equivalent to changing the
+#  figure's "renderer" property.  By default the renderer is "opengl" for
+## raster formats and "painters" for vector formats.
+##
+## @item  -loose
+## @itemx -tight
+##   Force a tight or loose bounding box for eps files.  The default is loose.
+##
+## @item -@var{preview}
+##   Add a preview to eps files.  Supported formats are:
+##
+##   @table @code
+##   @item -interchange
+##     Provide an interchange preview.
+##
+##   @item -metafile
+##     Provide a metafile preview.
+##
+##   @item -pict
+##     Provide pict preview.
+##
+##   @item -tiff
+##     Provide a tiff preview.
+##   @end table
+##
+## @item  -F@var{fontname}
+## @itemx -F@var{fontname}:@var{size}
+## @itemx -F:@var{size}
+##   Use @var{fontname} and/or @var{fontsize} for all text.
+## @var{fontname} is ignored for some devices: dxf, fig, hpgl, etc.
+##
+## @item  -color
+## @itemx -mono
+##   Color or monochrome output.
+##
+## @item  -solid
+## @itemx -dashed
+##   Force all lines to be solid or dashed, respectively.
 ##
 ## @item -d@var{device}
 ##   The available output format is specified by the option @var{device}, and
@@ -231,87 +330,23 @@
 ## file the size is determined by the plot box defined by the figure's
 ## @qcode{"paperposition"} property.
 ##
-## @item -append
-##   Append PostScript or PDF output to a pre-existing file of the same type.
-##
-## @item -r@var{NUM}
-##   Resolution of bitmaps in pixels per inch.  For both metafiles and SVG
-## the default is the screen resolution; for other formats it is 150 dpi.  To
-## specify screen resolution, use @qcode{"-r0"}.
-##
-## @item  -loose
-## @itemx -tight
-##   Force a tight or loose bounding box for eps files.  The default is loose.
-##
-## @item -@var{preview}
-##   Add a preview to eps files.  Supported formats are:
-##
-##   @table @code
-##   @item -interchange
-##     Provide an interchange preview.
+## @item -G@var{ghostscript_command}
+##   Specify the command for calling Ghostscript.  For Unix and Windows the
+## defaults are @qcode{"gs"} and @qcode{"gswin32c"}, respectively.
 ##
-##   @item -metafile
-##     Provide a metafile preview.
-##
-##   @item -pict
-##     Provide pict preview.
-##
-##   @item -tiff
-##     Provide a tiff preview.
-##   @end table
-##
-## @item -S@var{xsize},@var{ysize}
-##   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 the @qcode{"paperposition"} property.  When using the command form of
-## the print function you must quote the @var{xsize},@var{ysize} option.  For
-## example, by writing @w{"-S640,480"}.
-##
-## @item  -F@var{fontname}
-## @itemx -F@var{fontname}:@var{size}
-## @itemx -F:@var{size}
-##   Use @var{fontname} and/or @var{fontsize} for all text.
-## @var{fontname} is ignored for some devices: dxf, fig, hpgl, etc.
+## @item  -TextAlphaBits=@var{n}
+## @itemx -GraphicsAlphaBits=@var{n}
+##   Octave is able to produce output for various printers, bitmaps, and
+## vector formats by using Ghostscript.  For bitmap and printer output
+## anti-aliasing is applied using Ghostscript's TextAlphaBits and
+## GraphicsAlphaBits options.  The default number of bits are 4 and 1
+## respectively.  Allowed values for @var{N} are 1, 2, or 4.
 ## @end table
 ##
-## The filename and options can be given in any order.
-##
-## Example: Print to a file using the pdf device.
-##
-## @example
-## @group
-## figure (1);
-## clf ();
-## surf (peaks);
-## print figure1.pdf
-## @end group
-## @end example
-##
-## Example: Print to a file using jpg device.
-##
-## @example
-## @group
-## clf ();
-## surf (peaks);
-## print -djpg figure2.jpg
-## @end group
-## @end example
-##
-## Example: Print to printer named PS_printer using ps format.
-##
-## @example
-## @group
-## clf ();
-## surf (peaks);
-## print -dpswrite -PPS_printer
-## @end group
-## @end example
-##
-## @seealso{saveas, hgsave, orient, figure}
+## @seealso{saveas, hgsave, getframe, orient, figure}
 ## @end deftypefn
 
-function print (varargin)
+function rgbout = print (varargin)
 
   opts = __print_parse_opts__ (varargin{:});
 
@@ -391,7 +426,8 @@
     ## using gl2ps. For other formats, switch grid lines to light gray
     ## so that the image output approximately matches on-screen experience.
     hax = findall (opts.figure, "type", "axes");
-    if (! strcmp (tk, "gnuplot") && ! strcmp (opts.devopt, "svg"))
+    if (! strcmp (tk, "gnuplot") && ! strcmp (opts.devopt, "svg")
+        && ! strcmp (opts.renderer, "opengl"))
       for n = 1:numel (hax)
         if (strcmp (get (hax(n), "gridcolormode"), "auto"))
           props(end+1).h = hax(n);
@@ -480,6 +516,19 @@
       set (h, "linestyle", linestyle);
     endif
 
+    ## Scale linewidth when using opengl renderer
+    if (strcmp (opts.renderer, "opengl"))
+      h = findall (opts.figure, "-property", "linewidth");
+      m = numel (props);
+      for n = 1:numel (h)
+        linewidth = get(h(n), "linewidth");
+        props(m+n).h = h(n);
+        props(m+n).name = "linewidth";
+        props(m+n).value = {linewidth};
+        set (h(n), "linewidth", linewidth * opts.scalefontsize);
+      endfor
+    endif
+
     if (opts.use_color < 0)
       color_props = {"color", "facecolor", "edgecolor", "colormap"};
       for c = 1:numel (color_props)
@@ -506,7 +555,8 @@
       endfor
     endif
 
-    if (! isempty (opts.font) || ! isempty (opts.fontsize))
+    if (strcmp (opts.renderer, "opengl") || ! isempty (opts.font)
+        || ! isempty (opts.fontsize))
       h = findall (opts.figure, "-property", "fontname");
       m = numel (props);
       for n = 1:numel (h)
@@ -516,34 +566,45 @@
             props(end).name = "fontname";
             props(end).value = {get(h(n), "fontname")};
           endif
-        endif
-        if (ishghandle (h(n)))
-          if (! isempty (opts.fontsize))
+          
+          if (! isempty (opts.fontsize)
+              || (strcmp (opts.renderer, "opengl")
+                  && opts.scalefontsize != 1))
             props(end+1).h = h(n);
             props(end).name = "fontsize";
             props(end).value = {get(h(n), "fontsize")};
           endif
         endif
       endfor
+      
       if (! isempty (opts.font))
         set (h(ishghandle (h)), "fontname", opts.font);
       endif
-      if (! isempty (opts.fontsize))
-        if (ischar (opts.fontsize))
-          fontsize = str2double (opts.fontsize);
+      
+      if (! isempty (opts.fontsize) || strcmp (opts.renderer, "opengl"))
+        if (isempty (opts.fontsize))
+          fontsize = get (h(ishghandle (h)), "fontsize");
+        elseif (ischar (opts.fontsize))
+          fontsize = {str2double (opts.fontsize)};
         else
-          fontsize = opts.fontsize;
+          fontsize = {opts.fontsize};
         endif
+        
         if (! isempty (opts.scalefontsize) && ! opts.scalefontsize != 1)
           ## This is done to work around the bbox being whole numbers.
-          fontsize *= opts.scalefontsize;
+          fontsize = cellfun (@(x) x*opts.scalefontsize, fontsize, ...
+                              "uniformoutput", false);
         endif
         ## FIXME: legend child objects need to be acted on first.
         ##        or legend fontsize callback will destroy them.
         hlist = h(ishghandle (h));
         haxes = strcmp (get (hlist, "type"), "axes");
-        set (hlist(! haxes), "fontsize", fontsize);
-        set (hlist(haxes), "fontsize", fontsize);
+        for ii = 1:numel (hlist(! haxes))
+          set (hlist(! haxes)(ii), "fontsize", fontsize(! haxes){ii});
+        endfor
+        for ii = 1:numel (hlist(haxes))
+          set (hlist(haxes)(ii), "fontsize", fontsize(haxes){ii});
+        endfor
       endif
     endif
 
@@ -552,7 +613,15 @@
       case "gnuplot"
         opts = __gnuplot_print__ (opts);
       otherwise
-        opts = __opengl_print__ (opts);
+        if (strcmp (opts.renderer, "opengl"))
+          if (opts.rgb_output)
+            rgbout = getframe (opts.figure).cdata;
+          else
+            imwrite (getframe (opts.figure).cdata, opts.name);
+          endif
+        else
+          opts = __opengl_print__ (opts);
+        endif
     endswitch
 
   unwind_protect_cleanup
diff -r 735175432a20 -r 240a73b15c2a scripts/plot/util/private/__print_parse_opts__.m
--- a/scripts/plot/util/private/__print_parse_opts__.m	Fri Mar 02 13:46:45 2018 +0100
+++ b/scripts/plot/util/private/__print_parse_opts__.m	Thu Mar 01 23:41:52 2018 +0100
@@ -45,9 +45,8 @@
   arg_st.ghostscript.epscrop = true;
   arg_st.ghostscript.level = 2;
   arg_st.ghostscript.output = "";
-  arg_st.ghostscript.papersize = "";
+  arg_st.ghostscript.papersize = "letter";
   arg_st.ghostscript.pageoffset = [];
-  arg_st.ghostscript.resolution = 150;
   arg_st.ghostscript.antialiasing = false;
   arg_st.ghostscript.antialiasing_textalphabits = 4;
   arg_st.ghostscript.antialiasing_graphicsalphabits = 1;
@@ -58,6 +57,9 @@
   arg_st.pstoedit_binary = __quote_path__ (__find_binary__ ("pstoedit"));
   arg_st.preview = "";
   arg_st.printer = "";
+  arg_st.renderer = "auto";
+  arg_st.resolution = 150;
+  arg_st.rgb_output = false;
   arg_st.send_to_printer = false;
   arg_st.special_flag = "textnormal";
   arg_st.tight_flag = false;
@@ -76,7 +78,7 @@
     arg_st.figure = varargin{1};
     varargin(1) = [];
   endif
-
+  
   for i = 1:numel (varargin)
     arg = strtrim (varargin{i});
     if (ischar (arg))
@@ -90,6 +92,11 @@
         arg_st.force_solid = 1;
       elseif (strcmp (arg, "-dashed"))
         arg_st.force_solid = -1;
+      elseif (any (strcmp (arg, {"-opengl", "-painters"})))
+        arg_st.renderer = arg(2:end);
+      elseif (strcmp (arg, "-RGBImage"))
+        arg_st.rgb_output = true;
+        arg_st.renderer = "opengl";
       elseif (strncmp (arg, "-portrait", length (arg)))
         arg_st.orientation = "portrait";
       elseif (strncmp (arg, "-landscape", length (arg)))
@@ -151,11 +158,9 @@
       elseif (length (arg) > 2 && arg(1:2) == "-S")
         arg_st.canvas_size = str2double (strsplit (arg(3:end), ","));
       elseif (length (arg) > 2 && arg(1:2) == "-r")
-        arg_st.ghostscript.resolution = str2double (arg(3:end));
+        arg_st.resolution = str2double (arg(3:end));
       elseif (length (arg) > 2 && arg(1:2) == "-f")
         arg_st.figure = str2double (arg(3:end));
-      elseif (any (strcmp (arg, {"-painters", "-opengl"})))
-        warning ("print: '%s' accepted for Matlab compatibility, but is ignored", arg);
       elseif (strcmp (arg, "-noui"))
         warning ("print: option '-noui' not yet implemented");
       elseif (length (arg) >= 1 && arg(1) == "-")
@@ -169,10 +174,10 @@
       error ("print: first argument must be string or figure handle");
     endif
   endfor
-
-  if (arg_st.ghostscript.resolution == 0)
+  
+  if (arg_st.resolution == 0)
     ## Do as Matlab does.
-    arg_st.ghostscript.resolution = get (0, "screenpixelsperinch");
+    arg_st.resolution = get (0, "screenpixelsperinch");
   endif
 
   if (isempty (arg_st.orientation))
@@ -186,13 +191,37 @@
 
   dot = rindex (arg_st.name, ".");
   if (isempty (arg_st.devopt))
-    if (dot == 0)
+    if (arg_st.rgb_output)
+      arg_st.devopt = "png";
+    elseif (dot == 0)
       arg_st.devopt = "psc";
     else
       arg_st.devopt = tolower (arg_st.name(dot+1:end));
     endif
   endif
 
+  ## The opengl renderer is only available for raster outputs
+  fmts = imformats ();
+  persistent gl_devlist = [fmts(! cellfun (@isempty, {fmts.write})).ext];
+  opengl_ok = any (strcmp (gl_devlist, arg_st.devopt));
+  
+  if (strcmp (arg_st.renderer, "auto")
+      && strcmp (get (arg_st.figure, "renderermode"), "manual"))
+    arg_st.renderer = get (arg_st.figure, "renderer");
+  endif
+
+  if (strcmp (arg_st.renderer, "auto"))
+    if (opengl_ok)
+      arg_st.renderer = "opengl";
+    else
+      arg_st.renderer = "painters";
+    endif
+  elseif (strcmp (arg_st.renderer, "opengl") && ! opengl_ok)
+    arg_st.renderer = "painters";
+    warning (["print: unsupported output format \"%s\" for renderer ", ...
+              "\"opengl\"."], arg_st.devopt);
+  endif
+  
   if (arg_st.use_color == 0)
     if (any (strcmp ({"ps", "ps2", "eps", "eps2"}, arg_st.devopt)))
       arg_st.use_color = -1;
@@ -213,7 +242,7 @@
     arg_st.devopt = "jpeg";
   endif
 
-  persistent dev_list = {"aifm", "corel", "fig", "png", "jpeg", ...
+  persistent dev_list = [{"aifm", "corel", "fig", "png", "jpeg", ...
               "gif", "pbm", "pbmraw", "dxf", "mf", ...
               "svg", "hpgl", "ps", "ps2", "psc", ...
               "psc2", "eps", "eps2", "epsc", "epsc2", ...
@@ -225,9 +254,10 @@
               "epscairo", "pdfcairo", "pngcairo", "cairolatex", ...
               "pdfcairolatex", "pdfcairolatexstandalone", ...
               "epscairolatex", "epscairolatexstandalone", "pstricks", ...
-              "epswrite", "eps2write", "pswrite", "ps2write", "pdfwrite"};
+              "epswrite", "eps2write", "pswrite", "ps2write", "pdfwrite"}, ...
+                         gl_devlist];
 
-  persistent suffixes = {"ai", "cdr", "fig", "png", "jpg", ...
+  persistent suffixes = [{"ai", "cdr", "fig", "png", "jpg", ...
               "gif", "pbm", "pbm", "dxf", "mf", ...
               "svg", "hpgl", "ps", "ps", "ps", ...
               "ps", "eps", "eps", "eps", "eps", ...
@@ -239,7 +269,7 @@
               "eps", "pdf", "png", "tex", ...
               "tex", "tex", ...
               "tex", "tex", "tex", ...
-              "eps", "eps", "ps", "ps", "pdf"};
+              "eps", "eps", "ps", "ps", "pdf"}, gl_devlist];
 
   if (isfigure (arg_st.figure))
     __graphics_toolkit__ = get (arg_st.figure, "__graphics_toolkit__");
@@ -333,16 +363,22 @@
   elseif (isempty (arg_st.name))
     error ("print: an output filename must be specified");
   endif
-
+  
   if (isempty (arg_st.canvas_size))
     if (isfigure (arg_st.figure))
-      [arg_st.ghostscript.papersize, paperposition] = ...
-                           gs_papersize (arg_st.figure, arg_st.orientation);
+      if (strcmp (arg_st.renderer, "opengl"))
+        paperposition = get (arg_st.figure, "paperposition") * ...
+                        arg_st.resolution;
+        arg_st.scalefontsize = arg_st.resolution / 72;
+      else
+        [arg_st.ghostscript.papersize, paperposition] = ...
+           gs_papersize (arg_st.figure, arg_st.orientation);
+      endif
     else
       ## allows BIST 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);
     if (strcmp (__graphics_toolkit__, "gnuplot")
         && ! arg_st.ghostscript.epscrop)
@@ -352,18 +388,18 @@
     endif
   else
     ## Convert canvas size to points from pixels.
-    if (! isempty (arg_st.fontsize))
+    if (! isempty (arg_st.fontsize) || strcmp (arg_st.renderer, "opengl"))
       ## Work around the eps bbox having whole numbers (both gnuplot & gl2ps).
-      arg_st.scalefontsize = arg_st.ghostscript.resolution / 72;
+      arg_st.scalefontsize = arg_st.resolution / 72;
     endif
-    arg_st.ghostscript.resolution = 72;
+    arg_st.resolution = 72;
     arg_st.ghostscript.papersize = arg_st.canvas_size;
     arg_st.ghostscript.epscrop = true;
     arg_st.ghostscript.pageoffset = [0, 0];
   endif
 
   if (arg_st.formatted_for_printing)
-    arg_st.ghostscript.resolution = [];
+    arg_st.resolution = [];
   else
     arg_st.ghostscript.papersize = "";
     arg_st.ghostscript.pageoffset = [0, 0];
