ParaMonte MATLAB 3.0.0
Parallel Monte Carlo and Machine Learning Library
See the latest version documentation.
eps2pdf.m
Go to the documentation of this file.
1function eps2pdf(source, dest, crop, append, gray, quality, gs_options) %#ok<*RGXPI>
2%EPS2PDF Convert an eps file to pdf format using ghostscript
3%
4% Examples:
5% eps2pdf source dest
6% eps2pdf(source, dest, crop)
7% eps2pdf(source, dest, crop, append)
8% eps2pdf(source, dest, crop, append, gray)
9% eps2pdf(source, dest, crop, append, gray, quality)
10% eps2pdf(source, dest, crop, append, gray, quality, gs_options)
11%
12% This function converts an eps file to pdf format. The output can be
13% optionally cropped and also converted to grayscale. If the output pdf
14% file already exists then the eps file can optionally be appended as a new
15% page on the end of the eps file. The level of bitmap compression can also
16% optionally be set.
17%
18% This function requires that you have ghostscript installed on your system.
19% Ghostscript can be downloaded from: http://www.ghostscript.com
20%
21% Inputs:
22% source - filename of the source eps file to convert. The filename is
23% assumed to already have the extension ".eps".
24% dest - filename of the destination pdf file. The filename is assumed
25% to already have the extension ".pdf".
26% crop - boolean indicating whether to crop the borders off the pdf.
27% Default: true.
28% append - boolean indicating whether the eps should be appended to the
29% end of the pdf as a new page (if the pdf exists already).
30% Default: false.
31% gray - boolean indicating whether the output pdf should be grayscale
32% or not. Default: false.
33% quality - scalar indicating the level of image bitmap quality to
34% output. A larger value gives a higher quality. quality > 100
35% gives lossless output. Default: ghostscript prepress default.
36% gs_options - optional ghostscript options (e.g.: '-dNoOutputFonts'). If
37% multiple options are needed, enclose in call array: {'-a','-b'}
38
39% Copyright (C) Oliver Woodford 2009-2014, Yair Altman 2015-
40
41% Suggestion of appending pdf files provided by Matt C at:
42% http://www.mathworks.com/matlabcentral/fileexchange/23629
43
44% Thank you Fabio Viola for pointing out compression artifacts, leading to the quality setting.
45% Thank you Scott for pointing out the subsampling of very small images, which was fixed for lossless compression settings.
46
47% 09/12/11: Pass font path to ghostscript
48% 26/02/15: If temp dir is not writable, use the dest folder for temp destination files (Javier Paredes)
49% 28/02/15: Enable users to specify optional ghostscript options (issue #36)
50% 01/03/15: Upon GS error, retry without the -sFONTPATH= option (this might solve
51% some /findfont errors according to James Rankin, FEX Comment 23/01/15)
52% 23/06/15: Added extra debug info in case of ghostscript error; code indentation
53% 04/10/15: Suggest a workaround for issue #41 (missing font path; thanks Mariia Fedotenkova)
54% 22/02/16: Bug fix from latest release of this file (workaround for issue #41)
55% 20/03/17: Added informational message in case of GS croak (issue #186)
56% 16/01/18: Improved appending of multiple EPS files into single PDF (issue #233; thanks @shartjen)
57% 18/10/19: Workaround for GS 9.51+ .setpdfwrite removal problem (issue #285)
58% 18/10/19: Warn when ignoring GS fontpath or quality options; clarified error messages
59% 15/01/20: Added information about the GS/destination filepath in case of error (issue #294)
60% 20/01/20: Attempted fix for issue #285: unsupported patch transparency in some Ghostscript versions
61% 12/02/20: Improved fix for issue #285: add -dNOSAFER and -dALLOWPSTRANSPARENCY (thanks @linasstonys)
62% 26/08/21: Added GS version to error message; fixed some problems with PDF append (issue #339)
63% 20/02/23: Added GS fixes suggested by @scholnik (issues #285, #368)
64
65 % Intialise the options string for ghostscript
66 downsampleOptions = ['-dDownsampleColorImages=false ' ...
67 '-dDownsampleGrayImages=false ' ...
68 '-dDownsampleMonoImages=false']; %issue #368
69 options = ['-q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dPDFSETTINGS=/prepress ' ...
70 downsampleOptions ' -sOutputFile="' dest '"'];
71
72 % Set crop option
73 if nargin < 3 || crop
74 options = [options ' -dEPSCrop'];
75 end
76
77 % Set the font path
78 fp = font_path();
79 if ~isempty(fp)
80 options = [options ' -sFONTPATH="' fp '"'];
81 end
82
83 % Set the grayscale option
84 if nargin > 4 && gray
85 options = [options ' -sColorConversionStrategy=Gray -dProcessColorModel=/DeviceGray'];
86 end
87
88 % Set the bitmap quality
89 qualityOptions = '';
90 if nargin > 5 && ~isempty(quality)
91 qualityOptions = ' -dAutoFilterColorImages=false -dAutoFilterGrayImages=false';
92 if quality > 100
93 qualityOptions = [qualityOptions ' -dColorImageFilter=/FlateEncode -dGrayImageFilter=/FlateEncode'];
94 qualityOptions = [qualityOptions ' -c ".setpdfwrite << /ColorImageDownsampleThreshold 10 /GrayImageDownsampleThreshold 10 >> setdistillerparams"'];
95 else
96 qualityOptions = [qualityOptions ' -dColorImageFilter=/DCTEncode -dGrayImageFilter=/DCTEncode'];
97 v = 1 + (quality < 80);
98 quality = 1 - quality / 100;
99 s = sprintf('<< /QFactor %.2f /Blend 1 /HSample [%d 1 1 %d] /VSample [%d 1 1 %d] >>', quality, v, v, v, v);
100 qualityOptions = [qualityOptions ' -c ".setpdfwrite << /ColorImageDict ' s ' /GrayImageDict ' s ' >> setdistillerparams"'];
101 end
102 options = [options qualityOptions];
103 end
104
105 % Enable users to specify optional ghostscript options (issue #36)
106 if nargin > 6 && ~isempty(gs_options)
107 if iscell(gs_options)
108 gs_options = sprintf(' %s',gs_options{:});
109 elseif ~ischar(gs_options)
110 error('gs_options input argument must be a string or cell-array of strings');
111 else
112 gs_options = [' ' gs_options];
113 end
114 options = [options gs_options];
115 end
116
117 % Check if the output file exists
118 if nargin > 3 && append && exist(dest, 'file') == 2
119 % Store the original filesize for later use below
120 try
121 file_info = dir(dest);
122 orig_bytes = file_info.bytes;
123 catch
124 orig_bytes = [];
125 end
126 % File exists - append current figure to the end
127 tmp_nam = [tempname '.pdf'];
128 [fpath,fname,fext] = fileparts(tmp_nam);
129 try
130 % Ensure that the temp dir is writable (Javier Paredes 26/2/15)
131 fid = fopen(tmp_nam,'w');
132 fwrite(fid,1);
133 fclose(fid);
134 delete(tmp_nam);
135 catch
136 % Temp dir is not writable, so use the dest folder
137 fpath = fileparts(dest);
138 tmp_nam = fullfile(fpath,[fname fext]);
139 end
140 % Copy the original (dest) pdf file to temporary folder
141 copyfile(dest, tmp_nam);
142 % Produce an interim pdf of the source eps, rather than adding the eps directly (issue #233)
143 % this will override the original (dest) pdf file
144 orig_options = options;
145 ghostscript([options ' -f "' source '"']);
146 [~,fname] = fileparts(tempname);
147 tmp_nam2 = fullfile(fpath,[fname fext]); % ensure using a writable folder (not necessarily tempdir)
148 copyfile(dest, tmp_nam2);
149 % Add the original pdf (tmp_nam) and interim pdf (dest=>tmp_nam2) as inputs to ghostscript
150 %options = [options ' -f "' tmp_nam '" "' source '"']; % append the source eps to dest pdf
151 options = [options ' -f "' tmp_nam '" "' tmp_nam2 '"']; % append the interim pdf to dest pdf
152 try
153 % Convert to pdf using ghostscript
154 [status, message] = ghostscript(options);
155 % The output pdf should now be in dest
156
157 % If the returned message is non-empty, a possible error may have
158 % occured, so check the file size to ensure whether the file grew
159 if ~isempty(message) && ~isempty(orig_bytes)
160 file_info = dir(dest);
161 new_bytes = file_info.bytes;
162 if new_bytes < orig_bytes + 100
163 % Looks like nothing substantial (if anything) was appended to
164 % the original pdf, so try adding the eps file directly (issue #339)
165 options = [orig_options ' -f "' tmp_nam '" "' source '"']; % append the source eps to dest pdf
166 [status, message] = ghostscript(options);
167 end
168 end
169
170 % Delete the intermediate (temporary) files
171 delete(tmp_nam);
172 delete(tmp_nam2);
173 catch me
174 % Delete the intermediate files and rethrow the error
175 delete(tmp_nam);
176 delete(tmp_nam2);
177 rethrow(me);
178 end
179 else
180 % File doesn't exist or should be over-written
181 % Add the source eps file as input to ghostscript
182 options = [options ' -f "' source '"'];
183 % Convert to pdf using ghostscript
184 [status, message] = ghostscript(options);
185 end
186
187 % Check for error
188 if status
189 % Catch and correct undefined .setopacityalpha errors (issue #285)
190 % (see explanation inside print2eps.m)
191 if ~isempty(regexpi(message,'undefined in .setopacityalpha'))
192 % First try with -dNOSAFER and -dALLOWPSTRANSPARENCY (thanks @linasstonys)
193 new_options = [options ' -dNOSAFER -dALLOWPSTRANSPARENCY'];
194 [status, message] = ghostscript(new_options);
195 if ~status % hurray! (no error)
196 return
197 elseif isempty(regexpi(message,'undefined in .setopacityalpha')) % still some other error
198 options = new_options;
199 else % we still get a .setopacityalpha error
200 % Remove the transparency and retry
201 fstrm = read_write_entire_textfile(source);
202 fstrm = regexprep(fstrm, '0?\.\d+ .setopacityalpha \w+\n', '');
203 read_write_entire_textfile(source, fstrm);
204 [status, message] = ghostscript(options);
205 if ~status % hurray! (no error)
206 % Alert the user that transparency is not supported
207 warning('export_fig:GS:quality','Export_fig Face/Edge alpha transparancy is ignored - not supported by your Ghostscript version')
208 return
209 end
210 end
211 end
212
213 % Retry without the -sFONTPATH= option (this might solve some GS
214 % /findfont errors according to James Rankin, FEX Comment 23/01/15)
215 orig_options = options;
216 if ~isempty(fp)
217 options = regexprep(options, ' -sFONTPATH=[^ ]+ ',' ');
218 [status, message] = ghostscript(options);
219 if ~status % hurray! (no error)
220 warning('export_fig:GS:fontpath','Export_fig font option is ignored - not supported by your Ghostscript version')
221 return
222 end
223 end
224
225 % Retry with updated or no quality options (may solve problems with GS 9.51+, issue #285)
226 if ~isempty(qualityOptions)
227 % First try replacing .setpdfwrite as suggested in ghostscript error (issue #285)
228 options = strrep(orig_options, '.setpdfwrite', '3000000 setvmthreshold');
229 if ~ghostscript(options) % hurray! (no error)
230 % No warning: there's no known drawback when this works so no need to inform the user
231 %warning('export_fig:GS:setpdfwrite','Successfully worked around deprecated .setpdfwrite')
232 return
233 end
234 % Well, we tried. Fall back to no quality options.
235 options = strrep(orig_options, qualityOptions, '');
236 if ~ghostscript(options) % hurray! (no error)
237 warning('export_fig:GS:quality','Export_fig quality option ignored - not supported by your Ghostscript version')
238 return
239 end
240 % Hmm, perhaps the problem is just with the downsampleOptions?
241 options = strrep(orig_options, downsampleOptions, '');
242 if ~ghostscript(options) % hurray! (no error)
243 warning('export_fig:GS:downsample','Export_fig quality option ignored - not supported by your Ghostscript version')
244 return
245 end
246 % Nope, last attempt: remove both downsampleOptions & qualityOptions
247 options = strrep(orig_options, qualityOptions, '');
248 options = strrep(options, downsampleOptions, '');
249 [status, message] = ghostscript(options);
250 if ~status % hurray! (no error)
251 warning('export_fig:GS:quality2','Export_fig quality option ignored - not supported by your Ghostscript version')
252 return
253 end
254 else % no quality options, the problem lies elsewhere...
255 % Hmm, perhaps the problem is just with the downsampleOptions?
256 options = strrep(orig_options, downsampleOptions, '');
257 if ~ghostscript(options) % hurray! (no error)
258 warning('export_fig:GS:downsample','Export_fig quality option ignored - not supported by your Ghostscript version')
259 return
260 end
261 end
262 % Any other ideas, anyone?
263
264 % Report error
265 if isempty(message)
266 error(['Unable to generate pdf. Ensure that the destination folder (' fileparts(dest) ') is writable.']);
267 elseif ~isempty(strfind(message,'/typecheck in /findfont')) %#ok<STREMP>
268 % Suggest a workaround for issue #41 (missing font path)
269 font_name = strtrim(regexprep(message,'.*Operand stack:\s*(.*)\s*Execution.*','$1'));
270 fprintf(2, 'Ghostscript error: could not find the following font(s): %s\n', font_name);
271 %fpath = fileparts(mfilename('fullpath'));
272 %gs_fonts_file = fullfile(fpath, '.ignore', 'gs_font_path.txt');
273 [unused, gs_fonts_file] = user_string('gs_font_path'); %#ok<ASGLU>
274 fprintf(2, ' try to add the font''s folder to your %s file\n\n', gs_fonts_file);
275 error('export_fig error');
276 else
277 gs_options = strtrim(gs_options);
278 fprintf(2, '\nGhostscript error: ');
279 msg = regexprep(message, '^Error: /([^\n]+).*', '$1');
280 if ~isempty(msg) && ~strcmp(msg,message)
281 fprintf(2,'%s',msg);
282 end
283 fprintf(2, '\n * perhaps %s is open by another application\n', dest);
284 try gs_version = str2num(evalc('ghostscript(''--version'');')); catch, gs_version = ''; end %#ok<ST2NM>
285 if ~isempty(gs_version), gs_version = [' ' num2str(gs_version)]; end
286 if ~isempty(gs_options)
287 fprintf(2, ' * or maybe your Ghostscript version%s does not accept the extra "%s" option(s) that you requested\n', gs_version, gs_options);
288 end
289 fprintf(2, ' * or maybe you have another gs executable in your system''s path\n\n');
290 fprintf(2, 'Ghostscript path: %s\n', user_string('ghostscript'));
291 fprintf(2, 'Ghostscript options: %s\n\n', orig_options);
292 error(message);
293 end
294 end
295end
296
297% Function to return (and create, where necessary) the font path
298function fp = font_path()
299 fp = user_string('gs_font_path');
300 if ~isempty(fp)
301 return
302 end
303 % Create the path
304 % Start with the default path
305 fp = getenv('GS_FONTPATH');
306 % Add on the typical directories for a given OS
307 if ispc
308 if ~isempty(fp)
309 fp = [fp ';'];
310 end
311 fp = [fp getenv('WINDIR') filesep 'Fonts'];
312 else
313 if ~isempty(fp)
314 fp = [fp ':'];
315 end
316 fp = [fp '/usr/share/fonts:/usr/local/share/fonts:/usr/share/fonts/X11:/usr/local/share/fonts/X11:/usr/share/fonts/truetype:/usr/local/share/fonts/truetype'];
317 end
318 user_string('gs_font_path', fp);
319end
function version(in silent)
Return a scalar MATLAB string containing the latest available ParaMonte MATLAB version newer than the...
function font_path()
function eps2pdf(in source, in dest, in crop, in append, in gray, in quality, in gs_options)
function ghostscript(in cmd)
function info()
Return a MATLAB string and the corresponding cache file path containing the current system informatio...
function release(in type)
Return a scalar MATLAB string containing the MATLAB release version, year, or season as requested.
function user_string(in string_name, in string)
function which(in vendor)
Return the a MATLAB string containing the path to the first mpiexec executable binary found in system...