changeset 25998:8d2b3e3ff182

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". When the renderer is "opengl", change __device_pixel_ratio__ to draw the figure at the expected resolution and make use of getframe and eventually imwrite to produce an image file. * genpropdoc.m: Document "renderer" and "renderermode" figure properties. * NEWS: announce the addition of new option and the new behavior for raster formats. * geometryimages.m, interpimages.m, splineimages.m: Use the same size for all images in the manual. * graphics.cc (update_text_pos): Call axes::properties::sync_positions instead of individual label update methods. (axes::properties::get_extent): Scale the label extent in order to work with logical pixels. * GLCanvas.cc (GLCanvas::do_getPixels): When using a framebuffer object, scale its size with the __device_pixel_ratio__ and set the renderer's device_pixel_ration accordingly.
author Pantxo Diribarne <pantxo.diribarne@gmail.com>
date Thu, 01 Mar 2018 23:41:52 +0100
parents 22f4f26fcaf2
children f5e08983d07c
files NEWS doc/interpreter/genpropdoc.m doc/interpreter/geometryimages.m doc/interpreter/interpimages.m doc/interpreter/splineimages.m libgui/graphics/GLCanvas.cc libinterp/corefcn/gl-render.cc libinterp/corefcn/graphics.cc scripts/plot/util/print.m scripts/plot/util/private/__print_parse_opts__.m
diffstat 10 files changed, 267 insertions(+), 142 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Thu Nov 01 16:50:27 2018 +0100
+++ b/NEWS	Thu Mar 01 23:41:52 2018 +0100
@@ -64,6 +64,14 @@
  ** "FaceNormals" and "EdgeNormals" for patch and surface graphic
     objects are now calculated automatically if necessary.
 
+ ** Printing to raster formats now uses an opengl based method by default.
+    The print options "-opengl" and "-painters" have been added (for "qt"
+    toolkit only) and the corresponding figure properties "renderer" and 
+    "renderermode" are now also used when printing.
+
+ ** The print option "-RGBImage" has been added. It allows for retrieving
+    image pixels of a formated figure instead of printing to raster format.
+
  ** Printing using the -dtiff output device will now create compressed
     images using lzw compression.  This change was made for Matlab
     compatibility.  To produce uncompressed images use the -dtiffn
--- a/doc/interpreter/genpropdoc.m	Thu Nov 01 16:50:27 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 whether 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 = "Control whether the figure can be resized by dragging the \
--- a/doc/interpreter/geometryimages.m	Thu Nov 01 16:50:27 2018 +0100
+++ b/doc/interpreter/geometryimages.m	Thu Mar 01 23:41:52 2018 +0100
@@ -156,7 +156,7 @@
 endfunction
 
 function set_print_size ()
-  image_size = [8.0, 6.0]; # in inches, 4:3 format
+  image_size = [5.0, 3.5]; # in inches, 16:9 format
   border = 0;              # For postscript use 50/72
   set (groot, "defaultfigurepapertype", "<custom>");
   set (groot, "defaultfigurepaperorientation", "landscape");
--- a/doc/interpreter/interpimages.m	Thu Nov 01 16:50:27 2018 +0100
+++ b/doc/interpreter/interpimages.m	Thu Mar 01 23:41:52 2018 +0100
@@ -99,7 +99,7 @@
 endfunction
 
 function set_print_size ()
-  image_size = [8.0, 6.0]; # in inches, 4:3 format
+  image_size = [5.0, 3.5]; # in inches, 16:9 format
   border = 0;              # For postscript use 50/72
   set (groot, "defaultfigurepapertype", "<custom>");
   set (groot, "defaultfigurepaperorientation", "landscape");
--- a/doc/interpreter/splineimages.m	Thu Nov 01 16:50:27 2018 +0100
+++ b/doc/interpreter/splineimages.m	Thu Mar 01 23:41:52 2018 +0100
@@ -189,7 +189,7 @@
 endfunction
 
 function set_print_size ()
-  image_size = [8.0, 6.0]; # in inches, 4:3 format
+  image_size = [5.0, 3.5]; # in inches, 16:9 format
   border = 0;              # For postscript use 50/72
   set (groot, "defaultfigurepapertype", "<custom>");
   set (groot, "defaultfigurepaperorientation", "landscape");
--- a/libgui/graphics/GLCanvas.cc	Thu Nov 01 16:50:27 2018 +0100
+++ b/libgui/graphics/GLCanvas.cc	Thu Mar 01 23:41:52 2018 +0100
@@ -89,6 +89,9 @@
     if (go && go.isa ("figure"))
       {
         Matrix pos = go.get ("position").matrix_value ();
+        double dpr = go.get ("__device_pixel_ratio__").double_value ();
+        pos(2) *= dpr;
+        pos(3) *= dpr;
 
         // Make sure we have a valid current context
         if (! begin_rendering ())
@@ -101,11 +104,13 @@
             || go.get ("__printing__").string_value () == "on")
           {
             OCTAVE_QT_OPENGL_FBO
-            fbo (pos(2), pos(3),OCTAVE_QT_OPENGL_FBO::Attachment::Depth);
+            fbo (pos(2), pos(3),
+                 OCTAVE_QT_OPENGL_FBO::Attachment::Depth);
 
             fbo.bind ();
 
             m_renderer.set_viewport (pos(2), pos(3));
+            m_renderer.set_device_pixel_ratio (dpr);
             m_renderer.draw (go);
             retval = m_renderer.get_pixels (pos(2), pos(3));
 
@@ -114,6 +119,7 @@
         else
           {
             m_renderer.set_viewport (pos(2), pos(3));
+            m_renderer.set_device_pixel_ratio (dpr);
             m_renderer.draw (go);
             retval = m_renderer.get_pixels (pos(2), pos(3));
           }
--- a/libinterp/corefcn/gl-render.cc	Thu Nov 01 16:50:27 2018 +0100
+++ b/libinterp/corefcn/gl-render.cc	Thu Mar 01 23:41:52 2018 +0100
@@ -1147,8 +1147,9 @@
 
     m_glfcns.glPixelStorei (GL_PACK_ALIGNMENT, 1);
     uint8NDArray pix(dim_vector (3, width, height), 0);
+
     m_glfcns.glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE,
-                 pix.fortran_vec ());
+                          pix.fortran_vec ());
 
     // Permute and flip data
     Array<octave_idx_type> perm (dim_vector (3, 1));
--- a/libinterp/corefcn/graphics.cc	Thu Nov 01 16:50:27 2018 +0100
+++ b/libinterp/corefcn/graphics.cc	Thu Mar 01 23:41:52 2018 +0100
@@ -2116,11 +2116,7 @@
           axes::properties& ap
             = dynamic_cast<axes::properties&> (go.get_properties ());
           ap.update_font ();
-          ap.update_xlabel_position ();
-          ap.update_ylabel_position ();
-          ap.update_zlabel_position ();
-          ap.update_title_position ();
-          ap.update_axes_layout ();
+          ap.sync_positions ();
         }
     }
 }
@@ -6814,6 +6810,13 @@
             {
               Matrix text_ext = text_props.get_extent_matrix ();
 
+              // The text extent is returned in device pixels. Unscale and
+              // work with logical pixels
+              double dpr = device_pixel_ratio (get___myhandle__ ());
+              if (dpr != 1.0)
+                for (int j = 0; j < 4; j++)
+                  text_ext(j) /= dpr;
+
               bool ignore_horizontal = false;
               bool ignore_vertical = false;
               if (only_text_height)
--- a/scripts/plot/util/print.m	Thu Nov 01 16:50:27 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.
 ##
-## @var{h} specifies the handle of the figure to print.  If no handle is
-## specified the current figure is used.
+## @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
 ##
-## For output to a printer, PostScript file, or PDF file, the paper size is
+## If the first argument @var{h} is a handle to a figure object, it specifies
+## the figure to print.  By default the current figure is printed.
+##
+## 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.
+##
+## @example
+## @group
+## clf ();
+## surf (peaks);
+## print -dpswrite -PPS_printer
+## @end group
+## @end example
 ##
-## @item  -color
-## @itemx -mono
-##   Color or monochrome output.
+## @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.
 ##
-## @item  -solid
-## @itemx -dashed
-##   Force all lines to be solid or dashed, respectively.
+## @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 (), "facelighting", "gouraud");
+## 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
@@ -241,104 +340,42 @@
 ## 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{:});
 
-  folder = fileparts (opts.name);
-  if (! isempty (folder) && ! isfolder (folder))
-    error ("print: directory %s does not exist", folder);
-  endif
+  ## Check the requested file is writable
+  if (! opts.rgb_output)
+    folder = fileparts (opts.name);
+    if (! isempty (folder) && ! isfolder (folder))
+      error ("print: directory %s does not exist", folder);
+    endif
 
-  ## Check the requested file is writable
-  do_unlink = (exist (opts.name, "file") != 2);
-  fid = fopen (opts.name, "a");
-  if (fid == -1)
-    error ("print: cannot open file %s for writing", opts.name);
-  endif
-  fclose (fid);
-  if (do_unlink)
-    unlink (opts.name);
+    do_unlink = (exist (opts.name, "file") != 2);
+    fid = fopen (opts.name, "a");
+    if (fid == -1)
+      error ("print: cannot open file %s for writing", opts.name);
+    endif
+    fclose (fid);
+    if (do_unlink)
+      unlink (opts.name);
+    endif
   endif
 
   opts.pstoedit_cmd = @pstoedit;
@@ -386,8 +423,18 @@
       nfig += 1;
     endfor
 
-    ## Don't account for the actual pixel density
-    if (strcmp (tk, "qt"))
+    if (strcmp (opts.renderer, "opengl"))
+      ## Scale the figure to reach the required resolution
+      scale = opts.ghostscript.resolution / 72;
+      if (scale != 1)
+        props(end+1).h = opts.figure;
+        props(end).name = "__device_pixel_ratio__";
+        props(end).value{1} = get (opts.figure, "__device_pixel_ratio__");
+        set (opts.figure, "__device_pixel_ratio__", scale);
+        nfig += 1;
+      endif
+    elseif (strcmp (tk, "qt"))
+      ## Don't account for the actual pixel density
       props(end+1).h = opts.figure;
       props(end).name = "__device_pixel_ratio__";
       props(end).value = {get(opts.figure, "__device_pixel_ratio__")};
@@ -410,7 +457,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);
@@ -571,7 +619,24 @@
       case "gnuplot"
         opts = __gnuplot_print__ (opts);
       otherwise
-        opts = __opengl_print__ (opts);
+        if (strcmp (opts.renderer, "opengl"))
+          if (opts.rgb_output)
+            rgbout = __get_frame__ (opts.figure);
+          else
+            compression = "none";
+
+            if (strcmp (opts.devopt, "tiff"))
+              compression = "lzw";
+            elseif (strcmp (opts.devopt, "tiffn"))
+              opts.devopt = "tiff";
+            endif
+
+            imwrite (__get_frame__ (opts.figure), opts.name, ...
+                     opts.devopt, "Compression", compression);
+          endif
+        else
+          opts = __opengl_print__ (opts);
+        endif
     endswitch
 
   unwind_protect_cleanup
--- a/scripts/plot/util/private/__print_parse_opts__.m	Thu Nov 01 16:50:27 2018 +0100
+++ b/scripts/plot/util/private/__print_parse_opts__.m	Thu Mar 01 23:41:52 2018 +0100
@@ -45,7 +45,7 @@
   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;
@@ -58,6 +58,8 @@
   arg_st.pstoedit_binary = __quote_path__ (__find_binary__ ("pstoedit"));
   arg_st.preview = "";
   arg_st.printer = "";
+  arg_st.renderer = "auto";
+  arg_st.rgb_output = false;
   arg_st.send_to_printer = false;
   arg_st.special_flag = "textnormal";
   arg_st.tight_flag = false;
@@ -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)))
@@ -154,8 +161,6 @@
         arg_st.ghostscript.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) == "-")
@@ -186,13 +191,39 @@
 
   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, ...
+                           "tiffn"];
+
+  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 && strcmp (graphics_toolkit (arg_st.figure), "qt"))
+      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;
@@ -215,7 +246,7 @@
     arg_st.devopt = "tiff";
   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", ...
@@ -228,9 +259,9 @@
               "pdfcairolatex", "pdfcairolatexstandalone", ...
               "epscairolatex", "epscairolatexstandalone", "pstricks", ...
               "epswrite", "eps2write", "pswrite", "ps2write", "pdfwrite", ...
-              "canvas", "cgm", "latex", "eepic"};
+              "canvas", "cgm", "latex", "eepic"}, 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", ...
@@ -243,7 +274,7 @@
               "tex", "tex", ...
               "tex", "tex", "tex", ...
               "eps", "eps", "ps", "ps", "pdf", ...
-              "js", "cgm", "tex", "tex"};
+              "js", "cgm", "tex", "tex"}, gl_devlist];
 
   if (isfigure (arg_st.figure))
     __graphics_toolkit__ = get (arg_st.figure, "__graphics_toolkit__");
@@ -291,7 +322,13 @@
     endif
   endif
 
-  if (! isempty (arg_st.printer) || isempty (arg_st.name))
+  if (arg_st.rgb_output)
+    if (! isempty (arg_st.printer) || ! isempty (arg_st.name))
+      warning ("octave:print:ignored_argument", ...
+               ["print: ignoring file name and printer argument when using", ...
+                "-RGBImage option"])
+    endif
+  elseif (! isempty (arg_st.printer) || isempty (arg_st.name))
     arg_st.send_to_printer = true;
   endif
 
@@ -300,7 +337,8 @@
   endif
 
   aliases = gs_aliases ();
-  if (any (strcmp (arg_st.devopt, fieldnames (aliases))))
+  if (any (strcmp (arg_st.devopt, fieldnames (aliases)))
+      && ! strcmp (arg_st.renderer, "opengl"))
     arg_st.devopt = aliases.(arg_st.devopt);
     unknown_device = false;
   endif
@@ -343,7 +381,7 @@
       ## Only supported ghostscript devices
       error ("print: format must be a valid Ghostscript format for spooling to a printer");
     endif
-  elseif (isempty (arg_st.name))
+  elseif (isempty (arg_st.name) && ! arg_st.rgb_output)
     error ("print: an output filename must be specified");
   endif
 
@@ -384,7 +422,8 @@
 
   if (warn_on_missing_ghostscript)
     if (isempty (arg_st.ghostscript.binary))
-      warning ("print:missing_gs", "print.m: Ghostscript binary is not available.  Only eps output is possible");
+      warning ("octave:print:missing_gs", ...
+               "print.m: Ghostscript binary is not available.  Only eps output is possible");
     endif
     warn_on_missing_ghostscript = false;
   endif