1 ## Copyright (C) 2010-2012 Shai Ayal
3 ## This file is part of Octave.
5 ## Octave is free software; you can redistribute it and/or modify it
6 ## under the terms of the GNU General Public License as published by
7 ## the Free Software Foundation; either version 3 of the License, or (at
8 ## your option) any later version.
10 ## Octave is distributed in the hope that it will be useful, but
11 ## WITHOUT ANY WARRANTY; without even the implied warranty of
12 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 ## General Public License for more details.
15 ## You should have received a copy of the GNU General Public License
16 ## along with Octave; see the file COPYING. If not, see
17 ## <http://www.gnu.org/licenses/>.
20 ## @deftypefn {Function File} {@var{args} =} __print_parse_opts__ (@var{propname}, @var{propvalue})
21 ## @deftypefnx {Function File} {@var{args} =} __print_parse_opts__ (@var{struct})
22 ## Undocumented internal function.
25 function arg_st = __print_parse_opts__ (varargin)
27 persistent warn_on_missing_binary = true
29 arg_st.append_to_file = false;
30 arg_st.canvas_size = [];
32 arg_st.debug_file = "octave-print-commands.log";
34 arg_st.epstool_binary = __quote_path__ (__find_binary__ ("epstool"));
35 arg_st.figure = get (0, "currentfigure");
36 arg_st.fig2dev_binary = __quote_path__ (__find_binary__ ("fig2dev"));
39 arg_st.force_solid = 0; # 0=default, -1=dashed, +1=solid
40 arg_st.formatted_for_printing = false;
41 arg_st.ghostscript.binary = __quote_path__ (__ghostscript_binary__ ());
42 arg_st.ghostscript.debug = false;
43 arg_st.ghostscript.device = "";
44 arg_st.ghostscript.epscrop = true;
45 arg_st.ghostscript.level = [];
46 arg_st.ghostscript.output = "";
47 arg_st.ghostscript.papersize = "";
48 arg_st.ghostscript.pageoffset = [];
49 arg_st.ghostscript.resolution = 150;
50 arg_st.ghostscript.antialiasing = false;
52 arg_st.lpr_binary = __quote_path__ (__find_binary__ ("lpr"));
54 arg_st.orientation = "";
55 arg_st.pstoedit_binary = __quote_path__ (__find_binary__ ("pstoedit"));
58 arg_st.send_to_printer = false;
59 arg_st.special_flag = "textnormal";
60 arg_st.tight_flag = false;
61 arg_st.use_color = 0; # 0=default, -1=mono, +1=color
64 arg_st.lpr_options = "-l";
66 arg_st.lpr_options = "-o l";
68 arg_st.lpr_options = "";
72 if (nargin > 0 && isfigure (varargin{1}))
73 arg_st.figure = varargin{1};
77 for i = 1:numel(varargin)
78 arg = strtrim (varargin{i});
80 if (strcmp (arg, "-color"))
82 elseif (strcmp (arg, "-append"))
83 arg_st.append_to_file = true;
84 elseif (strcmp (arg, "-mono"))
85 arg_st.use_color = -1;
86 elseif (strcmp (arg, "-solid"))
87 arg_st.force_solid = 1;
88 elseif (strcmp (arg, "-dashed"))
89 arg_st.force_solid = -1;
90 elseif (strncmp (arg, "-portrait", numel (arg)))
91 arg_st.orientation = "portrait";
92 elseif (strncmp (arg, "-landscape", numel (arg)))
93 arg_st.orientation = "landscape";
94 elseif (strcmp (arg, "-loose"))
96 arg_st.tight_flag = false;
97 elseif (strcmp (arg, "-tight"))
99 arg_st.tight_flag = true;
100 elseif (strcmp (arg, "-textspecial"))
101 arg_st.special_flag = "textspecial";
102 elseif (any (strcmp (arg, {"-interchange", "-metafile", "-pict", "-tiff"})))
103 arg_st.preview = arg(2:end);
104 elseif (strncmp (arg, "-debug", 6))
106 arg_st.ghostscript.debug = true;
107 if (length (arg) > 7)
108 arg_st.debug_file = arg(8:end);
110 elseif (length (arg) > 2 && arg(1:2) == "-d")
111 arg_st.devopt = tolower (arg(3:end));
112 elseif (length (arg) > 2 && arg(1:2) == "-P")
113 arg_st.printer = arg;
114 elseif (strncmp (arg, "-EPSTOOL:", 9))
115 arg_st.epstool_binary = arg{10:end};
116 elseif (strncmp (arg, "-FIG2DEV:", 9))
117 arg_st.fig2dev_binary = arg{10:end};
118 elseif (strncmp (arg, "-PSTOEDIT:", 9))
119 arg_st.pstoedit_binary = arg{10:end};
120 elseif ((length (arg) > 2) && arg(1:2) == "-G")
121 arg_st.ghostscript.binary = file_in_path (getenv ("PATH"), arg(3:end));
122 if (isempty (arg_st.ghostscript.binary))
123 error ("print: Ghostscript binary ""%s"" could not be located",
126 arg_st.ghostscript_binary = __quote_path__ (arg_st.ghostscript_binary);
128 elseif (length (arg) > 2 && arg(1:2) == "-F")
129 idx = rindex (arg, ":");
131 arg_st.font = arg(3:idx-1);
132 arg_st.fontsize = str2num (arg(idx+1:end));
134 arg_st.font = arg(3:end);
136 elseif (length (arg) > 2 && arg(1:2) == "-S")
137 arg_st.canvas_size = str2num (arg(3:end));
138 elseif (length (arg) > 2 && arg(1:2) == "-r")
139 arg_st.ghostscript.resolution = str2double (arg(3:end));
140 elseif (length (arg) > 2 && arg(1:2) == "-f")
141 arg_st.figure = str2num (arg(3:end));
142 elseif (length (arg) >= 1 && arg(1) == "-")
143 error ("print: unknown option `%s'", arg);
144 elseif (length (arg) > 0)
147 elseif (isfigure (arg))
150 error ("print: expecting inputs to be character string options or a figure handle");
154 if (arg_st.ghostscript.resolution == 0)
155 ## Do as Matlab does.
156 arg_st.ghostscript.resolution = get (0, "screenpixelsperinch");
159 if (isempty (arg_st.orientation))
160 if (isfigure (arg_st.figure))
161 arg_st.orientation = get (arg_st.figure, "paperorientation");
163 ## Allows tests to be run without error.
164 arg_st.orientation = "portrait";
168 if (isempty (arg_st.ghostscript.binary))
169 arg_st.ghostscript.binary = __ghostscript_binary__ ();
172 dot = rindex (arg_st.name, ".");
173 if (isempty (arg_st.devopt))
175 arg_st.devopt = "psc";
177 arg_st.devopt = tolower (arg_st.name(dot+1:end));
181 if (arg_st.use_color == 0)
182 if (any (strcmp ({"ps", "ps2", "eps", "eps2"}, arg_st.devopt)))
183 arg_st.use_color = -1;
185 arg_st.use_color = 1;
189 if (strcmp (arg_st.devopt, "tex"))
190 arg_st.devopt = "epslatex";
191 elseif (strcmp (arg_st.devopt, "ill"))
192 arg_st.devopt = "aifm";
193 elseif (strcmp (arg_st.devopt, "cdr"))
194 arg_st.devopt = "corel";
195 elseif (strcmp (arg_st.devopt, "meta"))
196 arg_st.devopt = "emf";
197 elseif (strcmp (arg_st.devopt, "jpg"))
198 arg_st.devopt = "jpeg";
201 dev_list = {"aifm", "corel", "fig", "png", "jpeg", ...
202 "gif", "pbm", "pbmraw", "dxf", "mf", ...
203 "svg", "hpgl", "ps", "ps2", "psc", ...
204 "psc2", "eps", "eps2", "epsc", "epsc2", ...
205 "emf", "pdf", "pslatex", "epslatex", "epslatexstandalone", ...
206 "pslatexstandalone", "pdflatexstandalone", ...
207 "pstex", "tiff", "tiffn" "tikz", "pcxmono", ...
208 "pcx24b", "pcx256", "pcx16", "pgm", "pgmraw", ...
209 "ppm", "ppmraw", "pdflatex", "texdraw", ...
210 "pdfcairo", "pngcairo", "pstricks", ...
211 "epswrite", "pswrite", "ps2write", "pdfwrite"};
213 suffixes = {"ai", "cdr", "fig", "png", "jpg", ...
214 "gif", "pbm", "pbm", "dxf", "mf", ...
215 "svg", "hpgl", "ps", "ps", "ps", ...
216 "ps", "eps", "eps", "eps", "eps", ...
217 "emf", "pdf", "tex", "tex", "tex", ...
219 "ps", "tiff", "tiff", "tikz", "pcx", ...
220 "pcx", "pcx", "pcx", "pgm", "pgm", ...
221 "ppm", "ppm", "tex", "tex", ...
222 "pdf", "png", "tex", ...
223 "eps", "ps", "ps", "pdf"};
225 if (isfigure (arg_st.figure))
226 __graphics_toolkit__ = get (arg_st.figure, "__graphics_toolkit__");
228 ## Allow tests when no figures are present.
229 __graphics_toolkit__ = get (0, "defaultfigure__graphics_toolkit__");
232 if (strcmp (__graphics_toolkit__, "gnuplot")
233 && __gnuplot_has_feature__ ("epslatex_implies_eps_filesuffix"))
234 suffixes(strncmp (dev_list, "epslatex", 8)) = {"eps"};
237 match = strcmpi (dev_list, arg_st.devopt);
239 default_suffix = suffixes {match};
241 default_suffix = arg_st.devopt;
244 if (dot == 0 && ! isempty (arg_st.name))
245 arg_st.name = strcat (arg_st.name, ".", default_suffix);
248 if (arg_st.append_to_file)
249 if (isempty (arg_st.name))
250 arg_st.append_to_file = false;
251 elseif (any (strcmpi (arg_st.devopt, {"eps", "eps2", "epsc", "epsc2", ...
252 "ps", "ps2", "psc", "psc2", "pdf"})))
253 have_ghostscript = ! isempty (__ghostscript_binary__ ());
254 if (have_ghostscript)
255 file_exists = ((numel (dir (arg_st.name)) == 1)
256 && (! isdir (arg_st.name)));
258 arg_st.append_to_file = false;
261 arg_st.append_to_file = false;
262 warning ("print.m: appended output requires ghostscript to be installed");
265 warning ("print.m: appended output is not supported for device '%s'",
267 arg_st.append_to_file = false;
271 if (! isempty (arg_st.printer) || isempty (arg_st.name))
272 arg_st.send_to_printer = true;
275 if (any (strcmp (arg_st.devopt, {"ps", "ps2", "psc", "psc2", "pdf"})))
276 arg_st.formatted_for_printing = true;
279 aliases = gs_aliases ();
280 if (any (strcmp (arg_st.devopt, fieldnames (aliases))))
281 arg_st.devopt = aliases.(arg_st.devopt);
284 ## FIXME - eps2 & epsc2 needs to be handled
285 if (strcmp (arg_st.devopt, "pswrite"))
286 arg_st.ghostscript.level = 1;
287 elseif (strcmp (arg_st.devopt, "ps2write"))
288 arg_st.ghostscript.level = 2;
291 if ((any (strcmp (arg_st.devopt, gs_device_list))
292 && ! arg_st.formatted_for_printing)
293 || any (strcmp (arg_st.devopt, {"pswrite", "ps2write", "pdfwrite"})))
294 ## Use ghostscript for graphic formats
295 arg_st.ghostscript.device = arg_st.devopt;
296 arg_st.ghostscript.output = arg_st.name;
297 arg_st.ghostscript.antialiasing = true;
298 if (arg_st.formatted_for_printing)
299 arg_st.ghostscript.epscrop = ! arg_st.loose;
301 ## pstoedit throws errors if the EPS file isn't cropped
302 arg_st.ghostscript.epscrop = true;
304 elseif (all (! strcmp (arg_st.devopt, dev_list)))
305 ## Assume we are formating output for a printer
306 arg_st.formatted_for_printing = true;
307 arg_st.ghostscript.device = arg_st.devopt;
308 arg_st.ghostscript.output = arg_st.name;
309 arg_st.ghostscript.antialiasing = false;
310 arg_st.ghostscript.epscrop = ! arg_st.loose;
313 if (isempty (arg_st.canvas_size))
314 if (isfigure (arg_st.figure))
315 [arg_st.ghostscript.papersize, paperposition] = ...
316 gs_papersize (arg_st.figure, arg_st.orientation);
318 ## allows tests to be run
319 arg_st.ghostscript.papersize = "letter";
320 paperposition = [0.25, 2.50, 8.00, 6.00] * 72;
322 arg_st.canvas_size = paperposition(3:4);
323 if (strcmp (__graphics_toolkit__, "gnuplot") && ! arg_st.ghostscript.epscrop)
324 arg_st.ghostscript.pageoffset = paperposition(1:2) - 50;
326 arg_st.ghostscript.pageoffset = paperposition(1:2);
329 ## Convert canvas size to points from pixles.
330 arg_st.canvas_size = arg_st.canvas_size * 72 / arg_st.ghostscript.resolution;
331 arg_st.ghostscript.papersize = arg_st.canvas_size;
332 arg_st.ghostscript.epscrop = true;
333 arg_st.ghostscript.pageoffset = [0, 0];
336 if (arg_st.formatted_for_printing)
337 arg_st.ghostscript.resolution = [];
339 arg_st.ghostscript.papersize = "";
340 arg_st.ghostscript.pageoffset = [0, 0];
343 if (warn_on_missing_binary)
344 if (isempty (arg_st.ghostscript.binary))
345 warning ("print:missing_gs", "print.m: Ghostscript binary is not available.\nOnly eps output is available.");
347 if (isempty (arg_st.epstool_binary))
348 warning ("print:missing_epstool", "print.m: epstool binary is not available.\nSome output formats are not available.");
350 if (isempty (arg_st.fig2dev_binary))
351 warning ("print:missing_fig2dev", "print.m: fig2dev binary is not available.\nSome output formats are not available.");
353 if (isempty (arg_st.pstoedit_binary))
354 warning ("print:missing_pstoedit", "print.m: pstoedit binary is not available.\nSome output formats are not available.");
357 warn_on_missing_binary = false;
362 ## Test blocks are not allowed (and not needed) for private functions
364 %! opts = __print_parse_opts__ ();
365 %! assert (opts.devopt, "pswrite");
366 %! assert (opts.use_color, 1);
367 %! assert (opts.send_to_printer, true);
368 %! assert (opts.canvas_size, [576, 432]);
369 %! assert (opts.ghostscript.device, "pswrite")
372 %! opts = __print_parse_opts__ ("test.pdf", "-S640,480");
373 %! assert (opts.canvas_size, [307.2, 230.4], 0.1);
376 %! opts = __print_parse_opts__ ("-dpsc", "-append", "-loose");
377 %! assert (opts.devopt, "pswrite");
378 %! assert (opts.send_to_printer, true);
379 %! assert (opts.use_color, 1);
380 %! assert (opts.append_to_file, false);
381 %! assert (opts.ghostscript.device, "pswrite")
382 %! assert (opts.ghostscript.epscrop, false);
385 %! opts = __print_parse_opts__ ("-deps", "-tight");
386 %! assert (opts.tight_flag, true);
387 %! assert (opts.send_to_printer, true);
388 %! assert (opts.use_color, -1);
389 %! assert (opts.ghostscript.device, "")
392 %! opts = __print_parse_opts__ ("-djpg", "foobar", "-mono", "-loose");
393 %! assert (opts.devopt, "jpeg")
394 %! assert (opts.name, "foobar.jpg")
395 %! assert (opts.ghostscript.device, "jpeg")
396 %! assert (opts.ghostscript.epscrop, true);
397 %! assert (opts.ghostscript.papersize, "");
398 %! assert (opts.ghostscript.pageoffset, [0, 0]);
399 %! assert (opts.send_to_printer, false);
400 %! assert (opts.printer, "");
401 %! assert (opts.use_color, -1);
404 %! opts = __print_parse_opts__ ("-ddeskjet", "foobar", "-mono", "-Pmyprinter");
405 %! assert (opts.ghostscript.output, "foobar.deskjet")
406 %! assert (opts.ghostscript.device, "deskjet")
407 %! assert (opts.devopt, "deskjet")
408 %! assert (opts.send_to_printer, true);
409 %! assert (opts.printer, "-Pmyprinter");
410 %! assert (opts.use_color, -1);
413 %! opts = __print_parse_opts__ ("-f5", "-dljet3");
414 %! assert (opts.ghostscript.device, "ljet3")
415 %! assert (strfind (opts.ghostscript.output, ".ljet3"))
416 %! assert (opts.devopt, "ljet3")
417 %! assert (opts.send_to_printer, true);
418 %! assert (opts.figure, 5)
420 function cmd = __quote_path__ (cmd)
421 if (any (cmd == " ") && ! (cmd(1) == """" && cmd(end) == """"))
422 cmd = strcat ("""", strrep (cmd, """", """"""), """");
426 function gs = __ghostscript_binary__ ()
428 persistent ghostscript_binary = ""
429 persistent warn_on_no_ghostscript = true
430 persistent warn_on_bad_gsc = true
432 if (isempty (ghostscript_binary))
433 GSC = getenv ("GSC");
434 if (exist (GSC, "file")
435 || (! isempty (GSC) && file_in_path (getenv ("PATH"), GSC)))
437 elseif (! isempty (GSC) && warn_on_bad_gsc)
438 warning ("print:badgscenv",
439 "print.m: GSC environment variable not set properly");
440 warn_on_bad_gsc = false;
446 ## Unix - Includes Mac OSX and Cygwin.
447 gs_binaries = horzcat (gs_binaries, {"gs", "gs.exe"});
449 ## pc - Includes Win32 and mingw.
450 gs_binaries = horzcat (gs_binaries, {"gs.exe", "gswin32c.exe", "mgs.exe"});
453 while (n < numel (gs_binaries) && isempty (ghostscript_binary))
455 ghostscript_binary = file_in_path (getenv ("PATH"), gs_binaries{n});
457 if (warn_on_no_ghostscript && isempty (ghostscript_binary))
458 warning ("print:noghostscript",
459 "print.m: ghostscript not found in PATH");
460 warn_on_no_ghostscript = false;
464 gs = ghostscript_binary;
468 function bin = __find_binary__ (binary)
470 persistent data = struct ()
472 if (! isfield (data, binary))
473 ## Reinitialize when `user_binaries' is present.
474 data.(binary).bin = "";
475 data.(binary).warn_on_absence = false;
478 if (isempty (data.(binary).bin))
480 ## Unix - Includes Mac OSX and Cygwin.
481 binaries = strcat (binary, {"", ".exe"});
483 ## pc - Includes Win32 and mingw.
484 binaries = strcat (binary, {".exe"});
487 while (n < numel (binaries) && isempty (data.(binary).bin))
489 data.(binary).bin = file_in_path (getenv ("PATH"), binaries{n});
491 if (isempty (data.(binary).bin) && data.(binary).warn_on_absence)
492 warning (sprintf ("print:no%s", binary),
493 "print.m: '%s' not found in PATH", binary);
494 data.(binary).warn_on_absence = false;
498 bin = data.(binary).bin;
502 function [papersize, paperposition] = gs_papersize (hfig, paperorientation)
503 persistent papertypes papersizes
505 if (isempty (papertypes))
506 papertypes = {"usletter", "uslegal", "a0", "a1", ...
507 "a2", "a3", "a4", "a5", ...
508 "b0", "b1", "b2", "b3", ...
509 "b4", "b5", "arch-a", "arch-b", ...
510 "arch-c", "arch-d", "arch-e", "a", ...
511 "b", "c", "d", "e", ...
513 papersizes = [ 8.5, 11.0; 8.5, 14.0; 33.1, 46.8; 23.4, 33.1;
514 16.5, 23.4; 11.7, 16.5; 8.3, 11.7; 5.8, 8.3;
515 39.4, 55.7; 27.8, 39.4; 19.7, 27.8; 13.9, 19.7;
516 9.8, 13.9; 6.9, 9.8; 9.0, 12.0; 12.0, 18.0;
517 18.0, 24.0; 24.0, 36.0; 36.0, 48.0; 8.5, 11.0;
518 11.0, 17.0; 18.0, 24.0; 24.0, 36.0; 36.0, 48.0;
522 papertype = get (hfig, "papertype");
523 paperunits = get (hfig, "paperunits");
524 paperposition = get (hfig, "paperposition");
525 if (strcmp (papertype, "<custom>"))
526 papersize = get (hfig, "papersize");
527 papersize = convert2points (papersize , paperunits);
529 papersize = papersizes (strcmp (papertypes, papertype), :);
532 if (strcmp (paperunits, "normalized"))
533 paperposition = paperposition .* papersize([1,2,1,2]);
535 paperposition = convert2points (paperposition, paperunits);
538 ## FIXME - This will be obsoleted by listeners for paper properties.
539 ## Papersize is tall when portrait,and wide when landscape.
540 if ((papersize(1) > papersize(2) && strcmpi (paperorientation, "portrait"))
541 || (papersize(1) < papersize(2) && strcmpi (paperorientation, "landscape")))
542 papersize = papersize ([2,1]);
543 paperposition = paperposition([2,1,4,3]);
546 if ((! strcmp (papertype, "<custom>")) && (strcmp (paperorientation, "portrait")))
547 ## For portrait use the ghostscript name
548 papersize = papertype;
549 papersize(papersize=="-") = "";
550 papersize = strrep (papersize, "us", "");
553 papersize = "letter";
554 case {"b", "tabloid"}
557 papersize = strcat ("arch", papersize);
559 if (strncmp (papersize, "arch", 4))
560 papersize(end) = upper (papersize(end));
566 function value = convert2points (value, units)
571 value = value * 72 / 2.54;
573 error ("print:customnormalized",
574 "print.m: papersize=='<custom>' and paperunits='normalized' may not be combined");
578 function device_list = gs_device_list ();
579 ## Graphics formats/languages, not priners.
580 device_list = {"bmp16"; "bmp16m"; "bmp256"; "bmp32b"; "bmpgray"; ...
581 "epswrite"; "jpeg"; "jpegcymk"; "jpeggray"; "pbm"; ...
582 "pbmraw"; "pcx16"; "pcx24b"; "pcx256"; "pcx2up"; ...
583 "pcxcmyk"; "pcxgray"; "pcxmono"; "pdfwrite"; "pgm"; ...
584 "pgmraw"; "pgnm"; "pgnmraw"; "png16"; "png16m"; ...
585 "png256"; "png48"; "pngalpha"; "pnggray"; "pngmono"; ...
586 "pnm"; "pnmraw"; "ppm"; "ppmraw"; "ps2write"; ...
587 "pswrite"; "tiff12nc"; "tiff24nc"; "tiff32nc"; ...
588 "tiffcrle"; "tiffg3"; "tiffg32d"; "tiffg4"; ...
589 "tiffgray"; "tifflzw"; "tiffpack"; "tiffsep"};
592 function aliases = gs_aliases ();
593 ## Aliases for other devices: "bmp", "png", "tiff", "tiffn", "pdf",
594 ## "ps", "ps2", "psc", "psc2"
596 ## eps, epsc, eps2, epsc2 are not included here because those are
597 ## are generated by the graphics toolkit.
598 aliases.bmp = "bmp32b";
599 aliases.pdf = "pdfwrite";
600 aliases.png = "png16m";
601 aliases.ps = "pswrite";
602 aliases.ps2 = "ps2write";
603 aliases.psc = "pswrite";
604 aliases.psc2 = "ps2write";
605 aliases.tiff = "tiff24nc";
606 aliases.tiffn = "tiff24nc";