2%PRINT2EPS Prints figures to eps with improved line styles
7%
print2eps(filename, fig_handle, export_options)
8%
print2eps(filename, fig_handle, export_options, print_options)
10% This function saves a figure as an eps file, with two improvements over
11% MATLAB
's print command. First, it improves the line style, making dashed
12% lines more like those on screen and giving grid lines a dotted line style.
13% Secondly, it substitutes original font names back into the eps file,
14% where these have been changed by MATLAB, for up to 11 different fonts.
17% filename - string containing the name (optionally including full or
18% relative path) of the file the figure is to be saved as. A
19% ".eps" extension is added if not there already. If a path is
20% not specified, the figure is saved in the current directory.
21% fig_handle - The handle of the figure to be saved. Default: gcf().
22% export_options - array or struct of optional values:
23% bb_padding - Scalar value of amount of padding to add to border around
24% the cropped image, in points (if >1) or percent (if <1).
25% Can be negative as well as positive; Default: 0
26% crop - Cropping flag. Deafult: 0
27% fontswap - Whether to swap non-default fonts in figure. Default: true
28% preserve_size - Whether to preserve the figure's PaperSize. Default:
false
29% font_space - Character used to separate font-
name terms in the EPS output
30% e.g.
"Courier New" =>
"Courier-New". Default:
''
31% (available only via the
struct alternative)
32% renderer - Renderer used to generate bounding-box. Default:
'opengl'
33% (available only via the
struct alternative)
34% crop_amounts - 4-element vector of crop amounts: [top,right,bottom,left]
35% (available only via the
struct alternative)
36% regexprep - 2-element cell-array of regular-expression replacement in the
37% generated EPS. 1st element is the replaced string(s), 2nd is
38% the replacement(s) (available only via the
struct alternative)
39% print_options - Additional parameter strings to be passed to the print command
42% Copyright (C) Oliver Woodford 2008-2014, Yair Altman 2015-
44% The idea of editing the EPS file to change line styles comes from Jiro
45% Doke
's FIXPSLINESTYLE (fex id: 17928)
46% The idea of changing dash length with line width came from comments on
47% fex id: 5743, but the implementation is mine :)
50% 14/11/11: Fix a MATLAB bug rendering black or white text incorrectly.
51% Thanks to Mathieu Morlighem for reporting the issue and
52% obtaining a fix from TMW.
53% 08/12/11: Added ability to correct fonts. Several people have requested
54% this at one time or another, and also pointed me to printeps
55% (fex id: 7501), so thank you to them. My implementation (which
56% was not inspired by printeps - I'd already had the idea
for my
57% approach) goes slightly further in that it allows multiple
59% 14/12/11: Fix bug affecting font names containing spaces. Thanks to David
60% Szwer
for reporting the issue.
61% 25/01/12: Add a font not to be swapped. Thanks to Anna Rafferty and Adam
62% Jackson
for reporting the issue. Also fix a bug whereby
using a
63% font alias can lead to another font being swapped in.
64% 10/04/12: Make the font swapping
case insensitive.
65% 26/10/12: Set PaperOrientation to portrait. Thanks to Michael Watts
for
67% 26/10/12: Fix issue to
do with swapping fonts changing other fonts and
68% sizes we don
't want, due to listeners. Thanks to Malcolm Hudson
69% for reporting the issue.
70% 22/03/13: Extend font swapping to axes labels. Thanks to Rasmus Ischebeck
71% for reporting the issue.
72% 23/07/13: Bug fix to font swapping. Thanks to George for reporting the
74% 13/08/13: Fix MATLAB feature of not exporting white lines correctly.
75% Thanks to Sebastian Hesslinger for reporting it.
76% 24/02/15: Fix for Matlab R2014b bug (issue #31): LineWidths<0.75 are not
77% set in the EPS (default line width is used)
78% 25/02/15: Fixed issue #32: BoundingBox problem caused uncropped EPS/PDF files
79% 05/03/15: Fixed issue #43: Inability to perform EPS file post-processing
80% 06/03/15: Improved image padding & cropping thanks to Oscar Hartogensis
81% 21/03/15: Fixed edge-case of missing handles having a 'FontName
' property
82% 26/03/15: Attempt to fix issue #45: white lines in subplots do not print correctly
83% 27/03/15: Attempt to fix issue #44: white artifact lines appearing in patch exports
84% 30/03/15: Fixed issue #52: improved performance on HG2 (R2014b+)
85% 09/04/15: Comment blocks consolidation and minor code cleanup (no real code change)
86% 12/04/15: Fixed issue #56: bad cropping
87% 14/04/15: Workaround for issue #45: lines in image subplots are exported in invalid color
88% 07/07/15: Added option to avoid font-swapping in EPS/PDF
89% 07/07/15: Fixed issue #83: use numeric handles in HG1
90% 22/07/15: Fixed issue #91 (thanks to Carlos Moffat)
91% 28/09/15: Fixed issue #108 (thanks to JacobD10)
92% 01/11/15: Fixed issue #112: optional renderer for bounding-box computation (thanks to Jesús Pestana Puerta)
93% 21/02/16: Enabled specifying non-automated crop amounts
94% 22/02/16: Better support + backward compatibility for transparency (issue #108)
95% 10/06/16: Fixed issue #159: text handles get cleared by Matlab in the print() command
96% 12/06/16: Improved the fix for issue #159 (in the previous commit)
97% 12/06/16: Fixed issue #158: transparent patch color in PDF/EPS
98% 18/09/17: Fixed issue #194: incorrect fonts in EPS/PDF output
99% 18/09/17: Fixed issue #195: relaxed too-tight cropping in EPS/PDF
100% 14/11/17: Workaround for issue #211: dashed/dotted lines in 3D axes appear solid
101% 15/11/17: Updated issue #211: only set SortMethod='ChildOrder
' in HG2, and when it looks the same onscreen; support multiple figure axes
102% 18/11/17: Fixed issue #225: transparent/translucent dashed/dotted lines appear solid in EPS/PDF
103% 24/03/18: Fixed issue #239: black title meshes with temporary black background figure bgcolor, causing bad cropping
104% 21/03/19: Improvement for issue #258: missing fonts in output EPS/PDF (still *NOT* fully solved)
105% 21/03/19: Fixed issues #166,#251: Arial font is no longer replaced with Helvetica but rather treated as a non-standard user font
106% 14/05/19: Made Helvetica the top default font-swap, replacing Courier
107% 12/06/19: Issue #277: Enabled preservation of figure's PaperSize in output PDF/EPS file
108% 06/08/19: Issue #281: only fix patch/textbox color
if it
's not opaque
109% 15/01/20: Added warning ID for easier suppression by users
110% 20/01/20: Added comment about unsupported patch transparency in some Ghostscript versions (issue #285)
111% 10/12/20: Enabled user-specified regexp replacements in the generated EPS file (issue #324)
112% 11/03/21: Added documentation about export_options.regexprep; added sanity check (issue #324)
113% 21/07/21: Fixed misleading warning message about regexprep field when it's empty (issue #338)
114% 26/08/21: Added a
short pause to avoid unintended image cropping (issue #318)
115% 16/03/22: Fixed occasional empty files due to excessive cropping (issues #350, #351)
116% 15/05/22: Fixed EPS bounding box (issue #356)
117% 13/04/23: Reduced (hopefully fixed) unintended EPS/PDF image cropping (issues #97, #318)
120 options = {
'-loose'};
122 options = [options varargin];
130 % Retrieve padding, crop & font-swap values
131 crop_amounts = nan(1,4); %
auto-crop all 4 sides by
default
132 if isstruct(export_options)
133 try preserve_size = export_options.preserve_size;
catch, preserve_size =
false; end
134 try fontswap = export_options.fontswap;
catch, fontswap =
true; end
135 try font_space = export_options.font_space;
catch, font_space =
''; end
136 font_space(2:end) =
'';
137 try bb_crop = export_options.crop;
catch, bb_crop = 0; end
138 try crop_amounts = export_options.crop_amounts;
catch, end
139 try bb_padding = export_options.bb_padding;
catch, bb_padding = 0; end
140 try renderer = export_options.rendererStr;
catch, renderer =
'opengl'; end % fix
for issue #110
141 if renderer(1)~=
'-', renderer = [
'-' renderer]; end
143 if numel(export_options) > 3 % preserve_size
144 preserve_size = export_options(4);
146 preserve_size =
false;
148 if numel(export_options) > 2 % font-swapping
149 fontswap = export_options(3);
153 if numel(export_options) > 1 % cropping
154 bb_crop = export_options(2);
156 bb_crop = 0; % scalar value, so use
default bb_crop value of 0
158 if numel(export_options) > 0 % padding
159 bb_padding = export_options(1);
163 renderer =
'-opengl';
167 % Construct the filename
168 if numel(
name) < 5 || ~strcmpi(
name(end-3:end),
'.eps')
169 name = [
name '.eps']; % Add the missing extension
173 old_pos_mode = get(fig, 'PaperPositionMode');
174 old_orientation = get(fig, 'PaperOrientation');
175 old_paper_units = get(fig, 'PaperUnits');
176 set(fig, 'PaperPositionMode','auto', 'PaperOrientation','portrait', 'PaperUnits','points');
178 % Find all the used fonts in the figure
179 font_handles = findall(fig, '-property', 'FontName');
180 fonts = get(font_handles, 'FontName');
183 elseif ~iscell(fonts)
187 % Map supported font aliases onto the correct
name
188 fontsl = lower(fonts);
189 for a = 1:numel(fonts)
193 case {
'times',
'timesnewroman',
'times-roman'}
195 %
case {
'arial',
'helvetica'} % issues #166, #251
196 % fontsl{a} =
'helvetica';
197 case {
'newcenturyschoolbook',
'newcenturyschlbk'}
198 fontsl{a} =
'newcenturyschlbk';
202 fontslu = unique(fontsl);
204 % Determine the font swap table
206 % Issue #258: Rearrange standard fonts
list based on decending
"problematicness"
207 % The issue is still *NOT* fully solved because I cannot figure out how to force
208 % the EPS postscript engine to look
for the user
's font on disk
209 % Also see: https://stat.ethz.ch/pipermail/r-help/2005-January/064374.html
210 matlab_fonts = {'Helvetica
', 'Times
', 'Courier
', 'Symbol
', 'ZapfDingbats
', ...
211 'Palatino
', 'Bookman
', 'ZapfChancery
', 'AvantGarde
', ...
212 'NewCenturySchlbk
', 'Helvetica-Narrow
'};
213 matlab_fontsl = lower(matlab_fonts);
214 require_swap = find(~ismember(fontslu, matlab_fontsl));
215 unused_fonts = find(~ismember(matlab_fontsl, fontslu));
216 font_swap = cell(3, min(numel(require_swap), numel(unused_fonts)));
218 for a = 1:size(font_swap, 2)
219 font_swap{1,a} = find(strcmp(fontslu{require_swap(a)}, fontsl));
220 font_swap{2,a} = matlab_fonts{unused_fonts(a)};
221 font_swap{3,a} = fonts{font_swap{1,a}(1)};
222 fonts_new(font_swap{1,a}) = font_swap(2,a);
229 if ~isempty(font_swap)
230 fonts_size = get(font_handles, 'FontSize
');
231 if iscell(fonts_size)
232 fonts_size = cell2mat(fonts_size);
234 M = false(size(font_handles));
236 % Loop because some changes may not stick first time, due to listeners
238 update = zeros(1000, 1);
239 for b = 1:10 % Limit number of loops to avoid infinite loop case
241 M(a) = ~isequal(get(font_handles(a), 'FontName
'), fonts_new{a}) || ~isequal(get(font_handles(a), 'FontSize
'), fonts_size(a));
243 set(font_handles(a), 'FontName
', fonts_new{a}, 'FontSize
', fonts_size(a));
253 % Compute the order to revert fonts later, without the need of a loop
254 [update, M] = unique(update(1:c));
255 [dummy, M] = sort(M); %#ok<ASGLU>
256 update = reshape(update(M), 1, []);
259 % MATLAB bug fix - black and white text can come out inverted sometimes
260 % Find the white and black text
261 black_text_handles = findall(fig, 'Type
', 'text
', 'Color
', [0 0 0]);
262 white_text_handles = findall(fig, 'Type
', 'text
', 'Color
', [1 1 1]);
263 % Set the font colors slightly off their correct values
264 set(black_text_handles, 'Color
', [0 0 0] + eps);
265 set(white_text_handles, 'Color
', [1 1 1] - eps);
267 % MATLAB bug fix - white lines can come out funny sometimes
268 % Find the white lines
269 white_line_handles = findall(fig, 'Type
', 'line
', 'Color
', [1 1 1]);
270 % Set the line color slightly off white
271 set(white_line_handles, 'Color
', [1 1 1] - 0.00001);
273 % MATLAB bug fix (issue #211): dashed/dotted lines in 3D axes appear solid
274 % Note: this "may limit other functionality in plotting such as hidden line/surface removal"
275 % reference: Technical Support Case #02838114, https://mail.google.com/mail/u/0/#inbox/15fb7659f70e7bd8
276 hAxes = findall(fig, 'Type
', 'axes
');
277 if using_hg2 && ~isempty(hAxes) % issue #211 presumably happens only in HG2, not HG1
279 % If there are any axes using SortMethod~='ChildOrder
'
280 oldSortMethods = get(hAxes,{'SortMethod
'}); % use {'SortMethod
'} to ensure we get a cell array, even for single axes
281 if any(~strcmpi('ChildOrder
',oldSortMethods)) % i.e., any oldSortMethods=='depth
'
282 % Check if the axes look visually different onscreen when SortMethod='ChildOrder
'
283 imgBefore = print2array(fig);
284 set(hAxes,'SortMethod
','ChildOrder
');
285 imgAfter = print2array(fig);
286 if isequal(imgBefore, imgAfter)
287 % They look the same, so use SortMethod='ChildOrder
' when generating the EPS
289 % They look different, so revert SortMethod and issue a warning message
290 warning('YMA:export_fig:issue211
', ...
291 ['You seem to be
using axes that have overlapping/hidden graphic elements.
' 10 ...
292 'Setting axes.SortMethod=
''ChildOrder
'' may solve potential problems in EPS/PDF export.
' 10 ...
293 'Additional
info: https:
294 set(hAxes,{
'SortMethod'},oldSortMethods);
299 a=err; %#ok<NASGU> % debug breakpoint
303 % Workaround
for issue #45: lines in image subplots are exported in invalid color
304 % In
this case the -depsc driver solves the problem, but then all the other workarounds
305 % below (
for all the other issues) will fail, so it
's better to let the user decide by
306 % just issuing a warning and accepting the '-depsc
' input parameter
307 epsLevel2 = ~any(strcmpi(options,'-depsc
'));
309 % Use -depsc2 (EPS color level-2) if -depsc (EPS color level-3) was not specifically requested
310 options{end+1} = '-depsc2
';
311 % Issue a warning if multiple images & lines were found in the figure, and HG1 with painters renderer is used
312 isPainters = any(strcmpi(options,'-painters
'));
313 if isPainters && ~using_hg2 && numel(findall(fig,'Type
','image
'))>1 && ~isempty(findall(fig,'Type
','line
'))
314 warning('YMA:export_fig:issue45
', ...
315 ['Multiple images & lines detected. In such cases, the lines might \n
' ...
316 'appear with an invalid color due to an internal MATLAB bug (fixed in R2014b). \n
' ...
317 'Possible workaround: add a
''-depsc
'' or
''-opengl
'' parameter to the export_fig command.
']);
321 % Fix issue #83: use numeric handles in HG1
322 if ~using_hg2(fig), fig = double(fig); end
324 % Workaround for when transparency is lost through conversion fig>EPS>PDF (issue #108)
325 % Replace transparent patch RGB values with an ID value (rare chance that ID color is being used already)
327 origAlphaColors = eps_maintainAlpha(fig);
330 % Ensure that everything is fully rendered, to avoid cropping (issue #318)
331 drawnow; pause(0.05);
334 print(fig, options{:}, name);
336 % Restore the original axes SortMethods (if updated)
337 try set(hAxes,{'SortMethod
'},oldSortMethods); catch, end
339 % Do post-processing on the eps file
341 % Read the EPS file into memory
342 fstrm = read_write_entire_textfile(name);
347 % Restore colors for transparent patches/lines and apply the
348 % setopacityalpha setting in the EPS file (issue #108)
350 [~,fstrm,foundFlags] = eps_maintainAlpha(fig, fstrm, origAlphaColors);
352 % If some of the transparencies were not found in the EPS file, then rerun the
353 % export with only the found transparencies modified (backward compatibility)
354 if ~isempty(fstrm) && ~all(foundFlags)
355 foundIdx = find(foundFlags);
356 for objIdx = 1 : sum(foundFlags)
357 colorsIdx = foundIdx(objIdx);
358 colorsData = origAlphaColors{colorsIdx};
359 hObj = colorsData{1};
360 propName = colorsData{2};
361 newColor = colorsData{4};
362 hObj.(propName).ColorData = newColor;
365 print(fig, options{:}, name);
366 fstrm = read_write_entire_textfile(name);
367 [~,fstrm] = eps_maintainAlpha(fig, fstrm, origAlphaColors(foundFlags));
371 % Bail out if EPS post-processing is not possible
373 warning('YMA:export_fig:EPS
','Loading EPS file failed, so unable to perform post-processing. This is usually because the figure contains a large number of patch objects. Consider exporting to a bitmap format in
this case.
');
377 % Fix for Matlab R2014b bug (issue #31): LineWidths<0.75 are not set in the EPS (default line width is used)
380 % Convert miter joins to line joins
381 %fstrm = regexprep(fstrm, '\n10.0 ML\n
', '\n1 LJ\n
');
382 % This is faster (the original regexprep could take many seconds when the axes contains many lines):
383 fstrm = strrep(fstrm, sprintf('\n10.0 ML\n
'), sprintf('\n1 LJ\n
'));
385 % In HG2, grid lines and axes Ruler Axles have a default LineWidth of 0.5 => replace en-bulk (assume that 1.0 LineWidth = 1.333 LW)
386 % hAxes=gca; hAxes.YGridHandle.LineWidth, hAxes.YRuler.Axle.LineWidth
387 %fstrm = regexprep(fstrm, '(GC\n2 setlinecap\n1 LJ)\nN
', '$1\n0.667 LW\nN
');
389 fstrm = strrep(fstrm, sprintf('GC\n2 setlinecap\n1 LJ\nN
'), sprintf('GC\n2 setlinecap\n1 LJ\n0.667 LW\nN
'));
391 % This is more accurate but *MUCH* slower (issue #52)
393 % Modify all thin lines in the figure to have 10x LineWidths
394 hLines = findall(fig,'Type
','line
');
396 for lineIdx = 1 : numel(hLines)
397 thisLine = hLines(lineIdx);
398 if thisLine.LineWidth < 0.75 && strcmpi(thisLine.Visible,'on
')
399 hThinLines(end+1) = thisLine; %#ok<AGROW>
400 thisLine.LineWidth = thisLine.LineWidth * 10;
404 % If any thin lines were found
405 if ~isempty(hThinLines)
406 % Prepare an EPS with large-enough line widths
407 print(fig, options{:}, name);
408 % Restore the original LineWidths in the figure
409 for lineIdx = 1 : numel(hThinLines)
410 thisLine = handle(hThinLines(lineIdx));
411 thisLine.LineWidth = thisLine.LineWidth / 10;
414 % Compare the original and the new EPS files and correct the original stream's LineWidths
416 idx = 500; % skip heading with its possibly-different timestamp
417 markerStr = sprintf(
'10.0 ML\nN');
418 markerLen = length(markerStr);
419 while ~isempty(idx) && idx < length(fstrm)
420 lastIdx = min(length(fstrm), length(fstrm_new));
421 delta = fstrm(idx+1:lastIdx) - fstrm_new(idx+1:lastIdx);
422 idx = idx +
find(delta,1);
423 if ~isempty(idx) && ...
424 isequal(fstrm(idx-markerLen+1:idx), markerStr) && ...
425 ~isempty(regexp(fstrm_new(idx-markerLen+1:idx+12),
'10.0 ML\n[\d\.]+ LW\nN')) %#ok<RGXP1>
426 value = str2double(regexprep(fstrm_new(idx:idx+12),
' .*',
''));
427 if isnan(value),
break; end % something
's wrong... - bail out
428 newStr = sprintf('%0.3f LW\n
',value/10);
429 fstrm = [fstrm(1:idx-1) newStr fstrm(idx:end)];
438 % This is much faster although less accurate: fix all non-gray lines to have a LineWidth of 0.75 (=1 LW)
439 % Note: This will give incorrect LineWidth of 0.75 for lines having LineWidth<0.75, as well as for non-gray grid-lines (if present)
440 % However, in practice these edge-cases are very rare indeed, and the difference in LineWidth should not be noticeable
441 %fstrm = regexprep(fstrm, '([CR]C\n2 setlinecap\n1 LJ)\nN
', '$1\n1 LW\nN
');
442 % This is faster (the original regexprep could take many seconds when the axes contains many lines):
443 fstrm = strrep(fstrm, sprintf('\n2 setlinecap\n1 LJ\nN
'), sprintf('\n2 setlinecap\n1 LJ\n1 LW\nN
'));
446 fprintf(2, 'Error fixing LineWidths in EPS file: %s\n at %s:%d\n
', err.message, err.stack(1).file, err.stack(1).line);
449 % Reset the font and line colors
451 set(black_text_handles, 'Color
', [0 0 0]);
452 set(white_text_handles, 'Color
', [1 1 1]);
454 % Fix issue #159: redo findall() '*text_handles
'
455 black_text_handles = findall(fig, 'Type
', 'text
', 'Color
', [0 0 0]+eps);
456 white_text_handles = findall(fig, 'Type
', 'text
', 'Color
', [1 1 1]-eps);
457 set(black_text_handles, 'Color
', [0 0 0]);
458 set(white_text_handles, 'Color
', [1 1 1]);
460 set(white_line_handles, 'Color
', [1 1 1]);
462 % Preserve the figure's PaperSize in the output file,
if requested (issue #277)
465 paper_size = get(fig,
'PaperSize'); % in [points]
466 fstrm = sprintf(
'<< /PageSize [%d %d] >> setpagedevice\n%s', paper_size, fstrm);
470 set(fig,
'PaperPositionMode',old_pos_mode,
'PaperOrientation',old_orientation,
'PaperUnits',old_paper_units);
472 % Reset the font names in the figure
473 if ~isempty(font_swap)
475 set(font_handles(a),
'FontName', fonts{a},
'FontSize', fonts_size(a));
478 for a = 1:size(font_swap, 2)
479 fontName = font_swap{3,a};
480 %fontName = fontName(~isspace(font_swap{3,a}));
481 if length(fontName) > 29
482 warning(
'YMA:export_fig:font_name',
'Font name ''%s'' is longer than 29 characters. This might cause problems in some EPS/PDF readers. Consider using a different font.',fontName);
484 if isempty(font_space)
485 fontName(fontName==
' ') =
'';
487 fontName(fontName==
' ') = char(font_space);
490 % Replace all instances of the standard Matlab fonts with the original user
's font names
491 %fstrm = regexprep(fstrm, [font_swap{1,a} '-?[a-zA-Z]*\>
'], fontName);
492 %fstrm = regexprep(fstrm, [font_swap{2,a} '([ \n])
'], [fontName '$1
']);
493 %fstrm = regexprep(fstrm, font_swap{2,a}, fontName); % also replace -Bold, -Italic, -BoldItalic
495 % Times-Roman's Bold/Italic fontnames don
't include '-Roman
'
496 fstrm = regexprep(fstrm, [font_swap{2,a} '(\-Roman)?
'], fontName);
500 % Move the bounding box to the top of the file (HG2 only), or fix the line styles (HG1 only)
502 % Move the bounding box to the top of the file (HG2 only)
503 [s, e] = regexp(fstrm, '%%BoundingBox: [^%]*%%
');
505 fstrm = fstrm([1:s(1)-1 s(2):e(2)-2 e(1)-1:s(2)-1 e(2)-1:end]);
508 % Fix the line styles (HG1 only)
509 fstrm = fix_lines(fstrm);
512 % Apply the bounding box padding & cropping, replacing Matlab's print()
's bounding box
514 % Calculate a new bounding box based on a bitmap print using crop_border.m
515 % 1. Determine the Matlab BoundingBox and PageBoundingBox
516 [s,e] = regexp(fstrm, '%%BoundingBox: [^%]*%%
'); % location BB in eps file
517 if numel(s)==2, s=s(2); e=e(2); end
518 aa = fstrm(s+15:e-3); % dimensions bb - STEP1
519 bb_matlab = cell2mat(textscan(aa,'%f32%f32%f32%f32
')); % dimensions bb - STEP2
521 [s,e] = regexp(fstrm, '%%PageBoundingBox: [^%]*%%
'); % location bb in eps file
522 if numel(s)==2, s=s(2); e=e(2); end
523 aa = fstrm(s+19:e-3); % dimensions bb - STEP1
524 pagebb_matlab = cell2mat(textscan(aa,'%f32%f32%f32%f32
')); % dimensions bb - STEP2
526 % 1b. Fix issue #239: black title meshes with temporary black background figure bgcolor, causing bad cropping
528 if isequal(get(fig,'Color
'),'none
')
529 hAxes = findall(fig,'type
','axes
');
530 for idx = 1 : numel(hAxes)
534 oldColor = hTitle.Color;
535 if all(oldColor < 5*eps) || (ischar(oldColor) && lower(oldColor(1))=='k
')
536 hTitles(end+1) = hTitle; %#ok<AGROW>
537 hTitle.Color = [0,0,.01];
544 % 2. Create a bitmap image and use crop_borders to create the relative
545 % bb with respect to the PageBoundingBox
546 drawnow; pause(0.05); % avoid unintended cropping (issue #318)
547 [A, bcol] = print2array(fig, 1, renderer);
548 [aa, aa, aa, bb_rel] = crop_borders(A, bcol, bb_padding, crop_amounts); %#ok<ASGLU>
549 if any(bb_rel>1) || any(bb_rel<=0) || bb_rel(2)>0.15 % invalid cropping - retry after prolonged pause
550 pause(0.15); % avoid unintended cropping (issues #350, #351)
551 [A, bcol] = print2array(fig, 1, renderer);
552 [aa, aa, aa, bb_rel] = crop_borders(A, bcol, bb_padding, crop_amounts); %#ok<ASGLU>
554 bb_rel(bb_rel>1) = 1; % ignore invalid values
555 bb_rel(bb_rel<0) = 1; % ignore invalid values (fix issue #356)
557 try set(hTitles,'Color
','k
'); catch, end
559 % 3. Calculate the new Bounding Box
560 pagew = pagebb_matlab(3)-pagebb_matlab(1);
561 pageh = pagebb_matlab(4)-pagebb_matlab(2);
562 %bb_new = [pagebb_matlab(1)+pagew*bb_rel(1) pagebb_matlab(2)+pageh*bb_rel(2) ...
563 % pagebb_matlab(1)+pagew*bb_rel(3) pagebb_matlab(2)+pageh*bb_rel(4)];
564 bb_new = pagebb_matlab([1,2,1,2]) + [pagew,pageh,pagew,pageh].*bb_rel; % clearer
565 bb_offset = (bb_new-bb_matlab) + [-2,-2,2,2]; % 2px margin so that cropping is not TOO tight (issue #195)
567 % Apply the bounding box padding
570 bb_padding = round((mean([bb_new(3)-bb_new(1) bb_new(4)-bb_new(2)])*bb_padding)/0.5)*0.5; % ADJUST BB_PADDING
572 add_padding = @(n1, n2, n3, n4) sprintf(' %.0f
', str2double({n1, n2, n3, n4}) + bb_offset + bb_padding*[-1,-1,1,1]); %#ok<NASGU>
574 add_padding = @(n1, n2, n3, n4) sprintf(' %.0f
', str2double({n1, n2, n3, n4}) + bb_offset); %#ok<NASGU> % fix small but noticeable bounding box shift
576 fstrm = regexprep(fstrm, '%%BoundingBox:[ ]+([-]?\d+)[ ]+([-]?\d+)[ ]+([-]?\d+)[ ]+([-]?\d+)
', '%%BoundingBox:${add_padding($1, $2, $3, $4)}
');
579 % Fix issue #44: white artifact lines appearing in patch exports
580 % Note: the problem is due to the fact that Matlab's print() function exports patches
581 % as a combination of filled triangles, and a white line appears where the triangles
touch
582 % In the workaround below, we will modify such dual-triangles into a filled rectangle.
583 % We are careful to only modify regexps that exactly match specific patterns - it's better to not
584 % correct some white-line artifacts than to change the geometry of a patch, or to corrupt the EPS.
585 % e.g.: '0 -450 937 0 0 450 3 MP PP 937 0 0 -450 0 450 3 MP PP' => '0 -450 937 0 0 450 0 0 4 MP'
586 fstrm = regexprep(fstrm, '\n([-\d.]+ [-\d.]+) ([-\d.]+ [-\d.]+) ([-\d.]+ [-\d.]+) 3 MP\nPP\n\2 \1 \3 3 MP\nPP\n','\n$1 $2 $3 0 0 4 MP\nPP\n');
587 fstrm = regexprep(fstrm, '\n([-\d.]+ [-\d.]+) ([-\d.]+ [-\d.]+) ([-\d.]+ [-\d.]+) 3 MP\nPP\n\2 \3 \1 3 MP\nPP\n','\n$1 $2 $3 0 0 4 MP\nPP\n');
588 fstrm = regexprep(fstrm, '\n([-\d.]+ [-\d.]+) ([-\d.]+ [-\d.]+) ([-\d.]+ [-\d.]+) 3 MP\nPP\n\3 \1 \2 3 MP\nPP\n','\n$1 $2 $3 0 0 4 MP\nPP\n');
589 fstrm = regexprep(fstrm, '\n([-\d.]+ [-\d.]+) ([-\d.]+ [-\d.]+) ([-\d.]+ [-\d.]+) 3 MP\nPP\n\3 \2 \1 3 MP\nPP\n','\n$1 $2 $3 0 0 4 MP\nPP\n');
591 % If user requested a regexprep replacement of
string(s), do this now (issue
#324)
592 if isstruct(export_options) && isfield(export_options,
'regexprep') && ~isempty(export_options.regexprep) %issue #338
594 oldStrOrRegexp = export_options.regexprep{1};
595 newStrOrRegexp = export_options.regexprep{2};
596 fstrm = regexprep(fstrm, oldStrOrRegexp, newStrOrRegexp);
598 warning(
'YMA:export_fig:regexprep',
'Error parsing regexprep: %s', err.message);
602 % Write out the fixed eps file
605 drawnow; pause(0.01);
609 if nargin == 1 % in: convert transparency in Matlab figure into unique RGB colors
610 hObjs = findall(fig); %findobj(fig,
'Type',
'Area');
612 propNames = {
'Face',
'Edge'};
613 for objIdx = 1:length(hObjs)
614 hObj = hObjs(objIdx);
615 for propIdx = 1 : numel(propNames)
617 propName = propNames{propIdx};
618 if strcmp(hObj.(propName).ColorType,
'truecoloralpha')
619 oldColor = hObj.(propName).ColorData;
620 if numel(oldColor)>3 && oldColor(4)~=255 % issue #281: only fix patch/textbox color
if it
's not opaque
621 nColors = length(StoredColors);
622 newColor = uint8([101; 102+floor(nColors/255); mod(nColors,255); 255]);
623 StoredColors{end+1} = {hObj, propName, oldColor, newColor}; %#ok<AGROW>
624 hObj.(propName).ColorData = newColor;
628 % Never mind - ignore (either doesn't have the
property or cannot change it)
632 else % restore transparency in Matlab figure by converting back from the unique RGBs
633 %Find the transparent patches
635 nColors = length(StoredColors);
636 foundFlags =
false(1,nColors);
637 for objIdx = 1 : nColors
638 colorsData = StoredColors{objIdx};
639 hObj = colorsData{1};
640 propName = colorsData{2};
641 origColor = colorsData{3};
642 newColor = colorsData{4};
644 %Restore the EPS files patch color
645 colorID = num2str(round(
double(newColor(1:3)
') /255,3),'%.3g %.3g %.3g
'); %ID for searching
646 origRGB = num2str(round(double(origColor(1:3)')/255,3),
'%.3g %.3g %.3g'); %Replace with original color
647 origAlpha = num2str(round(
double(origColor(end)) /255,3),
'%.3g'); %Convert alpha value
for EPS
649 %Find and replace the RGBA values within the EPS text fstrm
650 %Note: .setopacityalpha is an unsupported PS extension that croaks in some GS versions (issue #285, https:
651 % (such cases are caught in
eps2pdf.m and corrected by adding the -dNOSAFER Ghosscript option or by removing the .setopacityalpha line)
652 if strcmpi(propName,
'Face')
653 oldStr = sprintf([
'\n' colorID
' RC\n']); % ...N\n (removed to fix issue #225)
654 newStr = sprintf([
'\n' origRGB
' RC\n' origAlpha
' .setopacityalpha true\n']); % ...N\n
656 oldStr = sprintf([
'\n' colorID
' RC\n']); % ...1 LJ\n (removed to fix issue #225)
657 newStr = sprintf([
'\n' origRGB
' RC\n' origAlpha
' .setopacityalpha true\n']);
659 foundFlags(objIdx) = ~isempty(strfind(fstrm, oldStr)); %#ok<STREMP>
660 fstrm = strrep(fstrm, oldStr, newStr);
662 %Restore the figure
object's original color
663 hObj.(propName).ColorData = origColor;
665 % something is wrong - cannot restore transparent color...
667 fprintf(2, 'Error maintaining transparency in EPS file: %s\n at %s:%d\n
', err.message, err.stack(1).file, err.stack(1).line);
function name(in vendor)
Return the MPI library name as used in naming the ParaMonte MATLAB shared library directories.
function list()
Return a list of MATLAB strings containing the names of OS platforms supported by the ParaMonte MATLA...
function eps2pdf(in source, in dest, in crop, in append, in gray, in quality, in gs_options)
function find(in vendor)
Return a list of scalar MATLAB strings containing the paths to all detected mpiexec binaries installe...
function info()
Return a MATLAB string containing the current system information.
function eps_maintainAlpha(in fig, in fstrm, in StoredColors)
function print2eps(in name, in fig, in export_options, in varargin)
function read_write_entire_textfile(in fname, in fstrm)
function touch()
Return the contents of the .bash_profile file in the system home folder as a scalar MATLAB string.