ParaMonte MATLAB 3.0.0
Parallel Monte Carlo and Machine Learning Library
See the latest version documentation.
append_pdfs.m
Go to the documentation of this file.
1function append_pdfs(varargin)
2%APPEND_PDFS Appends/concatenates multiple PDF files
3%
4% Usage example:
5% append_pdfs(outputFilename, inputFilename1, inputFilename2, ...)
6% append_pdfs(outputFilename, inputFilenames_list{:})
7% append_pdfs(outputFilename, inputFilenames_cell_or_string_array)
8% append_pdfs output.pdf input1.pdf input2.pdf
9%
10% This function appends multiple PDF files to an existing PDF file, or
11% concatenates them into a PDF file if the output file doesn't yet exist.
12%
13% This function requires that you have ghostscript installed on your
14% system. Ghostscript can be downloaded from: http://www.ghostscript.com
15%
16% Inputs:
17% output - output file name (including the .pdf extension).
18% If it exists it is appended to; if not, it is created.
19% input1 - input file name(s) (including the .pdf extension).
20% All input files are appended in order.
21% input_list - cell array list of input file name strings. All input
22% files are appended in order.
23
24% Copyright: Oliver Woodford, 2011-2014, Yair Altman 2015-
25
26%{
27% Thanks to Reinhard Knoll for pointing out that appending multiple pdfs in
28% one go is much faster than appending them one at a time.
29
30% Thanks to Michael Teo for reporting the issue of a too long command line.
31% Issue resolved on 5/5/2011, by passing gs a command file.
32
33% Thanks to Martin Wittmann for pointing out quality issue when appending bitmaps
34% Issue resolved (to best of my ability) 1/6/2011, using the prepress setting
35
36% 26/02/15: If temp dir is not writable, use the output folder for temp
37% files when appending (Javier Paredes); sanity check of inputs
38% 24/01/18: Fixed error in case of existing output file (append mode)
39% 24/01/18: Fixed issue #213: non-ASCII characters in folder names on Windows
40% 06/12/18: Avoid an "invalid escape-char" warning upon error
41% 22/03/20: Alert if ghostscript.m is not found on Matlab path
42% 29/03/20: Accept a cell-array of input files (issue #299); accept both "strings", 'chars'
43% 25/01/22: Improved handling of missing input files & folder with non-ASCII chars (issue #349)
44% 07/06/23: Fixed (hopefully) unterminated quote run-time error (issues #367, #378); fixed handling of pathnames with non-ASCII chars (issue #349); display ghostscript command upon run-time invocation error
45% 06/07/23: Another attempt to fix issue #378 (remove unnecessary quotes from ghostscript cmdfile)
46%}
47
48 if nargin < 2, return; end % sanity check
49
50 % Convert strings => chars; strtrim extra spaces
51 varargin = cellfun(@str2char,varargin,'un',false);
52
53 % Convert cell array into individual strings (issue #299)
54 if nargin==2 && iscell(varargin{2})
55 varargin = {varargin{1} varargin{2}{:}}; %#ok<CCAT>
56 end
57
58 % Handle special cases of input args
59 numArgs = numel(varargin);
60 if numArgs < 2
61 error('export_fig:append_pdfs:NoInputs', 'append_pdfs: Missing input filenames')
62 end
63
64 % Ensure that ghostscript() exists on the Matlab path
65 if ~exist('ghostscript','file')
66 error('export_fig:append_pdfs:ghostscript', 'The ghostscript.m function is required by append_pdf.m. Install the complete export_fig package from https://www.mathworks.com/matlabcentral/fileexchange/23629-export_fig or https://github.com/altmany/export_fig')
67 end
68
69 % Are we appending or creating a new file?
70 append = exist(varargin{1}, 'file') == 2;
71 if ~append && numArgs == 2 % only 1 input file - copy it directly to output
72 copyfile(varargin{2}, varargin{1});
73 return
74 end
75
76 % Ensure that the temp dir is writable (Javier Paredes 26/2/15)
77 output = [tempname '.pdf'];
78 try
79 fid = fopen(output,'w');
80 fwrite(fid,1);
81 fclose(fid);
82 delete(output);
83 isTempDirOk = true;
84 catch
85 % Temp dir is not writable, so use the output folder
86 [dummy,fname,fext] = fileparts(output); %#ok<ASGLU>
87 fpath = fileparts(varargin{1});
88 output = fullfile(fpath,[fname fext]);
89 isTempDirOk = false;
90 end
91 if ~append
92 output = varargin{1};
93 varargin = varargin(2:end);
94 end
95
96 % Ensure that all input files exist
97 for fileIdx = 2 : numel(varargin)
98 filename = varargin{fileIdx};
99 if ~exist(filename,'file')
100 error('export_fig:append_pdf:MissingFile','Input file %s does not exist',filename);
101 end
102 end
103
104 % Create the command file
105 if isTempDirOk
106 cmdfile = [tempname '.txt'];
107 else
108 cmdfile = fullfile(fpath,[fname '.txt']);
109 end
110 prepareCmdFile(cmdfile, output, varargin{:});
111 hCleanup = onCleanup(@()cleanup(cmdfile));
112
113 % Call ghostscript
114 [status, errMsg] = ghostscript(['@"' cmdfile '"']);
115
116 % Check for ghostscript execution errors
117 if status && ~isempty(strfind(errMsg,'undefinedfile')) && ispc %#ok<STREMP>
118 % Fix issue #213: non-ASCII characters in folder names on Windows
119 for fileIdx = 2 : numel(varargin)
120 [fpath,fname,fext] = fileparts(varargin{fileIdx});
121 varargin{fileIdx} = fullfile(normalizePath(fpath),[fname fext]);
122 end
123 % Rerun ghostscript with the normalized folder names
124 prepareCmdFile(cmdfile, output, varargin{:});
125 [status, errMsg] = ghostscript(['@"' cmdfile '"']);
126 end
127
128 % Delete the command file
129 %delete(cmdfile);
130
131 % Check for ghostscript execution errors
132 if status
133 type(cmdfile);
134 errMsg = strrep(errMsg,'\','\\'); % Avoid an "invalid escape-char" warning
135 error('export_fig:append_pdf:ghostscriptError',errMsg);
136 end
137
138 % Rename the file if needed
139 if append
140 movefile(output, varargin{1}, 'f');
141 end
142end
143
144% Cleanup function
145function cleanup(cmdfile)
146 % Delete the command file
147 try delete(cmdfile); catch, end
148end
149
150% Prepare a text file with ghostscript directives
151function prepareCmdFile(cmdfile, output, varargin)
152 if ispc, output(output=='\') = '/'; varargin = strrep(varargin,'\','/'); end
153 varargin = strrep(varargin,'"','');
154
155 str = ['-q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dPDFSETTINGS=/prepress ' ...
156 '-sOutputFile="' output '" -f ' sprintf('"%s" ',varargin{:})];
157 str = regexprep(str, ' "?" ',' '); % remove empty strings (issues #367,#378)
158 str = regexprep(str, '"([^ ]*)"', '$1'); % remove unnecessary quotes
159 str = strtrim(str); % trim extra spaces
160
161 fh = fopen(cmdfile, 'w');
162 fprintf(fh,'%s',str);
163 fclose(fh);
164end
165
166% Convert long/non-ASCII folder names into their short ASCII equivalents
167function pathStr = normalizePath(pathStr)
168 [fpath,fname,fext] = fileparts(pathStr);
169 if isempty(fpath) || strcmpi(fpath,pathStr), return, end
170 dirOutput = evalc(['system(''dir /X /AD "' pathStr '*"'')']);
171 regexpStr = ['.*\s(\S+)\s*' fname fext '.*'];
172 shortName = regexprep(dirOutput,regexpStr,'$1');
173 if isempty(shortName) || isequal(shortName,dirOutput) || strcmpi(shortName,'<DIR>')
174 shortName = [fname fext];
175 end
176 fpath = normalizePath(fpath); %recursive until entire fpath is processed
177 pathStr = fullfile(fpath, shortName);
178end
179
180% Convert a possible string => char
181function value = str2char(value)
182 try
183 value = controllib.internal.util.hString2Char(value);
184 catch
185 if isa(value,'string')
186 value = char(value);
187 end
188 end
189 value = strtrim(value);
190end
function normalizePath(in pathStr)
function prepareCmdFile(in cmdfile, in output, in varargin)
function str2char(in value)
function append_pdfs(in varargin)
function cleanup(in cmdfile)
function copy(in from, in to, in fields)
Copy the contents of the struct/object from to the struct/object to recursively and without destroyin...
function ghostscript(in cmd)