--- a +++ b/util/export_fig/ghostscript.m @@ -0,0 +1,196 @@ +function varargout = ghostscript(cmd) +%GHOSTSCRIPT Calls a local GhostScript executable with the input command +% +% Example: +% [status result] = ghostscript(cmd) +% +% Attempts to locate a ghostscript executable, finally asking the user to +% specify the directory ghostcript was installed into. The resulting path +% is stored for future reference. +% +% Once found, the executable is called with the input command string. +% +% This function requires that you have Ghostscript installed on your +% system. You can download this from: http://www.ghostscript.com +% +% IN: +% cmd - Command string to be passed into ghostscript. +% +% OUT: +% status - 0 iff command ran without problem. +% result - Output from ghostscript. + +% Copyright: Oliver Woodford, 2009-2015, Yair Altman 2015- +%{ +% Thanks to Jonas Dorn for the fix for the title of the uigetdir window on Mac OS. +% Thanks to Nathan Childress for the fix to default location on 64-bit Windows systems. +% 27/04/11 - Find 64-bit Ghostscript on Windows. Thanks to Paul Durack and +% Shaun Kline for pointing out the issue +% 04/05/11 - Thanks to David Chorlian for pointing out an alternative +% location for gs on linux. +% 12/12/12 - Add extra executable name on Windows. Thanks to Ratish +% Punnoose for highlighting the issue. +% 28/06/13 - Fix error using GS 9.07 in Linux. Many thanks to Jannick +% Steinbring for proposing the fix. +% 24/10/13 - Fix error using GS 9.07 in Linux. Many thanks to Johannes +% for the fix. +% 23/01/14 - Add full path to ghostscript.txt in warning. Thanks to Koen +% Vermeer for raising the issue. +% 27/02/15 - If Ghostscript croaks, display suggested workarounds +% 30/03/15 - Improved performance by caching status of GS path check, if ok +% 14/05/15 - Clarified warning message in case GS path could not be saved +% 29/05/15 - Avoid cryptic error in case the ghostscipt path cannot be saved (issue #74) +% 10/11/15 - Custom GS installation webpage for MacOS. Thanks to Andy Hueni via FEX +%} + + try + % Call ghostscript + [varargout{1:nargout}] = system([gs_command(gs_path()) cmd]); + catch err + % Display possible workarounds for Ghostscript croaks + url1 = 'https://github.com/altmany/export_fig/issues/12#issuecomment-61467998'; % issue #12 + url2 = 'https://github.com/altmany/export_fig/issues/20#issuecomment-63826270'; % issue #20 + hg2_str = ''; if using_hg2, hg2_str = ' or Matlab R2014a'; end + fprintf(2, 'Ghostscript error. Rolling back to GS 9.10%s may possibly solve this:\n * <a href="%s">%s</a> ',hg2_str,url1,url1); + if using_hg2 + fprintf(2, '(GS 9.10)\n * <a href="%s">%s</a> (R2014a)',url2,url2); + end + fprintf('\n\n'); + if ismac || isunix + url3 = 'https://github.com/altmany/export_fig/issues/27'; % issue #27 + fprintf(2, 'Alternatively, this may possibly be due to a font path issue:\n * <a href="%s">%s</a>\n\n',url3,url3); + % issue #20 + fpath = which(mfilename); + if isempty(fpath), fpath = [mfilename('fullpath') '.m']; end + fprintf(2, 'Alternatively, if you are using csh, modify shell_cmd from "export..." to "setenv ..."\nat the bottom of <a href="matlab:opentoline(''%s'',174)">%s</a>\n\n',fpath,fpath); + end + rethrow(err); + end +end + +function path_ = gs_path + % Return a valid path + % Start with the currently set path + path_ = user_string('ghostscript'); + % Check the path works + if check_gs_path(path_) + return + end + % Check whether the binary is on the path + if ispc + bin = {'gswin32c.exe', 'gswin64c.exe', 'gs'}; + else + bin = {'gs'}; + end + for a = 1:numel(bin) + path_ = bin{a}; + if check_store_gs_path(path_) + return + end + end + % Search the obvious places + if ispc + default_location = 'C:\Program Files\gs\'; + dir_list = dir(default_location); + if isempty(dir_list) + default_location = 'C:\Program Files (x86)\gs\'; % Possible location on 64-bit systems + dir_list = dir(default_location); + end + executable = {'\bin\gswin32c.exe', '\bin\gswin64c.exe'}; + ver_num = 0; + % If there are multiple versions, use the newest + for a = 1:numel(dir_list) + ver_num2 = sscanf(dir_list(a).name, 'gs%g'); + if ~isempty(ver_num2) && ver_num2 > ver_num + for b = 1:numel(executable) + path2 = [default_location dir_list(a).name executable{b}]; + if exist(path2, 'file') == 2 + path_ = path2; + ver_num = ver_num2; + end + end + end + end + if check_store_gs_path(path_) + return + end + else + executable = {'/usr/bin/gs', '/usr/local/bin/gs'}; + for a = 1:numel(executable) + path_ = executable{a}; + if check_store_gs_path(path_) + return + end + end + end + % Ask the user to enter the path + while true + if strncmp(computer, 'MAC', 3) % Is a Mac + % Give separate warning as the uigetdir dialogue box doesn't have a + % title + uiwait(warndlg('Ghostscript not found. Please locate the program.')) + end + base = uigetdir('/', 'Ghostcript not found. Please locate the program.'); + if isequal(base, 0) + % User hit cancel or closed window + break; + end + base = [base filesep]; %#ok<AGROW> + bin_dir = {'', ['bin' filesep], ['lib' filesep]}; + for a = 1:numel(bin_dir) + for b = 1:numel(bin) + path_ = [base bin_dir{a} bin{b}]; + if exist(path_, 'file') == 2 + if check_store_gs_path(path_) + return + end + end + end + end + end + if ismac + error('Ghostscript not found. Have you installed it (http://pages.uoregon.edu/koch)?'); + else + error('Ghostscript not found. Have you installed it from www.ghostscript.com?'); + end +end + +function good = check_store_gs_path(path_) + % Check the path is valid + good = check_gs_path(path_); + if ~good + return + end + % Update the current default path to the path found + if ~user_string('ghostscript', path_) + filename = fullfile(fileparts(which('user_string.m')), '.ignore', 'ghostscript.txt'); + warning('Path to ghostscript installation could not be saved in %s (perhaps a permissions issue). You can manually create this file and set its contents to %s, to improve performance in future invocations (this warning is safe to ignore).', filename, path_); + return + end +end + +function good = check_gs_path(path_) + persistent isOk + if isempty(path_) + isOk = false; + elseif ~isequal(isOk,true) + % Check whether the path is valid + [status, message] = system([gs_command(path_) '-h']); %#ok<ASGLU> + isOk = status == 0; + end + good = isOk; +end + +function cmd = gs_command(path_) + % Initialize any required system calls before calling ghostscript + % TODO: in Unix/Mac, find a way to determine whether to use "export" (bash) or "setenv" (csh/tcsh) + shell_cmd = ''; + if isunix + shell_cmd = 'export LD_LIBRARY_PATH=""; '; % Avoids an error on Linux with GS 9.07 + end + if ismac + shell_cmd = 'export DYLD_LIBRARY_PATH=""; '; % Avoids an error on Mac with GS 9.07 + end + % Construct the command string + cmd = sprintf('%s"%s" ', shell_cmd, path_); +end