Mercurial > hg > octave-lyh
view scripts/plot/print.m @ 9157:fce7315c1eee
print.m: Fix typo, improvments to code, and allow for creation of tight bbox.
author | Ben Abbott <bpabbott@mac.com> |
---|---|
date | Tue, 28 Apr 2009 19:45:40 -0400 |
parents | 4c9aff0c9a61 |
children | 923c7cb7f13f |
line wrap: on
line source
## Copyright (C) 1999, 2005, 2006, 2007, 2008, 2009 Daniel Heiserer ## Copyright (C) 2001 Laurent Mazet ## ## This file is part of Octave. ## ## Octave is free software; you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or (at ## your option) any later version. ## ## Octave is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with Octave; see the file COPYING. If not, see ## <http://www.gnu.org/licenses/>. ## -*- texinfo -*- ## @deftypefn {Function File} {} print (@var{filename}, @var{options}) ## @deftypefnx {Function File} {} print (@var{h}, @var{filename}, @var{options}) ## Print a graph, or save it to a file ## ## @var{filename} defines the file name of the output file. If no ## filename is specified, output is sent to the printer. ## ## @var{h} specifies the figure handle. If no handle is specified ## the handle for the current figure is used. ## ## @var{options}: ## @table @code ## @item -P@var{printer} ## 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 calling Ghostscript. For Unix and Windows, ## the defaults are 'gs' and 'gswin32c', respectively. ## @item -color ## @itemx -mono ## Monochrome or color lines. ## @item -solid ## @itemx -dashed ## Solid or dashed lines. ## @item -portrait ## @itemx -landscape ## Plot orientation, as returned by "orient". ## @item -d@var{device} ## Output device, where @var{device} is one of: ## @table @code ## @item ps ## @itemx ps2 ## @itemx psc ## @itemx psc2 ## Postscript (level 1 and 2, mono and color) ## @item eps ## @itemx eps2 ## @itemx epsc ## @itemx epsc2 ## Encapsulated postscript (level 1 and 2, mono and color) ## @item tex ## @itemx epslatex ## @itemx epslatexstandalone ## @itemx pstex ## @itemx pslatex ## Generate a LaTeX (or TeX) file for labels, and eps/ps for ## graphics. The file produced by @code{epslatexstandalone} can be ## processed directly by LaTeX. The other formats are intended to ## be included in a LaTeX (or TeX) document. The @code{tex} device ## is the same as the @code{epslatex} device. ## @item ill ## @itemx aifm ## Adobe Illustrator ## @item cdr ## @itemx corel ## CorelDraw ## @item dxf ## AutoCAD ## @item emf ## @itemx meta ## Microsoft Enhanced Metafile ## @item fig ## XFig. If this format is selected the additional options ## @code{-textspecial} or @code{-textnormal} can be used to control ## whether the special flag should be set for the text in ## the figure (default is @code{-textnormal}). ## @item hpgl ## HP plotter language ## @item mf ## Metafont ## @item png ## Portable network graphics ## @item jpg ## @itemx jpeg ## JPEG image ## @item gif ## GIF image ## @item pbm ## PBMplus ## @item svg ## Scalable vector graphics ## @item pdf ## Portable document format ## @end table ## ## If the device is omitted, it is inferred from the file extension, ## or if there is no filename it is sent to the printer as postscript. ## ## @item -d@var{gs_device} ## Additional devices are supported by Ghostscript. ## Some examples are; ## ## @table @code ## @item ljet2p ## HP LaserJet IIP ## @item ljet3 ## HP LaserJet III ## @item deskjet ## HP DeskJet and DeskJet Plus ## @item cdj550 ## HP DeskJet 550C ## @item paintjet ## HP PointJet ## @item pcx24b ## 24-bit color PCX file format ## @item ppm ## Portable Pixel Map file format ## @end table ## ## For a complete list, type `system ("gs -h")' to see what formats ## and devices are available. ## ## For output sent to a printer, the size is determined by the ## figure's "papersize" property. For output to a file the, size ## is determined by the "paperposition" property. ## ## @itemx -r@var{NUM} ## Resolution of bitmaps in pixels per inch. For both metafiles and ## SVG the default is the screen resolution, for other it is 150 dpi. ## To specify screen resolution, use "-r0". ## ## @item -tight ## Forces a tight bounding box for eps-files. Since the ghostscript ## devices are conversion of an eps-file, this option works the those ## devices as well. ## ## @itemx -S@var{xsize},@var{ysize} ## Plot size in pixels for EMF, GIF, JPEG, PBM, PNG and SVG. If ## using the command form of the print function, you must quote the ## @var{xsize},@var{ysize} option. For example, by writing ## @code{"-S640,480"}. The size defaults to that specified by the ## figure's paperposition property. ## ## @item -F@var{fontname} ## @itemx -F@var{fontname}:@var{size} ## @itemx -F:@var{size} ## @var{fontname} set the postscript font (for use with postscript, ## aifm, 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. ## @end table ## ## The filename and options can be given in any order. ## @end deftypefn ## Author: Daniel Heiserer <Daniel.heiserer@physik.tu-muenchen.de> ## Adapted-By: jwe function print (varargin) orientation = orient (); use_color = 0; # 0=default, -1=mono, +1=color force_solid = 0; # 0=default, -1=dashed, +1=solid fontsize = ""; font = ""; canvas_size = ""; name = ""; devopt = ""; printer = ""; debug = false; debug_file = "octave-print-commands.log"; special_flag = "textnormal"; tight_flag = false; resolution = ""; if (isunix ()) persistent ghostscript_binary = "gs"; elseif (ispc ()) persistent ghostscript_binary = "gswin32c"; endif old_fig = get (0, "currentfigure"); unwind_protect ## Ensure the last figure is on the screen for single line commands like ## plot(...); print(...); drawnow (); for i = 1:nargin arg = varargin{i}; if (ischar (arg)) if (strcmp (arg, "-color")) use_color = 1; elseif (strcmp (arg, "-mono")) use_color = -1; elseif (strcmp (arg, "-solid")) force_solid = 1; elseif (strcmp (arg, "-dashed")) force_solid = -1; elseif (strcmp (arg, "-portrait")) orientation = "portrait"; elseif (strcmp (arg, "-landscape")) orientation = "landscape"; elseif (strcmp (arg, "-tight")) tight_flag = true; elseif (strcmp (arg, "-textspecial")) special_flag = "textspecial"; elseif (strncmp (arg, "-debug", 6)) debug = true; if (length (arg) > 7) debug_file = arg(8:end); endif elseif (length (arg) > 2 && arg(1:2) == "-d") devopt = tolower(arg(3:end)); elseif (length (arg) > 2 && arg(1:2) == "-P") printer = arg; elseif ((length (arg) > 2) && arg(1:2) == "-G") ghostscript_binary = arg(3:end); elseif (length (arg) > 2 && arg(1:2) == "-F") idx = rindex (arg, ":"); if (idx) font = arg(3:idx-1); fontsize = arg(idx+1:length(arg)); else font = arg(3:length(arg)); endif elseif (length (arg) > 2 && arg(1:2) == "-S") canvas_size = arg(3:length(arg)); elseif (length (arg) > 2 && arg(1:2) == "-r") resolution = arg(3:length(arg)); elseif (length (arg) >= 1 && arg(1) == "-") error ("print: unknown option `%s'", arg); elseif (length (arg) > 0) name = arg; endif elseif (isfigure (arg)) figure (arg); else error ("print: expecting inputs to be character string options or a figure handle"); endif endfor if (isunix ()) [status, output] = system (sprintf ("which %s 2>&1", ghostscript_binary)); have_ghostscript = (status == 0); elseif (ispc ()) have_ghostscript = true; endif doprint = isempty (name); if (doprint) if (isempty (devopt)) if (use_color < 0) devopt = "ps"; printname = cstrcat (tmpnam, ".ps"); else devopt = "psc"; printname = cstrcat (tmpnam, ".psc"); endif else printname = cstrcat (tmpnam, ".", devopt); endif name = printname; endif if (isempty (devopt)) dot = rindex (name, "."); if (dot == 0) error ("print: no format specified"); else dev = tolower (name(dot+1:end)); endif else dev = devopt; endif if (strcmp (dev, "tex")) dev = "epslatex"; ## gnuplot 4.0 wants ".eps" in the output name if (! __gnuplot_has_feature__ ("epslatex_implies_eps_filesuffix")) name = cstrcat (name(1:dot), "eps"); endif elseif (strcmp (dev, "ill")) dev = "aifm"; elseif (strcmp (dev, "cdr")) dev = "corel"; elseif (strcmp (dev, "meta")) dev = "emf"; elseif (strcmp (dev, "jpg")) dev = "jpeg"; endif ## Check if the specified device is one that is supported by gnuplot. ## If not, assume it is a device/format supported by Ghostscript. 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"}; if (! any (strcmp (dev, dev_list))) ghostscript_output = name; ghostscript_device = dev; dev = "epsc"; name = cstrcat (tmpnam, ".eps"); else ghostscript_output = ""; endif termn = dev; ## SVG isn't actually a bitmap, but gnuplot treats its size option as it ## does the bitmap terminals. bitmap_devices = {"emf", "gif", "jpeg", "pbm", "png", "svg"}; if (any (strcmp (dev, {"ps", "ps2", "psc", "psc2", "epsc", "epsc2", ... "eps", "eps2", "pstex", "pslatex", "epslatex", ... "epslatexstandalone"}))) ## Various postscript options if (any (strcmp (dev, {"pstex", "pslatex", "epslatex"}))) options = ""; elseif (strcmp (dev, "epslatexstandalone")) if (__gnuplot_has_feature__ ("epslatexstandalone_terminal")) termn = "epslatex"; options = "standalone "; else error ("print: epslatexstandalone needs gnuplot 4.2 or higher"); endif else if (dev(1) == "e") options = "eps "; else options = cstrcat (orientation, " "); endif termn = "postscript"; endif if (any (dev == "c") || use_color > 0) if (force_solid < 0) options = cstrcat (options, "color dashed "); else options = cstrcat (options, "color solid "); endif else if (force_solid > 0) options = cstrcat (options, "mono solid "); else options = cstrcat (options, "mono dashed "); endif endif if (! isempty (font)) options = cstrcat (options, "\"", font, "\" "); endif if (! isempty (fontsize)) options = cstrcat (options, " ", fontsize); endif new_terminal = cstrcat (termn, " ", options); elseif (strcmp (dev, "aifm") || strcmp (dev, "corel")) ## Adobe Illustrator, CorelDraw if (use_color >= 0) options = " color"; else options = " mono"; endif if (! isempty (font)) options = cstrcat (options, " \"", font, "\""); endif if (! isempty (fontsize)) options = cstrcat (options, " ", fontsize); endif elseif (strcmp (dev, "fig")) ## XFig options = orientation; if (use_color >= 0) options = " color"; else options = " mono"; endif options = cstrcat (options, " ", special_flag); if (! isempty (fontsize)) options = cstrcat (options, " fontsize ", fontsize); endif elseif (strcmp (dev, "emf")) ## Enhanced Metafile format options = " "; if (use_color >= 0) options = " color"; else options = " mono"; endif if (force_solid >= 0) options = cstrcat (options, " solid"); endif if (! isempty (font)) options = cstrcat (options, " \"", font, "\""); endif if (! isempty (fontsize)) options = cstrcat (options, " ", fontsize); endif elseif (any (strcmp (dev, bitmap_devices))) if (isempty (canvas_size) && isempty (resolution) && any (strcmp (dev, {"pbm", "gif", "jpeg", "png"}))) options = "large"; elseif (strcmp (dev, "svg")) ## Referring to size, either "dynamic" or "fixed" options = "fixed"; else options = ""; end if (! isempty (canvas_size)) options = cstrcat (options, " size ", canvas_size); endif elseif (any (strcmp (dev, {"dxf", "mf", "hpgl"}))) ## AutoCad DXF, METAFONT, HPGL options = ""; elseif (strcmp (dev, "pdf")) ## Portable Document format options = " "; if (use_color >= 0) options = "color"; else options = "mono"; endif if (force_solid >= 0) options = cstrcat (options, " solid"); elseif (force_solid < 0) options = cstrcat (options, " dashed"); endif if (! isempty (font)) options = cstrcat (options, "\"", font, "\" "); endif if (! isempty (fontsize)) options = cstrcat (options, " ", fontsize); endif endif if (__gnuplot_has_feature__ ("variable_GPVAL_TERMINALS")) available_terminals = __gnuplot_get_var__ (gcf, "GPVAL_TERMINALS"); available_terminals = regexp (available_terminals, "\\b\\w+\\b", "match"); gnuplot_supports_term = any (strcmp (available_terminals, termn)); elseif (strcmp (termn, "pdf")) ## Some Linux variants do not include a "pdf" capable gnuplot. ## To be safe, use Ghostscript. if (have_ghostscript) gnuplot_supports_term = false; ghostscript_device = "pdfwrite"; else gnuplot_supports_term = true; endif else gnuplot_supports_term = true; endif if (! gnuplot_supports_term) if (strcmp (termn, "pdf")) ## If there the installed gnuplot does not support pdf, use Ghostscript. ghostscript_device = "pdfwrite"; if (strfind (name, ".pdf") == numel (name) - 3) ghostscript_output = name; else ghostscript_output = strcat (name, ".pdf"); endif name = cstrcat (tmpnam, ".ps"); termn = "postscript"; options = cstrcat (options, " portrait"); ## All "options" for pdf work for postscript as well. else error ("print: the gnuplot terminal, \"%s\", is not available.", termn) endif endif new_terminal = cstrcat (termn, " ", options); mono = use_color < 0; if (isempty (resolution)) if (any (strcmp (termn, {"emf", "svg"}))) resolution = get (0, "screenpixelsperinch"); else resolution = 150; endif else resolution = str2num (resolution); if (resolution == 0) resolution = get (0, "screenpixelsperinch"); endif endif figure_properties = get (gcf); if (! isfield (figure_properties, "__pixels_per_inch__")) addproperty ("__pixels_per_inch__", gcf, "double", resolution); endif set (gcf, "__pixels_per_inch__", resolution) unwind_protect paper_position_mode = get (gcf, "paperpositionmode"); terminals_for_prn = {"postscript", "pdf"}; restore_properties = false; is_eps_file = strncmp (dev, "eps", 3); output_for_printer = any (strncmp (termn, terminals_for_prn, numel(termn))); if ((! output_for_printer || is_eps_file) && ! doprint) ## If not PDF or PostScript, and the result is not being sent to a printer, ## render an image the size of the paperposition box. restore_properties = true; p.paperunits = get (gcf, "paperunits"); p.papertype = get (gcf, "papertype"); p.papersize = get (gcf, "papersize"); p.paperposition = get (gcf, "paperposition"); p.paperpositionmode = get (gcf, "paperpositionmode"); set (gcf, "paperunits", "inches"); if (! isempty (canvas_size)) size_in_pixels = sscanf (canvas_size ,"%d, %d"); size_in_pixels = reshape (size_in_pixels, [1, numel(size_in_pixels)]); papersize_in_inches = size_in_pixels ./ resolution; paperposition_in_inches = [0, 0, papersize_in_inches]; else paperposition_in_inches = get (gcf, "paperposition"); paperposition_in_inches(1:2) = 0; papersize_in_inches = paperposition_in_inches(3:4); endif set (gcf, "papertype", "<custom>"); set (gcf, "papersize", papersize_in_inches); set (gcf, "paperposition", paperposition_in_inches); set (gcf, "paperpositionmode", "manual"); endif if (debug) drawnow (new_terminal, name, mono, debug_file); else drawnow (new_terminal, name, mono); endif unwind_protect_cleanup ## FIXME - it would be nice to delete "__pixels_per_inch__" property here. if (restore_properties) props = fieldnames (p); for n = 1:numel(props) set (gcf, props{n}, p.(props{n})) endfor endif end_unwind_protect if (! isempty (ghostscript_output)) if (is_eps_file && tight_flag) ## If gnuplot's output is an eps-file then crop at the bounding box. fix_eps_bbox (name, ghostscript_binary); endif ghostscript_options = "-q -dBATCH -dSAFER -dNOPAUSE -dTextAlphaBits=4"; if (is_eps_file) ghostscript_options = sprintf ("%s -dEPSCrop", ghostscript_options); endif if (isempty (strfind (lower (ghostscript_device), "write"))) ## If output is a bitmap then include the resolution ghostscript_options = sprintf ("%s -r%d", ghostscript_options, resolution); endif ghostscript_options = sprintf ("%s -sDEVICE=%s", ghostscript_options, ghostscript_device); command = sprintf ("%s %s -sOutputFile='%s' '%s' 2>&1", ghostscript_binary, ghostscript_options, ghostscript_output, name); [errcode, output] = system (command); unlink (name); if (errcode) error ("print: Conversion failed, %s -> %s.", name, ghostscript_output); endif elseif (is_eps_file && tight_flag && ! doprint) ## If the saved output file is an eps file, use ghostscript to set a tight bbox. ## This may result in a smaller or larger bbox geometry. fix_eps_bbox (name, ghostscript_binary); endif if (doprint) if (isunix ()) prn_opt = "-l"; elseif (ispc ()) prn_opt = "-o l"; else ## FIXME - besides Unix and Windows, what other OS's might be considered. prn_opt = ""; endif if (isempty (printer)) prn_cmd = sprintf ("lpr %s '%s' 2>&1", prn_opt, printname); else prn_cmd = sprintf ("lpr %s -P %s '%s' 2>&1", prn_opt, printer, printname); endif [status, output] = system (prn_cmd); if (status != 0) disp (output) warning ("print.m: printing failed.") endif [status, output] = unlink (printname); if (status != 0) disp (output) warning ("print.m: failed to delete temporay file, '%s'.", printname) endif endif unwind_protect_cleanup if (isfigure (old_fig)) figure (old_fig) endif end_unwind_protect endfunction function bb = fix_eps_bbox (eps_file_name, ghostscript_binary) persistent warn_on_no_ghostscript = true box_string = "%%BoundingBox:"; ghostscript_options = "-q -dBATCH -dSAFER -dNOPAUSE -dTextAlphaBits=4 -sDEVICE=bbox"; cmd = sprintf ("%s %s '%s' 2>&1", ghostscript_binary, ghostscript_options, eps_file_name); [status, output] = system (cmd); if (status == 0) pattern = strcat (box_string, "[^%]*"); pattern = pattern(1:find(double(pattern)>32, 1, "last")); bbox_line = regexp (output, pattern, "match"); if (iscell (bbox_line)) bbox_line = bbox_line{1}; endif ## Remore the EOL characters. bbox_line(double(bbox_line)<32) = ""; fid = fopen (eps_file_name, "r+"); unwind_protect bbox_replaced = false; while (! bbox_replaced) current_line = fgetl (fid); if (strncmpi (current_line, box_string, numel(box_string))) line_length = numel (current_line); num_spaces = line_length - numel (bbox_line); if (numel (current_line) < numel (bbox_line)) ## If there new line is longer, continue with the current line. new_line = current_line; else new_line = bbox_line; new_line(end+1:numel(current_line)) = " "; endif ## Back up to the beginning of the line (include EOL characters). if (ispc ()) fseek (fid, -line_length-2, "cof"); else fseek (fid, -line_length-1, "cof"); endif count = fprintf (fid, "%s", new_line); bbox_replaced = true; elseif (! ischar (current_line)) bbox_replaced = true; warning ("print.m: no bounding box found in '%s'.", eps_file_name) endif endwhile unwind_protect_cleanup fclose (fid); end_unwind_protect elseif (warn_on_no_ghostscript) warn_on_no_ghostscript = false; warning ("print.m: Ghostscript could not be used to adjust bounding box.") endif endfunction