1 | function [imageData, alpha] = export_fig(varargin)
|
---|
2 | %EXPORT_FIG Exports figures in a publication-quality format
|
---|
3 | %
|
---|
4 | % Examples:
|
---|
5 | % imageData = export_fig
|
---|
6 | % [imageData, alpha] = export_fig
|
---|
7 | % export_fig filename
|
---|
8 | % export_fig filename -format1 -format2
|
---|
9 | % export_fig ... -nocrop
|
---|
10 | % export_fig ... -transparent
|
---|
11 | % export_fig ... -native
|
---|
12 | % export_fig ... -m<val>
|
---|
13 | % export_fig ... -r<val>
|
---|
14 | % export_fig ... -a<val>
|
---|
15 | % export_fig ... -q<val>
|
---|
16 | % export_fig ... -p<val>
|
---|
17 | % export_fig ... -d<gs_option>
|
---|
18 | % export_fig ... -depsc
|
---|
19 | % export_fig ... -<renderer>
|
---|
20 | % export_fig ... -<colorspace>
|
---|
21 | % export_fig ... -append
|
---|
22 | % export_fig ... -bookmark
|
---|
23 | % export_fig ... -clipboard
|
---|
24 | % export_fig ... -update
|
---|
25 | % export_fig ... -nofontswap
|
---|
26 | % export_fig(..., handle)
|
---|
27 | %
|
---|
28 | % This function saves a figure or single axes to one or more vector and/or
|
---|
29 | % bitmap file formats, and/or outputs a rasterized version to the workspace,
|
---|
30 | % with the following properties:
|
---|
31 | % - Figure/axes reproduced as it appears on screen
|
---|
32 | % - Cropped borders (optional)
|
---|
33 | % - Embedded fonts (vector formats)
|
---|
34 | % - Improved line and grid line styles
|
---|
35 | % - Anti-aliased graphics (bitmap formats)
|
---|
36 | % - Render images at native resolution (optional for bitmap formats)
|
---|
37 | % - Transparent background supported (pdf, eps, png)
|
---|
38 | % - Semi-transparent patch objects supported (png only)
|
---|
39 | % - RGB, CMYK or grayscale output (CMYK only with pdf, eps, tiff)
|
---|
40 | % - Variable image compression, including lossless (pdf, eps, jpg)
|
---|
41 | % - Optionally append to file (pdf, tiff)
|
---|
42 | % - Vector formats: pdf, eps
|
---|
43 | % - Bitmap formats: png, tiff, jpg, bmp, export to workspace
|
---|
44 | %
|
---|
45 | % This function is especially suited to exporting figures for use in
|
---|
46 | % publications and presentations, because of the high quality and
|
---|
47 | % portability of media produced.
|
---|
48 | %
|
---|
49 | % Note that the background color and figure dimensions are reproduced
|
---|
50 | % (the latter approximately, and ignoring cropping & magnification) in the
|
---|
51 | % output file. For transparent background (and semi-transparent patch
|
---|
52 | % objects), use the -transparent option or set the figure 'Color' property
|
---|
53 | % to 'none'. To make axes transparent set the axes 'Color' property to
|
---|
54 | % 'none'. PDF, EPS and PNG are the only formats that support a transparent
|
---|
55 | % background, while only PNG format supports transparency of patch objects.
|
---|
56 | %
|
---|
57 | % The choice of renderer (opengl, zbuffer or painters) has a large impact
|
---|
58 | % on the quality of output. The default value (opengl for bitmaps, painters
|
---|
59 | % for vector formats) generally gives good results, but if you aren't
|
---|
60 | % satisfied then try another renderer. Notes: 1) For vector formats (EPS,
|
---|
61 | % PDF), only painters generates vector graphics. 2) For bitmaps, only
|
---|
62 | % opengl can render transparent patch objects correctly. 3) For bitmaps,
|
---|
63 | % only painters will correctly scale line dash and dot lengths when
|
---|
64 | % magnifying or anti-aliasing. 4) Fonts may be substitued with Courier when
|
---|
65 | % using painters.
|
---|
66 | %
|
---|
67 | % When exporting to vector format (PDF & EPS) and bitmap format using the
|
---|
68 | % painters renderer, this function requires that ghostscript is installed
|
---|
69 | % on your system. You can download this from:
|
---|
70 | % http://www.ghostscript.com
|
---|
71 | % When exporting to eps it additionally requires pdftops, from the Xpdf
|
---|
72 | % suite of functions. You can download this from:
|
---|
73 | % http://www.foolabs.com/xpdf
|
---|
74 | %
|
---|
75 | % Inputs:
|
---|
76 | % filename - string containing the name (optionally including full or
|
---|
77 | % relative path) of the file the figure is to be saved as. If
|
---|
78 | % a path is not specified, the figure is saved in the current
|
---|
79 | % directory. If no name and no output arguments are specified,
|
---|
80 | % the default name, 'export_fig_out', is used. If neither a
|
---|
81 | % file extension nor a format are specified, a ".png" is added
|
---|
82 | % and the figure saved in that format.
|
---|
83 | % -format1, -format2, etc. - strings containing the extensions of the
|
---|
84 | % file formats the figure is to be saved as.
|
---|
85 | % Valid options are: '-pdf', '-eps', '-png',
|
---|
86 | % '-tif', '-jpg' and '-bmp'. All combinations
|
---|
87 | % of formats are valid.
|
---|
88 | % -nocrop - option indicating that the borders of the output are not to
|
---|
89 | % be cropped.
|
---|
90 | % -transparent - option indicating that the figure background is to be
|
---|
91 | % made transparent (png, pdf and eps output only).
|
---|
92 | % -m<val> - option where val indicates the factor to magnify the
|
---|
93 | % on-screen figure pixel dimensions by when generating bitmap
|
---|
94 | % outputs (does not affect vector formats). Default: '-m1'.
|
---|
95 | % -r<val> - option val indicates the resolution (in pixels per inch) to
|
---|
96 | % export bitmap and vector outputs at, keeping the dimensions
|
---|
97 | % of the on-screen figure. Default: '-r864' (for vector output
|
---|
98 | % only). Note that the -m option overides the -r option for
|
---|
99 | % bitmap outputs only.
|
---|
100 | % -native - option indicating that the output resolution (when outputting
|
---|
101 | % a bitmap format) should be such that the vertical resolution
|
---|
102 | % of the first suitable image found in the figure is at the
|
---|
103 | % native resolution of that image. To specify a particular
|
---|
104 | % image to use, give it the tag 'export_fig_native'. Notes:
|
---|
105 | % This overrides any value set with the -m and -r options. It
|
---|
106 | % also assumes that the image is displayed front-to-parallel
|
---|
107 | % with the screen. The output resolution is approximate and
|
---|
108 | % should not be relied upon. Anti-aliasing can have adverse
|
---|
109 | % effects on image quality (disable with the -a1 option).
|
---|
110 | % -a1, -a2, -a3, -a4 - option indicating the amount of anti-aliasing to
|
---|
111 | % use for bitmap outputs. '-a1' means no anti-
|
---|
112 | % aliasing; '-a4' is the maximum amount (default).
|
---|
113 | % -<renderer> - option to force a particular renderer (painters, opengl or
|
---|
114 | % zbuffer). Default value: opengl for bitmap formats or
|
---|
115 | % figures with patches and/or transparent annotations;
|
---|
116 | % painters for vector formats without patches/transparencies.
|
---|
117 | % -<colorspace> - option indicating which colorspace color figures should
|
---|
118 | % be saved in: RGB (default), CMYK or gray. CMYK is only
|
---|
119 | % supported in pdf, eps and tiff output.
|
---|
120 | % -q<val> - option to vary bitmap image quality (in pdf, eps and jpg
|
---|
121 | % files only). Larger val, in the range 0-100, gives higher
|
---|
122 | % quality/lower compression. val > 100 gives lossless
|
---|
123 | % compression. Default: '-q95' for jpg, ghostscript prepress
|
---|
124 | % default for pdf & eps. Note: lossless compression can
|
---|
125 | % sometimes give a smaller file size than the default lossy
|
---|
126 | % compression, depending on the type of images.
|
---|
127 | % -p<val> - option to pad a border of width val to exported files, where
|
---|
128 | % val is either a relative size with respect to cropped image
|
---|
129 | % size (i.e. p=0.01 adds a 1% border). For EPS & PDF formats,
|
---|
130 | % val can also be integer in units of 1/72" points (abs(val)>1).
|
---|
131 | % val can be positive (padding) or negative (extra cropping).
|
---|
132 | % If used, the -nocrop flag will be ignored, i.e. the image will
|
---|
133 | % always be cropped and then padded. Default: 0 (i.e. no padding).
|
---|
134 | % -append - option indicating that if the file (pdfs only) already
|
---|
135 | % exists, the figure is to be appended as a new page, instead
|
---|
136 | % of being overwritten (default).
|
---|
137 | % -bookmark - option to indicate that a bookmark with the name of the
|
---|
138 | % figure is to be created in the output file (pdf only).
|
---|
139 | % -clipboard - option to save output as an image on the system clipboard.
|
---|
140 | % Note: background transparency is not preserved in clipboard
|
---|
141 | % -d<gs_option> - option to indicate a ghostscript setting. For example,
|
---|
142 | % -dMaxBitmap=0 or -dNoOutputFonts (Ghostscript 9.15+).
|
---|
143 | % -depsc - option to use EPS level-3 rather than the default level-2 print
|
---|
144 | % device. This solves some bugs with Matlab's default -depsc2 device
|
---|
145 | % such as discolored subplot lines on images (vector formats only).
|
---|
146 | % -update - option to download and install the latest version of export_fig
|
---|
147 | % -nofontswap - option to avoid font swapping. Font swapping is automatically
|
---|
148 | % done in vector formats (only): 11 standard Matlab fonts are
|
---|
149 | % replaced by the original figure fonts. This option prevents this.
|
---|
150 | % handle - The handle of the figure, axes or uipanels (can be an array of
|
---|
151 | % handles, but the objects must be in the same figure) to be
|
---|
152 | % saved. Default: gcf.
|
---|
153 | %
|
---|
154 | % Outputs:
|
---|
155 | % imageData - MxNxC uint8 image array of the exported image.
|
---|
156 | % alpha - MxN single array of alphamatte values in the range [0,1],
|
---|
157 | % for the case when the background is transparent.
|
---|
158 | %
|
---|
159 | % Some helpful examples and tips can be found at:
|
---|
160 | % https://github.com/altmany/export_fig
|
---|
161 | %
|
---|
162 | % See also PRINT, SAVEAS, ScreenCapture (on the Matlab File Exchange)
|
---|
163 |
|
---|
164 | %{
|
---|
165 | % Copyright (C) Oliver Woodford 2008-2014, Yair Altman 2015-
|
---|
166 |
|
---|
167 | % The idea of using ghostscript is inspired by Peder Axensten's SAVEFIG
|
---|
168 | % (fex id: 10889) which is itself inspired by EPS2PDF (fex id: 5782).
|
---|
169 | % The idea for using pdftops came from the MATLAB newsgroup (id: 168171).
|
---|
170 | % The idea of editing the EPS file to change line styles comes from Jiro
|
---|
171 | % Doke's FIXPSLINESTYLE (fex id: 17928).
|
---|
172 | % The idea of changing dash length with line width came from comments on
|
---|
173 | % fex id: 5743, but the implementation is mine :)
|
---|
174 | % The idea of anti-aliasing bitmaps came from Anders Brun's MYAA (fex id:
|
---|
175 | % 20979).
|
---|
176 | % The idea of appending figures in pdfs came from Matt C in comments on the
|
---|
177 | % FEX (id: 23629)
|
---|
178 |
|
---|
179 | % Thanks to Roland Martin for pointing out the colour MATLAB
|
---|
180 | % bug/feature with colorbar axes and transparent backgrounds.
|
---|
181 | % Thanks also to Andrew Matthews for describing a bug to do with the figure
|
---|
182 | % size changing in -nodisplay mode. I couldn't reproduce it, but included a
|
---|
183 | % fix anyway.
|
---|
184 | % Thanks to Tammy Threadgill for reporting a bug where an axes is not
|
---|
185 | % isolated from gui objects.
|
---|
186 | %}
|
---|
187 | %{
|
---|
188 | % 23/02/12: Ensure that axes limits don't change during printing
|
---|
189 | % 14/03/12: Fix bug in fixing the axes limits (thanks to Tobias Lamour for reporting it).
|
---|
190 | % 02/05/12: Incorporate patch of Petr Nechaev (many thanks), enabling bookmarking of figures in pdf files.
|
---|
191 | % 09/05/12: Incorporate patch of Arcelia Arrieta (many thanks), to keep tick marks fixed.
|
---|
192 | % 12/12/12: Add support for isolating uipanels. Thanks to michael for suggesting it.
|
---|
193 | % 25/09/13: Add support for changing resolution in vector formats. Thanks to Jan Jaap Meijer for suggesting it.
|
---|
194 | % 07/05/14: Add support for '~' at start of path. Thanks to Sally Warner for suggesting it.
|
---|
195 | % 24/02/15: Fix Matlab R2014b bug (issue #34): plot markers are not displayed when ZLimMode='manual'
|
---|
196 | % 25/02/15: Fix issue #4 (using HG2 on R2014a and earlier)
|
---|
197 | % 25/02/15: Fix issue #21 (bold TeX axes labels/titles in R2014b)
|
---|
198 | % 26/02/15: If temp dir is not writable, use the user-specified folder for temporary EPS/PDF files (Javier Paredes)
|
---|
199 | % 27/02/15: Modified repository URL from github.com/ojwoodford to /altmany
|
---|
200 | % Indented main function
|
---|
201 | % Added top-level try-catch block to display useful workarounds
|
---|
202 | % 28/02/15: Enable users to specify optional ghostscript options (issue #36)
|
---|
203 | % 06/03/15: Improved image padding & cropping thanks to Oscar Hartogensis
|
---|
204 | % 26/03/15: Fixed issue #49 (bug with transparent grayscale images); fixed out-of-memory issue
|
---|
205 | % 26/03/15: Fixed issue #42: non-normalized annotations on HG1
|
---|
206 | % 26/03/15: Fixed issue #46: Ghostscript crash if figure units <> pixels
|
---|
207 | % 27/03/15: Fixed issue #39: bad export of transparent annotations/patches
|
---|
208 | % 28/03/15: Fixed issue #50: error on some Matlab versions with the fix for issue #42
|
---|
209 | % 29/03/15: Fixed issue #33: bugs in Matlab's print() function with -cmyk
|
---|
210 | % 29/03/15: Improved processing of input args (accept space between param name & value, related to issue #51)
|
---|
211 | % 30/03/15: When exporting *.fig files, then saveas *.fig if figure is open, otherwise export the specified fig file
|
---|
212 | % 30/03/15: Fixed edge case bug introduced yesterday (commit #ae1755bd2e11dc4e99b95a7681f6e211b3fa9358)
|
---|
213 | % 09/04/15: Consolidated header comment sections; initialize output vars only if requested (nargout>0)
|
---|
214 | % 14/04/15: Workaround for issue #45: lines in image subplots are exported in invalid color
|
---|
215 | % 15/04/15: Fixed edge-case in parsing input parameters; fixed help section to show the -depsc option (issue #45)
|
---|
216 | % 21/04/15: Bug fix: Ghostscript croaks on % chars in output PDF file (reported by Sven on FEX page, 15-Jul-2014)
|
---|
217 | % 22/04/15: Bug fix: Pdftops croaks on relative paths (reported by Tintin Milou on FEX page, 19-Jan-2015)
|
---|
218 | % 04/05/15: Merged fix #63 (Kevin Mattheus Moerman): prevent tick-label changes during export
|
---|
219 | % 07/05/15: Partial fix for issue #65: PDF export used painters rather than opengl renderer (thanks Nguyenr)
|
---|
220 | % 08/05/15: Fixed issue #65: bad PDF append since commit #e9f3cdf 21/04/15 (thanks Robert Nguyen)
|
---|
221 | % 12/05/15: Fixed issue #67: exponent labels cropped in export, since fix #63 (04/05/15)
|
---|
222 | % 28/05/15: Fixed issue #69: set non-bold label font only if the string contains symbols (\beta etc.), followup to issue #21
|
---|
223 | % 29/05/15: Added informative error message in case user requested SVG output (issue #72)
|
---|
224 | % 09/06/15: Fixed issue #58: -transparent removed anti-aliasing when exporting to PNG
|
---|
225 | % 19/06/15: Added -update option to download and install the latest version of export_fig
|
---|
226 | % 07/07/15: Added -nofontswap option to avoid font-swapping in EPS/PDF
|
---|
227 | % 16/07/15: Fixed problem with anti-aliasing on old Matlab releases
|
---|
228 | % 11/09/15: Fixed issue #103: magnification must never become negative; also fixed reported error msg in parsing input params
|
---|
229 | %}
|
---|
230 |
|
---|
231 | if nargout
|
---|
232 | [imageData, alpha] = deal([]);
|
---|
233 | end
|
---|
234 | hadError = false;
|
---|
235 | displaySuggestedWorkarounds = true;
|
---|
236 |
|
---|
237 | % Ensure the figure is rendered correctly _now_ so that properties like axes limits are up-to-date
|
---|
238 | drawnow;
|
---|
239 | pause(0.05); % this solves timing issues with Java Swing's EDT (http://undocumentedmatlab.com/blog/solving-a-matlab-hang-problem)
|
---|
240 |
|
---|
241 | % Parse the input arguments
|
---|
242 | fig = get(0, 'CurrentFigure');
|
---|
243 | [fig, options] = parse_args(nargout, fig, varargin{:});
|
---|
244 |
|
---|
245 | % Ensure that we have a figure handle
|
---|
246 | if isequal(fig,-1)
|
---|
247 | return; % silent bail-out
|
---|
248 | elseif isempty(fig)
|
---|
249 | error('No figure found');
|
---|
250 | end
|
---|
251 |
|
---|
252 | % Isolate the subplot, if it is one
|
---|
253 | cls = all(ismember(get(fig, 'Type'), {'axes', 'uipanel'}));
|
---|
254 | if cls
|
---|
255 | % Given handles of one or more axes, so isolate them from the rest
|
---|
256 | fig = isolate_axes(fig);
|
---|
257 | else
|
---|
258 | % Check we have a figure
|
---|
259 | if ~isequal(get(fig, 'Type'), 'figure');
|
---|
260 | error('Handle must be that of a figure, axes or uipanel');
|
---|
261 | end
|
---|
262 | % Get the old InvertHardcopy mode
|
---|
263 | old_mode = get(fig, 'InvertHardcopy');
|
---|
264 | end
|
---|
265 |
|
---|
266 | % Hack the font units where necessary (due to a font rendering bug in print?).
|
---|
267 | % This may not work perfectly in all cases.
|
---|
268 | % Also it can change the figure layout if reverted, so use a copy.
|
---|
269 | magnify = options.magnify * options.aa_factor;
|
---|
270 | if isbitmap(options) && magnify ~= 1
|
---|
271 | fontu = findall(fig, 'FontUnits', 'normalized');
|
---|
272 | if ~isempty(fontu)
|
---|
273 | % Some normalized font units found
|
---|
274 | if ~cls
|
---|
275 | fig = copyfig(fig);
|
---|
276 | set(fig, 'Visible', 'off');
|
---|
277 | fontu = findall(fig, 'FontUnits', 'normalized');
|
---|
278 | cls = true;
|
---|
279 | end
|
---|
280 | set(fontu, 'FontUnits', 'points');
|
---|
281 | end
|
---|
282 | end
|
---|
283 |
|
---|
284 | try
|
---|
285 | % MATLAB "feature": axes limits and tick marks can change when printing
|
---|
286 | Hlims = findall(fig, 'Type', 'axes');
|
---|
287 | if ~cls
|
---|
288 | % Record the old axes limit and tick modes
|
---|
289 | Xlims = make_cell(get(Hlims, 'XLimMode'));
|
---|
290 | Ylims = make_cell(get(Hlims, 'YLimMode'));
|
---|
291 | Zlims = make_cell(get(Hlims, 'ZLimMode'));
|
---|
292 | Xtick = make_cell(get(Hlims, 'XTickMode'));
|
---|
293 | Ytick = make_cell(get(Hlims, 'YTickMode'));
|
---|
294 | Ztick = make_cell(get(Hlims, 'ZTickMode'));
|
---|
295 | Xlabel = make_cell(get(Hlims, 'XTickLabelMode'));
|
---|
296 | Ylabel = make_cell(get(Hlims, 'YTickLabelMode'));
|
---|
297 | Zlabel = make_cell(get(Hlims, 'ZTickLabelMode'));
|
---|
298 | end
|
---|
299 |
|
---|
300 | % Set all axes limit and tick modes to manual, so the limits and ticks can't change
|
---|
301 | % Fix Matlab R2014b bug (issue #34): plot markers are not displayed when ZLimMode='manual'
|
---|
302 | set(Hlims, 'XLimMode', 'manual', 'YLimMode', 'manual');
|
---|
303 | set_tick_mode(Hlims, 'X');
|
---|
304 | set_tick_mode(Hlims, 'Y');
|
---|
305 | if ~using_hg2(fig)
|
---|
306 | set(Hlims,'ZLimMode', 'manual');
|
---|
307 | set_tick_mode(Hlims, 'Z');
|
---|
308 | end
|
---|
309 | catch
|
---|
310 | % ignore - fix issue #4 (using HG2 on R2014a and earlier)
|
---|
311 | end
|
---|
312 |
|
---|
313 | % Fix issue #21 (bold TeX axes labels/titles in R2014b when exporting to EPS/PDF)
|
---|
314 | try
|
---|
315 | if using_hg2(fig) && isvector(options)
|
---|
316 | % Set the FontWeight of axes labels/titles to 'normal'
|
---|
317 | % Fix issue #69: set non-bold font only if the string contains symbols (\beta etc.)
|
---|
318 | texLabels = findall(fig, 'type','text', 'FontWeight','bold');
|
---|
319 | symbolIdx = ~cellfun('isempty',strfind({texLabels.String},'\'));
|
---|
320 | set(texLabels(symbolIdx), 'FontWeight','normal');
|
---|
321 | end
|
---|
322 | catch
|
---|
323 | % ignore
|
---|
324 | end
|
---|
325 |
|
---|
326 | % Fix issue #42: non-normalized annotations on HG1 (internal Matlab bug)
|
---|
327 | annotationHandles = [];
|
---|
328 | try
|
---|
329 | if ~using_hg2(fig)
|
---|
330 | annotationHandles = findall(fig,'Type','hggroup','-and','-property','Units','-and','-not','Units','norm');
|
---|
331 | originalUnits = get(annotationHandles,'Units');
|
---|
332 | set(annotationHandles,'Units','norm');
|
---|
333 | end
|
---|
334 | catch
|
---|
335 | % should never happen, but ignore in any case - issue #50
|
---|
336 | end
|
---|
337 |
|
---|
338 | % Fix issue #46: Ghostscript crash if figure units <> pixels
|
---|
339 | oldFigUnits = get(fig,'Units');
|
---|
340 | set(fig,'Units','pixels');
|
---|
341 |
|
---|
342 | % Set to print exactly what is there
|
---|
343 | set(fig, 'InvertHardcopy', 'off');
|
---|
344 | % Set the renderer
|
---|
345 | switch options.renderer
|
---|
346 | case 1
|
---|
347 | renderer = '-opengl';
|
---|
348 | case 2
|
---|
349 | renderer = '-zbuffer';
|
---|
350 | case 3
|
---|
351 | renderer = '-painters';
|
---|
352 | otherwise
|
---|
353 | renderer = '-opengl'; % Default for bitmaps
|
---|
354 | end
|
---|
355 |
|
---|
356 | try
|
---|
357 | % Do the bitmap formats first
|
---|
358 | if isbitmap(options)
|
---|
359 | if abs(options.bb_padding) > 1
|
---|
360 | displaySuggestedWorkarounds = false;
|
---|
361 | error('For bitmap output (png,jpg,tif,bmp) the padding value (-p) must be between -1<p<1')
|
---|
362 | end
|
---|
363 | % Get the background colour
|
---|
364 | if options.transparent && (options.png || options.alpha)
|
---|
365 | % Get out an alpha channel
|
---|
366 | % MATLAB "feature": black colorbar axes can change to white and vice versa!
|
---|
367 | hCB = findall(fig, 'Type','axes', 'Tag','Colorbar');
|
---|
368 | if isempty(hCB)
|
---|
369 | yCol = [];
|
---|
370 | xCol = [];
|
---|
371 | else
|
---|
372 | yCol = get(hCB, 'YColor');
|
---|
373 | xCol = get(hCB, 'XColor');
|
---|
374 | if iscell(yCol)
|
---|
375 | yCol = cell2mat(yCol);
|
---|
376 | xCol = cell2mat(xCol);
|
---|
377 | end
|
---|
378 | yCol = sum(yCol, 2);
|
---|
379 | xCol = sum(xCol, 2);
|
---|
380 | end
|
---|
381 | % MATLAB "feature": apparently figure size can change when changing
|
---|
382 | % colour in -nodisplay mode
|
---|
383 | pos = get(fig, 'Position');
|
---|
384 | % Set the background colour to black, and set size in case it was
|
---|
385 | % changed internally
|
---|
386 | tcol = get(fig, 'Color');
|
---|
387 | set(fig, 'Color', 'k', 'Position', pos);
|
---|
388 | % Correct the colorbar axes colours
|
---|
389 | set(hCB(yCol==0), 'YColor', [0 0 0]);
|
---|
390 | set(hCB(xCol==0), 'XColor', [0 0 0]);
|
---|
391 |
|
---|
392 | % The following code might cause out-of-memory errors
|
---|
393 | try
|
---|
394 | % Print large version to array
|
---|
395 | B = print2array(fig, magnify, renderer);
|
---|
396 | % Downscale the image
|
---|
397 | B = downsize(single(B), options.aa_factor);
|
---|
398 | catch
|
---|
399 | % This is more conservative in memory, but kills transparency (issue #58)
|
---|
400 | B = single(print2array(fig, magnify/options.aa_factor, renderer));
|
---|
401 | end
|
---|
402 |
|
---|
403 | % Set background to white (and set size)
|
---|
404 | set(fig, 'Color', 'w', 'Position', pos);
|
---|
405 | % Correct the colorbar axes colours
|
---|
406 | set(hCB(yCol==3), 'YColor', [1 1 1]);
|
---|
407 | set(hCB(xCol==3), 'XColor', [1 1 1]);
|
---|
408 |
|
---|
409 | % The following code might cause out-of-memory errors
|
---|
410 | try
|
---|
411 | % Print large version to array
|
---|
412 | A = print2array(fig, magnify, renderer);
|
---|
413 | % Downscale the image
|
---|
414 | A = downsize(single(A), options.aa_factor);
|
---|
415 | catch
|
---|
416 | % This is more conservative in memory, but kills transparency (issue #58)
|
---|
417 | A = single(print2array(fig, magnify/options.aa_factor, renderer));
|
---|
418 | end
|
---|
419 |
|
---|
420 | % Set the background colour (and size) back to normal
|
---|
421 | set(fig, 'Color', tcol, 'Position', pos);
|
---|
422 | % Compute the alpha map
|
---|
423 | alpha = round(sum(B - A, 3)) / (255 * 3) + 1;
|
---|
424 | A = alpha;
|
---|
425 | A(A==0) = 1;
|
---|
426 | A = B ./ A(:,:,[1 1 1]);
|
---|
427 | clear B
|
---|
428 | % Convert to greyscale
|
---|
429 | if options.colourspace == 2
|
---|
430 | A = rgb2grey(A);
|
---|
431 | end
|
---|
432 | A = uint8(A);
|
---|
433 | % Crop the background
|
---|
434 | if options.crop
|
---|
435 | %[alpha, v] = crop_borders(alpha, 0, 1);
|
---|
436 | %A = A(v(1):v(2),v(3):v(4),:);
|
---|
437 | [alpha, vA, vB] = crop_borders(alpha, 0, options.bb_padding);
|
---|
438 | if ~any(isnan(vB)) % positive padding
|
---|
439 | B = repmat(uint8(zeros(1,1,size(A,3))),size(alpha));
|
---|
440 | B(vB(1):vB(2), vB(3):vB(4), :) = A(vA(1):vA(2), vA(3):vA(4), :); % ADDED BY OH
|
---|
441 | A = B;
|
---|
442 | else % negative padding
|
---|
443 | A = A(vA(1):vA(2), vA(3):vA(4), :);
|
---|
444 | end
|
---|
445 | end
|
---|
446 | if options.png
|
---|
447 | % Compute the resolution
|
---|
448 | res = options.magnify * get(0, 'ScreenPixelsPerInch') / 25.4e-3;
|
---|
449 | % Save the png
|
---|
450 | imwrite(A, [options.name '.png'], 'Alpha', double(alpha), 'ResolutionUnit', 'meter', 'XResolution', res, 'YResolution', res);
|
---|
451 | % Clear the png bit
|
---|
452 | options.png = false;
|
---|
453 | end
|
---|
454 | % Return only one channel for greyscale
|
---|
455 | if isbitmap(options)
|
---|
456 | A = check_greyscale(A);
|
---|
457 | end
|
---|
458 | if options.alpha
|
---|
459 | % Store the image
|
---|
460 | imageData = A;
|
---|
461 | % Clear the alpha bit
|
---|
462 | options.alpha = false;
|
---|
463 | end
|
---|
464 | % Get the non-alpha image
|
---|
465 | if isbitmap(options)
|
---|
466 | alph = alpha(:,:,ones(1, size(A, 3)));
|
---|
467 | A = uint8(single(A) .* alph + 255 * (1 - alph));
|
---|
468 | clear alph
|
---|
469 | end
|
---|
470 | if options.im
|
---|
471 | % Store the new image
|
---|
472 | imageData = A;
|
---|
473 | end
|
---|
474 | else
|
---|
475 | % Print large version to array
|
---|
476 | if options.transparent
|
---|
477 | % MATLAB "feature": apparently figure size can change when changing
|
---|
478 | % colour in -nodisplay mode
|
---|
479 | pos = get(fig, 'Position');
|
---|
480 | tcol = get(fig, 'Color');
|
---|
481 | set(fig, 'Color', 'w', 'Position', pos);
|
---|
482 | A = print2array(fig, magnify, renderer);
|
---|
483 | set(fig, 'Color', tcol, 'Position', pos);
|
---|
484 | tcol = 255;
|
---|
485 | else
|
---|
486 | [A, tcol] = print2array(fig, magnify, renderer);
|
---|
487 | end
|
---|
488 | % Crop the background
|
---|
489 | if options.crop
|
---|
490 | A = crop_borders(A, tcol, options.bb_padding);
|
---|
491 | end
|
---|
492 | % Downscale the image
|
---|
493 | A = downsize(A, options.aa_factor);
|
---|
494 | if options.colourspace == 2
|
---|
495 | % Convert to greyscale
|
---|
496 | A = rgb2grey(A);
|
---|
497 | else
|
---|
498 | % Return only one channel for greyscale
|
---|
499 | A = check_greyscale(A);
|
---|
500 | end
|
---|
501 | % Outputs
|
---|
502 | if options.im
|
---|
503 | imageData = A;
|
---|
504 | end
|
---|
505 | if options.alpha
|
---|
506 | imageData = A;
|
---|
507 | alpha = zeros(size(A, 1), size(A, 2), 'single');
|
---|
508 | end
|
---|
509 | end
|
---|
510 | % Save the images
|
---|
511 | if options.png
|
---|
512 | res = options.magnify * get(0, 'ScreenPixelsPerInch') / 25.4e-3;
|
---|
513 | imwrite(A, [options.name '.png'], 'ResolutionUnit', 'meter', 'XResolution', res, 'YResolution', res);
|
---|
514 | end
|
---|
515 | if options.bmp
|
---|
516 | imwrite(A, [options.name '.bmp']);
|
---|
517 | end
|
---|
518 | % Save jpeg with given quality
|
---|
519 | if options.jpg
|
---|
520 | quality = options.quality;
|
---|
521 | if isempty(quality)
|
---|
522 | quality = 95;
|
---|
523 | end
|
---|
524 | if quality > 100
|
---|
525 | imwrite(A, [options.name '.jpg'], 'Mode', 'lossless');
|
---|
526 | else
|
---|
527 | imwrite(A, [options.name '.jpg'], 'Quality', quality);
|
---|
528 | end
|
---|
529 | end
|
---|
530 | % Save tif images in cmyk if wanted (and possible)
|
---|
531 | if options.tif
|
---|
532 | if options.colourspace == 1 && size(A, 3) == 3
|
---|
533 | A = double(255 - A);
|
---|
534 | K = min(A, [], 3);
|
---|
535 | K_ = 255 ./ max(255 - K, 1);
|
---|
536 | C = (A(:,:,1) - K) .* K_;
|
---|
537 | M = (A(:,:,2) - K) .* K_;
|
---|
538 | Y = (A(:,:,3) - K) .* K_;
|
---|
539 | A = uint8(cat(3, C, M, Y, K));
|
---|
540 | clear C M Y K K_
|
---|
541 | end
|
---|
542 | append_mode = {'overwrite', 'append'};
|
---|
543 | imwrite(A, [options.name '.tif'], 'Resolution', options.magnify*get(0, 'ScreenPixelsPerInch'), 'WriteMode', append_mode{options.append+1});
|
---|
544 | end
|
---|
545 | end
|
---|
546 |
|
---|
547 | % Now do the vector formats
|
---|
548 | if isvector(options)
|
---|
549 | % Set the default renderer to painters
|
---|
550 | if ~options.renderer
|
---|
551 | if isempty(findall(fig,'-property','FaceAlpha','-and','-not','FaceAlpha',1)) && ...
|
---|
552 | isempty(findall(fig,'type','patch'))
|
---|
553 | renderer = '-painters';
|
---|
554 | else
|
---|
555 | % This is *MUCH* slower, but more accurate for patches and transparent annotations (issue #39)
|
---|
556 | renderer = '-opengl';
|
---|
557 | end
|
---|
558 | end
|
---|
559 | % Generate some filenames
|
---|
560 | tmp_nam = [tempname '.eps'];
|
---|
561 | try
|
---|
562 | % Ensure that the temp dir is writable (Javier Paredes 30/1/15)
|
---|
563 | fid = fopen(tmp_nam,'w');
|
---|
564 | fwrite(fid,1);
|
---|
565 | fclose(fid);
|
---|
566 | delete(tmp_nam);
|
---|
567 | isTempDirOk = true;
|
---|
568 | catch
|
---|
569 | % Temp dir is not writable, so use the user-specified folder
|
---|
570 | [dummy,fname,fext] = fileparts(tmp_nam); %#ok<ASGLU>
|
---|
571 | fpath = fileparts(options.name);
|
---|
572 | tmp_nam = fullfile(fpath,[fname fext]);
|
---|
573 | isTempDirOk = false;
|
---|
574 | end
|
---|
575 | if isTempDirOk
|
---|
576 | pdf_nam_tmp = [tempname '.pdf'];
|
---|
577 | else
|
---|
578 | pdf_nam_tmp = fullfile(fpath,[fname '.pdf']);
|
---|
579 | end
|
---|
580 | if options.pdf
|
---|
581 | pdf_nam = [options.name '.pdf'];
|
---|
582 | try copyfile(pdf_nam, pdf_nam_tmp, 'f'); catch, end % fix for issue #65
|
---|
583 | else
|
---|
584 | pdf_nam = pdf_nam_tmp;
|
---|
585 | end
|
---|
586 | % Generate the options for print
|
---|
587 | p2eArgs = {renderer, sprintf('-r%d', options.resolution)};
|
---|
588 | if options.colourspace == 1 % CMYK
|
---|
589 | % Issue #33: due to internal bugs in Matlab's print() function, we can't use its -cmyk option
|
---|
590 | %p2eArgs{end+1} = '-cmyk';
|
---|
591 | end
|
---|
592 | if ~options.crop
|
---|
593 | % Issue #56: due to internal bugs in Matlab's print() function, we can't use its internal cropping mechanism,
|
---|
594 | % therefore we always use '-loose' (in print2eps.m) and do our own cropping (in crop_borders)
|
---|
595 | %p2eArgs{end+1} = '-loose';
|
---|
596 | end
|
---|
597 | if any(strcmpi(varargin,'-depsc'))
|
---|
598 | % Issue #45: lines in image subplots are exported in invalid color.
|
---|
599 | % The workaround is to use the -depsc parameter instead of the default -depsc2
|
---|
600 | p2eArgs{end+1} = '-depsc';
|
---|
601 | end
|
---|
602 | try
|
---|
603 | % Generate an eps
|
---|
604 | print2eps(tmp_nam, fig, [options.bb_padding, options.crop, options.fontswap], p2eArgs{:});
|
---|
605 | % Remove the background, if desired
|
---|
606 | if options.transparent && ~isequal(get(fig, 'Color'), 'none')
|
---|
607 | eps_remove_background(tmp_nam, 1 + using_hg2(fig));
|
---|
608 | end
|
---|
609 | % Fix colorspace to CMYK, if requested (workaround for issue #33)
|
---|
610 | if options.colourspace == 1 % CMYK
|
---|
611 | % Issue #33: due to internal bugs in Matlab's print() function, we can't use its -cmyk option
|
---|
612 | change_rgb_to_cmyk(tmp_nam);
|
---|
613 | end
|
---|
614 | % Add a bookmark to the PDF if desired
|
---|
615 | if options.bookmark
|
---|
616 | fig_nam = get(fig, 'Name');
|
---|
617 | if isempty(fig_nam)
|
---|
618 | warning('export_fig:EmptyBookmark', 'Bookmark requested for figure with no name. Bookmark will be empty.');
|
---|
619 | end
|
---|
620 | add_bookmark(tmp_nam, fig_nam);
|
---|
621 | end
|
---|
622 | % Generate a pdf
|
---|
623 | eps2pdf(tmp_nam, pdf_nam_tmp, 1, options.append, options.colourspace==2, options.quality, options.gs_options);
|
---|
624 | % Ghostscript croaks on % chars in the output PDF file, so use tempname and then rename the file
|
---|
625 | try movefile(pdf_nam_tmp, pdf_nam, 'f'); catch, end
|
---|
626 | catch ex
|
---|
627 | % Delete the eps
|
---|
628 | delete(tmp_nam);
|
---|
629 | rethrow(ex);
|
---|
630 | end
|
---|
631 | % Delete the eps
|
---|
632 | delete(tmp_nam);
|
---|
633 | if options.eps
|
---|
634 | try
|
---|
635 | % Generate an eps from the pdf
|
---|
636 | % since pdftops can't handle relative paths (e.g., '..\'), use a temp file
|
---|
637 | eps_nam_tmp = strrep(pdf_nam_tmp,'.pdf','.eps');
|
---|
638 | pdf2eps(pdf_nam, eps_nam_tmp);
|
---|
639 | movefile(eps_nam_tmp, [options.name '.eps'], 'f');
|
---|
640 | catch ex
|
---|
641 | if ~options.pdf
|
---|
642 | % Delete the pdf
|
---|
643 | delete(pdf_nam);
|
---|
644 | end
|
---|
645 | try delete(eps_nam_tmp); catch, end
|
---|
646 | rethrow(ex);
|
---|
647 | end
|
---|
648 | if ~options.pdf
|
---|
649 | % Delete the pdf
|
---|
650 | delete(pdf_nam);
|
---|
651 | end
|
---|
652 | end
|
---|
653 | end
|
---|
654 |
|
---|
655 | % Revert the figure or close it (if requested)
|
---|
656 | if cls || options.closeFig
|
---|
657 | % Close the created figure
|
---|
658 | close(fig);
|
---|
659 | else
|
---|
660 | % Reset the hardcopy mode
|
---|
661 | set(fig, 'InvertHardcopy', old_mode);
|
---|
662 | % Reset the axes limit and tick modes
|
---|
663 | for a = 1:numel(Hlims)
|
---|
664 | try
|
---|
665 | set(Hlims(a), 'XLimMode', Xlims{a}, 'YLimMode', Ylims{a}, 'ZLimMode', Zlims{a},...
|
---|
666 | 'XTickMode', Xtick{a}, 'YTickMode', Ytick{a}, 'ZTickMode', Ztick{a},...
|
---|
667 | 'XTickLabelMode', Xlabel{a}, 'YTickLabelMode', Ylabel{a}, 'ZTickLabelMode', Zlabel{a});
|
---|
668 | catch
|
---|
669 | % ignore - fix issue #4 (using HG2 on R2014a and earlier)
|
---|
670 | end
|
---|
671 | end
|
---|
672 | % Revert the tex-labels font weights
|
---|
673 | try set(texLabels, 'FontWeight','bold'); catch, end
|
---|
674 | % Revert annotation units
|
---|
675 | for handleIdx = 1 : numel(annotationHandles)
|
---|
676 | try
|
---|
677 | oldUnits = originalUnits{handleIdx};
|
---|
678 | catch
|
---|
679 | oldUnits = originalUnits;
|
---|
680 | end
|
---|
681 | try set(annotationHandles(handleIdx),'Units',oldUnits); catch, end
|
---|
682 | end
|
---|
683 | % Revert figure units
|
---|
684 | set(fig,'Units',oldFigUnits);
|
---|
685 | end
|
---|
686 |
|
---|
687 | % Output to clipboard (if requested)
|
---|
688 | if options.clipboard
|
---|
689 | % Delete the output file if unchanged from the default name ('export_fig_out.png')
|
---|
690 | if strcmpi(options.name,'export_fig_out')
|
---|
691 | try
|
---|
692 | fileInfo = dir('export_fig_out.png');
|
---|
693 | if ~isempty(fileInfo)
|
---|
694 | timediff = now - fileInfo.datenum;
|
---|
695 | ONE_SEC = 1/24/60/60;
|
---|
696 | if timediff < ONE_SEC
|
---|
697 | delete('export_fig_out.png');
|
---|
698 | end
|
---|
699 | end
|
---|
700 | catch
|
---|
701 | % never mind...
|
---|
702 | end
|
---|
703 | end
|
---|
704 |
|
---|
705 | % Save the image in the system clipboard
|
---|
706 | % credit: Jiro Doke's IMCLIPBOARD: http://www.mathworks.com/matlabcentral/fileexchange/28708-imclipboard
|
---|
707 | try
|
---|
708 | error(javachk('awt', 'export_fig -clipboard output'));
|
---|
709 | catch
|
---|
710 | warning('export_fig -clipboard output failed: requires Java to work');
|
---|
711 | return;
|
---|
712 | end
|
---|
713 | try
|
---|
714 | % Import necessary Java classes
|
---|
715 | import java.awt.Toolkit.*
|
---|
716 | import java.awt.image.BufferedImage
|
---|
717 | import java.awt.datatransfer.DataFlavor
|
---|
718 |
|
---|
719 | % Get System Clipboard object (java.awt.Toolkit)
|
---|
720 | cb = getDefaultToolkit.getSystemClipboard();
|
---|
721 |
|
---|
722 | % Add java class (ImageSelection) to the path
|
---|
723 | if ~exist('ImageSelection', 'class')
|
---|
724 | javaaddpath(fileparts(which(mfilename)), '-end');
|
---|
725 | end
|
---|
726 |
|
---|
727 | % Get image size
|
---|
728 | ht = size(imageData, 1);
|
---|
729 | wd = size(imageData, 2);
|
---|
730 |
|
---|
731 | % Convert to Blue-Green-Red format
|
---|
732 | try
|
---|
733 | imageData2 = imageData(:, :, [3 2 1]);
|
---|
734 | catch
|
---|
735 | % Probably gray-scaled image (2D, without the 3rd [RGB] dimension)
|
---|
736 | imageData2 = imageData(:, :, [1 1 1]);
|
---|
737 | end
|
---|
738 |
|
---|
739 | % Convert to 3xWxH format
|
---|
740 | imageData2 = permute(imageData2, [3, 2, 1]);
|
---|
741 |
|
---|
742 | % Append Alpha data (unused - transparency is not supported in clipboard copy)
|
---|
743 | alphaData2 = uint8(permute(255*alpha,[3,2,1])); %=255*ones(1,wd,ht,'uint8')
|
---|
744 | imageData2 = cat(1, imageData2, alphaData2);
|
---|
745 |
|
---|
746 | % Create image buffer
|
---|
747 | imBuffer = BufferedImage(wd, ht, BufferedImage.TYPE_INT_RGB);
|
---|
748 | imBuffer.setRGB(0, 0, wd, ht, typecast(imageData2(:), 'int32'), 0, wd);
|
---|
749 |
|
---|
750 | % Create ImageSelection object from the image buffer
|
---|
751 | imSelection = ImageSelection(imBuffer);
|
---|
752 |
|
---|
753 | % Set clipboard content to the image
|
---|
754 | cb.setContents(imSelection, []);
|
---|
755 | catch
|
---|
756 | warning('export_fig -clipboard output failed: %s', lasterr); %#ok<LERR>
|
---|
757 | end
|
---|
758 | end
|
---|
759 |
|
---|
760 | % Don't output the data to console unless requested
|
---|
761 | if ~nargout
|
---|
762 | clear imageData alpha
|
---|
763 | end
|
---|
764 | catch err
|
---|
765 | % Display possible workarounds before the error message
|
---|
766 | if displaySuggestedWorkarounds
|
---|
767 | if ~hadError, fprintf(2, 'export_fig error. '); end
|
---|
768 | fprintf(2, 'Please ensure:\n');
|
---|
769 | fprintf(2, ' that you are using the <a href="https://github.com/altmany/export_fig/archive/master.zip">latest version</a> of export_fig\n');
|
---|
770 | fprintf(2, ' and that you have <a href="http://www.ghostscript.com">Ghostscript</a> installed\n');
|
---|
771 | try
|
---|
772 | if options.eps
|
---|
773 | fprintf(2, ' and that you have <a href="http://www.foolabs.com/xpdf">pdftops</a> installed\n');
|
---|
774 | end
|
---|
775 | catch
|
---|
776 | % ignore - probably an error in parse_args
|
---|
777 | end
|
---|
778 | fprintf(2, ' and that you do not have <a href="matlab:which export_fig -all">multiple versions</a> of export_fig installed by mistake\n');
|
---|
779 | fprintf(2, ' and that you did not made a mistake in the <a href="matlab:help export_fig">expected input arguments</a>\n');
|
---|
780 | fprintf(2, '\nIf the problem persists, then please <a href="https://github.com/altmany/export_fig/issues">report a new issue</a>.\n\n');
|
---|
781 | end
|
---|
782 | rethrow(err)
|
---|
783 | end
|
---|
784 | end
|
---|
785 |
|
---|
786 | function [fig, options] = parse_args(nout, fig, varargin)
|
---|
787 | % Parse the input arguments
|
---|
788 | % Set the defaults
|
---|
789 | options = struct(...
|
---|
790 | 'name', 'export_fig_out', ...
|
---|
791 | 'crop', true, ...
|
---|
792 | 'transparent', false, ...
|
---|
793 | 'renderer', 0, ... % 0: default, 1: OpenGL, 2: ZBuffer, 3: Painters
|
---|
794 | 'pdf', false, ...
|
---|
795 | 'eps', false, ...
|
---|
796 | 'png', false, ...
|
---|
797 | 'tif', false, ...
|
---|
798 | 'jpg', false, ...
|
---|
799 | 'bmp', false, ...
|
---|
800 | 'clipboard', false, ...
|
---|
801 | 'colourspace', 0, ... % 0: RGB/gray, 1: CMYK, 2: gray
|
---|
802 | 'append', false, ...
|
---|
803 | 'im', nout == 1, ...
|
---|
804 | 'alpha', nout == 2, ...
|
---|
805 | 'aa_factor', 0, ...
|
---|
806 | 'bb_padding', 0, ...
|
---|
807 | 'magnify', [], ...
|
---|
808 | 'resolution', [], ...
|
---|
809 | 'bookmark', false, ...
|
---|
810 | 'closeFig', false, ...
|
---|
811 | 'quality', [], ...
|
---|
812 | 'update', false, ...
|
---|
813 | 'fontswap', true, ...
|
---|
814 | 'gs_options', {{}});
|
---|
815 | native = false; % Set resolution to native of an image
|
---|
816 |
|
---|
817 | % Go through the other arguments
|
---|
818 | skipNext = false;
|
---|
819 | for a = 1:nargin-2
|
---|
820 | if skipNext
|
---|
821 | skipNext = false;
|
---|
822 | continue;
|
---|
823 | end
|
---|
824 | if all(ishandle(varargin{a}))
|
---|
825 | fig = varargin{a};
|
---|
826 | elseif ischar(varargin{a}) && ~isempty(varargin{a})
|
---|
827 | if varargin{a}(1) == '-'
|
---|
828 | switch lower(varargin{a}(2:end))
|
---|
829 | case 'nocrop'
|
---|
830 | options.crop = false;
|
---|
831 | case {'trans', 'transparent'}
|
---|
832 | options.transparent = true;
|
---|
833 | case 'opengl'
|
---|
834 | options.renderer = 1;
|
---|
835 | case 'zbuffer'
|
---|
836 | options.renderer = 2;
|
---|
837 | case 'painters'
|
---|
838 | options.renderer = 3;
|
---|
839 | case 'pdf'
|
---|
840 | options.pdf = true;
|
---|
841 | case 'eps'
|
---|
842 | options.eps = true;
|
---|
843 | case 'png'
|
---|
844 | options.png = true;
|
---|
845 | case {'tif', 'tiff'}
|
---|
846 | options.tif = true;
|
---|
847 | case {'jpg', 'jpeg'}
|
---|
848 | options.jpg = true;
|
---|
849 | case 'bmp'
|
---|
850 | options.bmp = true;
|
---|
851 | case 'rgb'
|
---|
852 | options.colourspace = 0;
|
---|
853 | case 'cmyk'
|
---|
854 | options.colourspace = 1;
|
---|
855 | case {'gray', 'grey'}
|
---|
856 | options.colourspace = 2;
|
---|
857 | case {'a1', 'a2', 'a3', 'a4'}
|
---|
858 | options.aa_factor = str2double(varargin{a}(3));
|
---|
859 | case 'append'
|
---|
860 | options.append = true;
|
---|
861 | case 'bookmark'
|
---|
862 | options.bookmark = true;
|
---|
863 | case 'native'
|
---|
864 | native = true;
|
---|
865 | case 'clipboard'
|
---|
866 | options.clipboard = true;
|
---|
867 | options.im = true;
|
---|
868 | options.alpha = true;
|
---|
869 | case 'svg'
|
---|
870 | msg = ['SVG output is not supported by export_fig. Use one of the following alternatives:\n' ...
|
---|
871 | ' 1. saveas(gcf,''filename.svg'')\n' ...
|
---|
872 | ' 2. plot2svg utility: http://github.com/jschwizer99/plot2svg\n' ...
|
---|
873 | ' 3. export_fig to EPS/PDF, then convert to SVG using generic (non-Matlab) tools\n'];
|
---|
874 | error(sprintf(msg)); %#ok<SPERR>
|
---|
875 | case 'update'
|
---|
876 | % Download the latest version of export_fig into the export_fig folder
|
---|
877 | try
|
---|
878 | zipFileName = 'https://github.com/altmany/export_fig/archive/master.zip';
|
---|
879 | folderName = fileparts(which(mfilename('fullpath')));
|
---|
880 | targetFileName = fullfile(folderName, datestr(now,'yyyy-mm-dd.zip'));
|
---|
881 | urlwrite(zipFileName,targetFileName);
|
---|
882 | catch
|
---|
883 | error('Could not download %s into %s\n',zipFileName,targetFileName);
|
---|
884 | end
|
---|
885 |
|
---|
886 | % Unzip the downloaded zip file in the export_fig folder
|
---|
887 | try
|
---|
888 | unzip(targetFileName,folderName);
|
---|
889 | catch
|
---|
890 | error('Could not unzip %s\n',targetFileName);
|
---|
891 | end
|
---|
892 | case 'nofontswap'
|
---|
893 | options.fontswap = false;
|
---|
894 | otherwise
|
---|
895 | try
|
---|
896 | wasError = false;
|
---|
897 | if strcmpi(varargin{a}(1:2),'-d')
|
---|
898 | varargin{a}(2) = 'd'; % ensure lowercase 'd'
|
---|
899 | options.gs_options{end+1} = varargin{a};
|
---|
900 | else
|
---|
901 | val = str2double(regexp(varargin{a}, '(?<=-(m|M|r|R|q|Q|p|P))-?\d*.?\d+', 'match'));
|
---|
902 | if isempty(val) || isnan(val)
|
---|
903 | % Issue #51: improved processing of input args (accept space between param name & value)
|
---|
904 | val = str2double(varargin{a+1});
|
---|
905 | if isscalar(val) && ~isnan(val)
|
---|
906 | skipNext = true;
|
---|
907 | end
|
---|
908 | end
|
---|
909 | if ~isscalar(val) || isnan(val)
|
---|
910 | wasError = true;
|
---|
911 | error('option %s is not recognised or cannot be parsed', varargin{a});
|
---|
912 | end
|
---|
913 | switch lower(varargin{a}(2))
|
---|
914 | case 'm'
|
---|
915 | % Magnification may never be negative
|
---|
916 | if val <= 0
|
---|
917 | wasError = true;
|
---|
918 | error('Bad magnification value: %g (must be positive)', val);
|
---|
919 | end
|
---|
920 | options.magnify = val;
|
---|
921 | case 'r'
|
---|
922 | options.resolution = val;
|
---|
923 | case 'q'
|
---|
924 | options.quality = max(val, 0);
|
---|
925 | case 'p'
|
---|
926 | options.bb_padding = val;
|
---|
927 | end
|
---|
928 | end
|
---|
929 | catch err
|
---|
930 | % We might have reached here by raising an intentional error
|
---|
931 | if wasError % intentional raise
|
---|
932 | rethrow(err)
|
---|
933 | else % unintentional
|
---|
934 | error(['Unrecognized export_fig input option: ''' varargin{a} '''']);
|
---|
935 | end
|
---|
936 | end
|
---|
937 | end
|
---|
938 | else
|
---|
939 | [p, options.name, ext] = fileparts(varargin{a});
|
---|
940 | if ~isempty(p)
|
---|
941 | options.name = [p filesep options.name];
|
---|
942 | end
|
---|
943 | switch lower(ext)
|
---|
944 | case {'.tif', '.tiff'}
|
---|
945 | options.tif = true;
|
---|
946 | case {'.jpg', '.jpeg'}
|
---|
947 | options.jpg = true;
|
---|
948 | case '.png'
|
---|
949 | options.png = true;
|
---|
950 | case '.bmp'
|
---|
951 | options.bmp = true;
|
---|
952 | case '.eps'
|
---|
953 | options.eps = true;
|
---|
954 | case '.pdf'
|
---|
955 | options.pdf = true;
|
---|
956 | case '.fig'
|
---|
957 | % If no open figure, then load the specified .fig file and continue
|
---|
958 | if isempty(fig)
|
---|
959 | fig = openfig(varargin{a},'invisible');
|
---|
960 | varargin{a} = fig;
|
---|
961 | options.closeFig = true;
|
---|
962 | else
|
---|
963 | % save the current figure as the specified .fig file and exit
|
---|
964 | saveas(fig(1),varargin{a});
|
---|
965 | fig = -1;
|
---|
966 | return
|
---|
967 | end
|
---|
968 | case '.svg'
|
---|
969 | msg = ['SVG output is not supported by export_fig. Use one of the following alternatives:\n' ...
|
---|
970 | ' 1. saveas(gcf,''filename.svg'')\n' ...
|
---|
971 | ' 2. plot2svg utility: http://github.com/jschwizer99/plot2svg\n' ...
|
---|
972 | ' 3. export_fig to EPS/PDF, then convert to SVG using generic (non-Matlab) tools\n'];
|
---|
973 | error(sprintf(msg)); %#ok<SPERR>
|
---|
974 | otherwise
|
---|
975 | options.name = varargin{a};
|
---|
976 | end
|
---|
977 | end
|
---|
978 | end
|
---|
979 | end
|
---|
980 |
|
---|
981 | % Quick bail-out if no figure found
|
---|
982 | if isempty(fig), return; end
|
---|
983 |
|
---|
984 | % Do border padding with repsect to a cropped image
|
---|
985 | if options.bb_padding
|
---|
986 | options.crop = true;
|
---|
987 | end
|
---|
988 |
|
---|
989 | % Set default anti-aliasing now we know the renderer
|
---|
990 | if options.aa_factor == 0
|
---|
991 | try isAA = strcmp(get(ancestor(fig, 'figure'), 'GraphicsSmoothing'), 'on'); catch, isAA = false; end
|
---|
992 | options.aa_factor = 1 + 2 * (~(using_hg2(fig) && isAA) | (options.renderer == 3));
|
---|
993 | end
|
---|
994 |
|
---|
995 | % Convert user dir '~' to full path
|
---|
996 | if numel(options.name) > 2 && options.name(1) == '~' && (options.name(2) == '/' || options.name(2) == '\')
|
---|
997 | options.name = fullfile(char(java.lang.System.getProperty('user.home')), options.name(2:end));
|
---|
998 | end
|
---|
999 |
|
---|
1000 | % Compute the magnification and resolution
|
---|
1001 | if isempty(options.magnify)
|
---|
1002 | if isempty(options.resolution)
|
---|
1003 | options.magnify = 1;
|
---|
1004 | options.resolution = 864;
|
---|
1005 | else
|
---|
1006 | options.magnify = options.resolution ./ get(0, 'ScreenPixelsPerInch');
|
---|
1007 | end
|
---|
1008 | elseif isempty(options.resolution)
|
---|
1009 | options.resolution = 864;
|
---|
1010 | end
|
---|
1011 |
|
---|
1012 | % Set the default format
|
---|
1013 | if ~isvector(options) && ~isbitmap(options)
|
---|
1014 | options.png = true;
|
---|
1015 | end
|
---|
1016 |
|
---|
1017 | % Check whether transparent background is wanted (old way)
|
---|
1018 | if isequal(get(ancestor(fig(1), 'figure'), 'Color'), 'none')
|
---|
1019 | options.transparent = true;
|
---|
1020 | end
|
---|
1021 |
|
---|
1022 | % If requested, set the resolution to the native vertical resolution of the
|
---|
1023 | % first suitable image found
|
---|
1024 | if native && isbitmap(options)
|
---|
1025 | % Find a suitable image
|
---|
1026 | list = findall(fig, 'Type','image', 'Tag','export_fig_native');
|
---|
1027 | if isempty(list)
|
---|
1028 | list = findall(fig, 'Type','image', 'Visible','on');
|
---|
1029 | end
|
---|
1030 | for hIm = list(:)'
|
---|
1031 | % Check height is >= 2
|
---|
1032 | height = size(get(hIm, 'CData'), 1);
|
---|
1033 | if height < 2
|
---|
1034 | continue
|
---|
1035 | end
|
---|
1036 | % Account for the image filling only part of the axes, or vice
|
---|
1037 | % versa
|
---|
1038 | yl = get(hIm, 'YData');
|
---|
1039 | if isscalar(yl)
|
---|
1040 | yl = [yl(1)-0.5 yl(1)+height+0.5];
|
---|
1041 | else
|
---|
1042 | if ~diff(yl)
|
---|
1043 | continue
|
---|
1044 | end
|
---|
1045 | yl = yl + [-0.5 0.5] * (diff(yl) / (height - 1));
|
---|
1046 | end
|
---|
1047 | hAx = get(hIm, 'Parent');
|
---|
1048 | yl2 = get(hAx, 'YLim');
|
---|
1049 | % Find the pixel height of the axes
|
---|
1050 | oldUnits = get(hAx, 'Units');
|
---|
1051 | set(hAx, 'Units', 'pixels');
|
---|
1052 | pos = get(hAx, 'Position');
|
---|
1053 | set(hAx, 'Units', oldUnits);
|
---|
1054 | if ~pos(4)
|
---|
1055 | continue
|
---|
1056 | end
|
---|
1057 | % Found a suitable image
|
---|
1058 | % Account for stretch-to-fill being disabled
|
---|
1059 | pbar = get(hAx, 'PlotBoxAspectRatio');
|
---|
1060 | pos = min(pos(4), pbar(2)*pos(3)/pbar(1));
|
---|
1061 | % Set the magnification to give native resolution
|
---|
1062 | options.magnify = abs((height * diff(yl2)) / (pos * diff(yl))); % magnification must never be negative: issue #103
|
---|
1063 | break
|
---|
1064 | end
|
---|
1065 | end
|
---|
1066 | end
|
---|
1067 |
|
---|
1068 | function A = downsize(A, factor)
|
---|
1069 | % Downsample an image
|
---|
1070 | if factor == 1
|
---|
1071 | % Nothing to do
|
---|
1072 | return
|
---|
1073 | end
|
---|
1074 | try
|
---|
1075 | % Faster, but requires image processing toolbox
|
---|
1076 | A = imresize(A, 1/factor, 'bilinear');
|
---|
1077 | catch
|
---|
1078 | % No image processing toolbox - resize manually
|
---|
1079 | % Lowpass filter - use Gaussian as is separable, so faster
|
---|
1080 | % Compute the 1d Gaussian filter
|
---|
1081 | filt = (-factor-1:factor+1) / (factor * 0.6);
|
---|
1082 | filt = exp(-filt .* filt);
|
---|
1083 | % Normalize the filter
|
---|
1084 | filt = single(filt / sum(filt));
|
---|
1085 | % Filter the image
|
---|
1086 | padding = floor(numel(filt) / 2);
|
---|
1087 | for a = 1:size(A, 3)
|
---|
1088 | A(:,:,a) = conv2(filt, filt', single(A([ones(1, padding) 1:end repmat(end, 1, padding)],[ones(1, padding) 1:end repmat(end, 1, padding)],a)), 'valid');
|
---|
1089 | end
|
---|
1090 | % Subsample
|
---|
1091 | A = A(1+floor(mod(end-1, factor)/2):factor:end,1+floor(mod(end-1, factor)/2):factor:end,:);
|
---|
1092 | end
|
---|
1093 | end
|
---|
1094 |
|
---|
1095 | function A = rgb2grey(A)
|
---|
1096 | A = cast(reshape(reshape(single(A), [], 3) * single([0.299; 0.587; 0.114]), size(A, 1), size(A, 2)), class(A)); %#ok<ZEROLIKE>
|
---|
1097 | end
|
---|
1098 |
|
---|
1099 | function A = check_greyscale(A)
|
---|
1100 | % Check if the image is greyscale
|
---|
1101 | if size(A, 3) == 3 && ...
|
---|
1102 | all(reshape(A(:,:,1) == A(:,:,2), [], 1)) && ...
|
---|
1103 | all(reshape(A(:,:,2) == A(:,:,3), [], 1))
|
---|
1104 | A = A(:,:,1); % Save only one channel for 8-bit output
|
---|
1105 | end
|
---|
1106 | end
|
---|
1107 |
|
---|
1108 | function eps_remove_background(fname, count)
|
---|
1109 | % Remove the background of an eps file
|
---|
1110 | % Open the file
|
---|
1111 | fh = fopen(fname, 'r+');
|
---|
1112 | if fh == -1
|
---|
1113 | error('Not able to open file %s.', fname);
|
---|
1114 | end
|
---|
1115 | % Read the file line by line
|
---|
1116 | while count
|
---|
1117 | % Get the next line
|
---|
1118 | l = fgets(fh);
|
---|
1119 | if isequal(l, -1)
|
---|
1120 | break; % Quit, no rectangle found
|
---|
1121 | end
|
---|
1122 | % Check if the line contains the background rectangle
|
---|
1123 | if isequal(regexp(l, ' *0 +0 +\d+ +\d+ +r[fe] *[\n\r]+', 'start'), 1)
|
---|
1124 | % Set the line to whitespace and quit
|
---|
1125 | l(1:regexp(l, '[\n\r]', 'start', 'once')-1) = ' ';
|
---|
1126 | fseek(fh, -numel(l), 0);
|
---|
1127 | fprintf(fh, l);
|
---|
1128 | % Reduce the count
|
---|
1129 | count = count - 1;
|
---|
1130 | end
|
---|
1131 | end
|
---|
1132 | % Close the file
|
---|
1133 | fclose(fh);
|
---|
1134 | end
|
---|
1135 |
|
---|
1136 | function b = isvector(options)
|
---|
1137 | b = options.pdf || options.eps;
|
---|
1138 | end
|
---|
1139 |
|
---|
1140 | function b = isbitmap(options)
|
---|
1141 | b = options.png || options.tif || options.jpg || options.bmp || options.im || options.alpha;
|
---|
1142 | end
|
---|
1143 |
|
---|
1144 | % Helper function
|
---|
1145 | function A = make_cell(A)
|
---|
1146 | if ~iscell(A)
|
---|
1147 | A = {A};
|
---|
1148 | end
|
---|
1149 | end
|
---|
1150 |
|
---|
1151 | function add_bookmark(fname, bookmark_text)
|
---|
1152 | % Adds a bookmark to the temporary EPS file after %%EndPageSetup
|
---|
1153 | % Read in the file
|
---|
1154 | fh = fopen(fname, 'r');
|
---|
1155 | if fh == -1
|
---|
1156 | error('File %s not found.', fname);
|
---|
1157 | end
|
---|
1158 | try
|
---|
1159 | fstrm = fread(fh, '*char')';
|
---|
1160 | catch ex
|
---|
1161 | fclose(fh);
|
---|
1162 | rethrow(ex);
|
---|
1163 | end
|
---|
1164 | fclose(fh);
|
---|
1165 |
|
---|
1166 | % Include standard pdfmark prolog to maximize compatibility
|
---|
1167 | fstrm = strrep(fstrm, '%%BeginProlog', sprintf('%%%%BeginProlog\n/pdfmark where {pop} {userdict /pdfmark /cleartomark load put} ifelse'));
|
---|
1168 | % Add page bookmark
|
---|
1169 | fstrm = strrep(fstrm, '%%EndPageSetup', sprintf('%%%%EndPageSetup\n[ /Title (%s) /OUT pdfmark',bookmark_text));
|
---|
1170 |
|
---|
1171 | % Write out the updated file
|
---|
1172 | fh = fopen(fname, 'w');
|
---|
1173 | if fh == -1
|
---|
1174 | error('Unable to open %s for writing.', fname);
|
---|
1175 | end
|
---|
1176 | try
|
---|
1177 | fwrite(fh, fstrm, 'char*1');
|
---|
1178 | catch ex
|
---|
1179 | fclose(fh);
|
---|
1180 | rethrow(ex);
|
---|
1181 | end
|
---|
1182 | fclose(fh);
|
---|
1183 | end
|
---|
1184 |
|
---|
1185 | function set_tick_mode(Hlims, ax)
|
---|
1186 | % Set the tick mode of linear axes to manual
|
---|
1187 | % Leave log axes alone as these are tricky
|
---|
1188 | M = get(Hlims, [ax 'Scale']);
|
---|
1189 | if ~iscell(M)
|
---|
1190 | M = {M};
|
---|
1191 | end
|
---|
1192 | M = cellfun(@(c) strcmp(c, 'linear'), M);
|
---|
1193 | set(Hlims(M), [ax 'TickMode'], 'manual');
|
---|
1194 | %set(Hlims(M), [ax 'TickLabelMode'], 'manual'); % this hides exponent label in HG2!
|
---|
1195 | end
|
---|
1196 |
|
---|
1197 | function change_rgb_to_cmyk(fname) % convert RGB => CMYK within an EPS file
|
---|
1198 | % Do post-processing on the eps file
|
---|
1199 | try
|
---|
1200 | % Read the EPS file into memory
|
---|
1201 | fstrm = read_write_entire_textfile(fname);
|
---|
1202 |
|
---|
1203 | % Replace all gray-scale colors
|
---|
1204 | fstrm = regexprep(fstrm, '\n([\d.]+) +GC\n', '\n0 0 0 ${num2str(1-str2num($1))} CC\n');
|
---|
1205 |
|
---|
1206 | % Replace all RGB colors
|
---|
1207 | fstrm = regexprep(fstrm, '\n[0.]+ +[0.]+ +[0.]+ +RC\n', '\n0 0 0 1 CC\n'); % pure black
|
---|
1208 | fstrm = regexprep(fstrm, '\n([\d.]+) +([\d.]+) +([\d.]+) +RC\n', '\n${sprintf(''%.4g '',[1-[str2num($1),str2num($2),str2num($3)]/max([str2num($1),str2num($2),str2num($3)]),1-max([str2num($1),str2num($2),str2num($3)])])} CC\n');
|
---|
1209 |
|
---|
1210 | % Overwrite the file with the modified contents
|
---|
1211 | read_write_entire_textfile(fname, fstrm);
|
---|
1212 | catch
|
---|
1213 | % never mind - leave as is...
|
---|
1214 | end
|
---|
1215 | end
|
---|