function [imageData, alpha] = export_fig(varargin) %#ok<*STRCL1>
%EXPORT_FIG Exports figures in a publication-quality format
%
% Examples:
% imageData = export_fig
% [imageData, alpha] = export_fig
% export_fig filename
% export_fig filename -format1 -format2
% export_fig ... -nocrop
% export_fig ... -c[<val>,<val>,<val>,<val>]
% export_fig ... -transparent
% export_fig ... -native
% export_fig ... -m<val>
% export_fig ... -r<val>
% export_fig ... -a<val>
% export_fig ... -q<val>
% export_fig ... -p<val>
% export_fig ... -d<gs_option>
% export_fig ... -depsc
% export_fig ... -<renderer>
% export_fig ... -<colorspace>
% export_fig ... -append
% export_fig ... -bookmark
% export_fig ... -clipboard
% export_fig ... -update
% export_fig ... -nofontswap
% export_fig ... -font_space <char>
% export_fig ... -linecaps
% export_fig ... -noinvert
% export_fig ... -preserve_size
% export_fig ... -options <optionsStruct>
% export_fig(..., handle)
%
% This function saves a figure or single axes to one or more vector and/or
% bitmap file formats, and/or outputs a rasterized version to the workspace,
% with the following properties:
% - Figure/axes reproduced as it appears on screen
% - Cropped borders (optional)
% - Embedded fonts (vector formats)
% - Improved line and grid line styles
% - Anti-aliased graphics (bitmap formats)
% - Render images at native resolution (optional for bitmap formats)
% - Transparent background supported (pdf, eps, png, tif)
% - Semi-transparent patch objects supported (png, tif)
% - RGB, CMYK or grayscale output (CMYK only with pdf, eps, tif)
% - Variable image compression, including lossless (pdf, eps, jpg)
% - Optional rounded line-caps (pdf, eps)
% - Optionally append to file (pdf, tif)
% - Vector formats: pdf, eps, svg
% - Bitmap formats: png, tif, jpg, bmp, export to workspace
%
% This function is especially suited to exporting figures for use in
% publications and presentations, because of the high quality and
% portability of media produced.
%
% Note that the background color and figure dimensions are reproduced
% (the latter approximately, and ignoring cropping & magnification) in the
% output file. For transparent background (and semi-transparent patch
% objects), use the -transparent option or set the figure 'Color' property
% to 'none'. To make axes transparent set the axes 'Color' property to
% 'none'. PDF, EPS, TIF & PNG are the only formats that support a transparent
% background; only TIF & PNG formats support transparency of patch objects.
%
% The choice of renderer (opengl/zbuffer/painters) has a large impact on the
% output quality. The default value (opengl for bitmaps, painters for vector
% formats) generally gives good results, but if you aren't satisfied
% then try another renderer. Notes:
% 1) For vector formats (EPS,PDF), only painters generates vector graphics
% 2) For bitmap formats, only opengl correctly renders transparent patches
% 3) For bitmap formats, only painters correctly scales line dash and dot
% lengths when magnifying or anti-aliasing
% 4) Fonts may be substitued with Courier when using painters
%
% When exporting to vector format (PDF & EPS) and bitmap format using the
% painters renderer, this function requires that ghostscript is installed
% on your system. You can download this from:
% http://www.ghostscript.com
% When exporting to EPS it additionally requires pdftops, from the Xpdf
% suite of functions. You can download this from: http://xpdfreader.com
%
% SVG output uses the fig2svg (https://github.com/kupiqu/fig2svg) or plot2svg
% (https://github.com/jschwizer99/plot2svg) utilities, or Matlab's built-in
% SVG export if neither of these utilities are available on Matlab's path.
% Note: cropping/padding are not supported in export_fig's SVG output.
%
% Inputs:
% filename - string containing the name (optionally including full or
% relative path) of the file the figure is to be saved as. If
% a path is not specified, the figure is saved in the current
% directory. If no name and no output arguments are specified,
% the default name, 'export_fig_out', is used. If neither a
% file extension nor a format are specified, a ".png" is added
% and the figure saved in that format.
% -<format> - string(s) containing the output file extension(s). Options:
% '-pdf', '-eps', '-svg', '-png', '-tif', '-jpg' and '-bmp'.
% Multiple formats can be specified, without restriction.
% For example: export_fig('-jpg', '-pdf', '-png', ...)
% Either '-tif','-tiff' can be specified, and either '-jpg','-jpeg'.
% -nocrop - option indicating that empty margins should not be cropped.
% -c[<val>,<val>,<val>,<val>] - option indicating crop amounts. Must be
% a 4-element vector of numeric values: [top,right,bottom,left]
% where NaN/Inf indicate auto-cropping, 0 means no cropping,
% and any other value mean cropping in pixel amounts.
% -transparent - option indicating that the figure background is to be made
% transparent (PNG,PDF,TIF,EPS formats only). Implies -noinvert.
% -m<val> - option where val indicates the factor to magnify the
% on-screen figure pixel dimensions by when generating bitmap
% outputs (does not affect vector formats). Default: '-m1'.
% -r<val> - option val indicates the resolution (in pixels per inch) to
% export bitmap and vector outputs at, keeping the dimensions
% of the on-screen figure. Default: '-r864' (for vector output
% only). Note that the -m option overides the -r option for
% bitmap outputs only.
% -native - option indicating that the output resolution (when outputting
% a bitmap format) should be such that the vertical resolution
% of the first suitable image found in the figure is at the
% native resolution of that image. To specify a particular
% image to use, give it the tag 'export_fig_native'. Notes:
% This overrides any value set with the -m and -r options. It
% also assumes that the image is displayed front-to-parallel
% with the screen. The output resolution is approximate and
% should not be relied upon. Anti-aliasing can have adverse
% effects on image quality (disable with the -a1 option).
% -a1, -a2, -a3, -a4 - option indicating the amount of anti-aliasing to
% use for bitmap outputs. '-a1' means no anti-aliasing;
% '-a4' is the maximum amount (default).
% -<renderer> - option to force a particular renderer (painters, opengl or
% zbuffer). Default value: opengl for bitmap formats or
% figures with patches and/or transparent annotations;
% painters for vector formats without patches/transparencies.
% -<colorspace> - option indicating which colorspace color figures should
% be saved in: RGB (default), CMYK or gray. Usage example: '-gray'.
% Note: CMYK is only supported in PDF, EPS and TIF formats.
% -q<val> - option to vary bitmap image quality (PDF, EPS, JPG formats only).
% A larger val, in the range 0-100, produces higher quality and
% lower compression. val > 100 results in lossless compression.
% Default: '-q95' for JPG, ghostscript prepress default for PDF,EPS.
% Note: lossless compression can sometimes give a smaller file size
% than the default lossy compression, depending on the image type.
% -p<val> - option to pad a border of width val to exported files, where
% val is either a relative size with respect to cropped image
% size (i.e. p=0.01 adds a 1% border). For EPS & PDF formats,
% val can also be integer in units of 1/72" points (abs(val)>1).
% val can be positive (padding) or negative (extra cropping).
% If used, the -nocrop flag will be ignored, i.e. the image will
% always be cropped and then padded. Default: 0 (i.e. no padding).
% -append - option indicating that if the file already exists the figure is to
% be appended as a new page, instead of being overwritten (default).
% PDF & TIF output formats only.
% -bookmark - option to indicate that a bookmark with the name of the
% figure is to be created in the output file (PDF format only).
% -clipboard - option to save output as an image on the system clipboard.
% Note: background transparency is not preserved in clipboard
% -d<gs_option> - option to indicate a ghostscript setting. For example,
% -dMaxBitmap=0 or -dNoOutputFonts (Ghostscript 9.15+).
% -depsc - option to use EPS level-3 rather than the default level-2 print
% device. This solves some bugs with Matlab's default -depsc2 device
% such as discolored subplot lines on images (vector formats only).
% -update - option to download and install the latest version of export_fig
% -nofontswap - option to avoid font swapping. Font swapping is automatically
% done in vector formats (only): 11 standard Matlab fonts are
% replaced by the original figure fonts. This option prevents this.
% -font_space <char> - option to set a spacer character for font-names that
% contain spaces, used by EPS/PDF. Default: ''
% -linecaps - option to create rounded line-caps (vector formats only).
% -noinvert - option to avoid setting figure's InvertHardcopy property to
% 'off' during output (this solves some problems of empty outputs).
% -preserve_size - option to preserve the figure's PaperSize property in output
% file (PDF/EPS formats only; default is to not preserve it).
% -options <optionsStruct> - format-specific parameters as defined in Matlab's
% documentation of the imwrite function, contained in a struct under
% the format name. For example to specify the JPG Comment parameter,
% pass a struct such as this: options.JPG.Comment='abc'. Similarly,
% options.PNG.BitDepth=4. Valid only for PNG,TIF,JPG output formats.
% handle - The handle of the figure, axes or uipanels (can be an array of
% handles, but the objects must be in the same figure) which is
% to be saved. Default: gcf (handle of current figure).
%
% Outputs:
% imageData - MxNxC uint8 image array of the exported image.
% alpha - MxN single array of alphamatte values in the range [0,1],
% for the case when the background is transparent.
%
% Some helpful examples and tips can be found at:
% https://github.com/altmany/export_fig
%
% See also PRINT, SAVEAS, ScreenCapture (on the Matlab File Exchange)
%{
% Copyright (C) Oliver Woodford 2008-2014, Yair Altman 2015-
% The idea of using ghostscript is inspired by Peder Axensten's SAVEFIG
% (fex id: 10889) which is itself inspired by EPS2PDF (fex id: 5782).
% The idea for using pdftops came from the MATLAB newsgroup (id: 168171).
% The idea of editing the EPS file to change line styles comes from Jiro
% Doke's FIXPSLINESTYLE (fex id: 17928).
% The idea of changing dash length with line width came from comments on
% fex id: 5743, but the implementation is mine :)
% The idea of anti-aliasing bitmaps came from Anders Brun's MYAA (fex id:
% 20979).
% The idea of appending figures in pdfs came from Matt C in comments on the
% FEX (id: 23629)
% Thanks to Roland Martin for pointing out the colour MATLAB
% bug/feature with colorbar axes and transparent backgrounds.
% Thanks also to Andrew Matthews for describing a bug to do with the figure
% size changing in -nodisplay mode. I couldn't reproduce it, but included a
% fix anyway.
% Thanks to Tammy Threadgill for reporting a bug where an axes is not
% isolated from gui objects.
%}
%{
% 23/02/12: Ensure that axes limits don't change during printing
% 14/03/12: Fix bug in fixing the axes limits (thanks to Tobias Lamour for reporting it).
% 02/05/12: Incorporate patch of Petr Nechaev (many thanks), enabling bookmarking of figures in pdf files.
% 09/05/12: Incorporate patch of Arcelia Arrieta (many thanks), to keep tick marks fixed.
% 12/12/12: Add support for isolating uipanels. Thanks to michael for suggesting it.
% 25/09/13: Add support for changing resolution in vector formats. Thanks to Jan Jaap Meijer for suggesting it.
% 07/05/14: Add support for '~' at start of path. Thanks to Sally Warner for suggesting it.
% 24/02/15: Fix Matlab R2014b bug (issue #34): plot markers are not displayed when ZLimMode='manual'
% 25/02/15: Fix issue #4 (using HG2 on R2014a and earlier)
% 25/02/15: Fix issue #21 (bold TeX axes labels/titles in R2014b)
% 26/02/15: If temp dir is not writable, use the user-specified folder for temporary EPS/PDF files (Javier Paredes)
% 27/02/15: Modified repository URL from github.com/ojwoodford to /altmany
% Indented main function
% Added top-level try-catch block to display useful workarounds
% 28/02/15: Enable users to specify optional ghostscript options (issue #36)
% 06/03/15: Improved image padding & cropping thanks to Oscar Hartogensis
% 26/03/15: Fixed issue #49 (bug with transparent grayscale images); fixed out-of-memory issue
% 26/03/15: Fixed issue #42: non-normalized annotations on HG1
% 26/03/15: Fixed issue #46: Ghostscript crash if figure units <> pixels
% 27/03/15: Fixed issue #39: bad export of transparent annotations/patches
% 28/03/15: Fixed issue #50: error on some Matlab versions with the fix for issue #42
% 29/03/15: Fixed issue #33: bugs in Matlab's print() function with -cmyk
% 29/03/15: Improved processing of input args (accept space between param name & value, related to issue #51)
% 30/03/15: When exporting *.fig files, then saveas *.fig if figure is open, otherwise export the specified fig file
% 30/03/15: Fixed edge case bug introduced yesterday (commit #ae1755bd2e11dc4e99b95a7681f6e211b3fa9358)
% 09/04/15: Consolidated header comment sections; initialize output vars only if requested (nargout>0)
% 14/04/15: Workaround for issue #45: lines in image subplots are exported in invalid color
% 15/04/15: Fixed edge-case in parsing input parameters; fixed help section to show the -depsc option (issue #45)
% 21/04/15: Bug fix: Ghostscript croaks on % chars in output PDF file (reported by Sven on FEX page, 15-Jul-2014)
% 22/04/15: Bug fix: Pdftops croaks on relative paths (reported by Tintin Milou on FEX page, 19-Jan-2015)
% 04/05/15: Merged fix #63 (Kevin Mattheus Moerman): prevent tick-label changes during export
% 07/05/15: Partial fix for issue #65: PDF export used painters rather than opengl renderer (thanks Nguyenr)
% 08/05/15: Fixed issue #65: bad PDF append since commit #e9f3cdf 21/04/15 (thanks Robert Nguyen)
% 12/05/15: Fixed issue #67: exponent labels cropped in export, since fix #63 (04/05/15)
% 28/05/15: Fixed issue #69: set non-bold label font only if the string contains symbols (\beta etc.), followup to issue #21
% 29/05/15: Added informative error message in case user requested SVG output (issue #72)
% 09/06/15: Fixed issue #58: -transparent removed anti-aliasing when exporting to PNG
% 19/06/15: Added -update option to download and install the latest version of export_fig
% 07/07/15: Added -nofontswap option to avoid font-swapping in EPS/PDF
% 16/07/15: Fixed problem with anti-aliasing on old Matlab releases
% 11/09/15: Fixed issue #103: magnification must never become negative; also fixed reported error msg in parsing input params
% 26/09/15: Alert if trying to export transparent patches/areas to non-PNG outputs (issue #108)
% 04/10/15: Do not suggest workarounds for certain errors that have already been handled previously
% 01/11/15: Fixed issue #112: use same renderer in print2eps as export_fig (thanks to Jesús Pestana Puerta)
% 10/11/15: Custom GS installation webpage for MacOS. Thanks to Andy Hueni via FEX
% 19/11/15: Fixed clipboard export in R2015b (thanks to Dan K via FEX)
% 21/02/16: Added -c option for indicating specific crop amounts (idea by Cedric Noordam on FEX)
% 08/05/16: Added message about possible error reason when groot.Units~=pixels (issue #149)
% 17/05/16: Fixed case of image YData containing more than 2 elements (issue #151)
% 08/08/16: Enabled exporting transparency to TIF, in addition to PNG/PDF (issue #168)
% 11/12/16: Added alert in case of error creating output PDF/EPS file (issue #179)
% 13/12/16: Minor fix to the commit for issue #179 from 2 days ago
% 22/03/17: Fixed issue #187: only set manual ticks when no exponent is present
% 09/04/17: Added -linecaps option (idea by Baron Finer, issue #192)
% 15/09/17: Fixed issue #205: incorrect tick-labels when Ticks number don't match the TickLabels number
% 15/09/17: Fixed issue #210: initialize alpha map to ones instead of zeros when -transparent is not used
% 18/09/17: Added -font_space option to replace font-name spaces in EPS/PDF (workaround for issue #194)
% 18/09/17: Added -noinvert option to solve some export problems with some graphic cards (workaround for issue #197)
% 08/11/17: Fixed issue #220: axes exponent is removed in HG1 when TickMode is 'manual' (internal Matlab bug)
% 08/11/17: Fixed issue #221: alert if the requested folder does not exist
% 19/11/17: Workaround for issue #207: alert when trying to use transparent bgcolor with -opengl
% 29/11/17: Workaround for issue #206: warn if exporting PDF/EPS for a figure that contains an image
% 11/12/17: Fixed issue #230: use OpenGL renderer when exported image contains transparency (also see issue #206)
% 30/01/18: Updated SVG message to point to https://github.com/kupiqu/plot2svg and display user-selected filename if available
% 27/02/18: Fixed issue #236: axes exponent cropped from output if on right-hand axes
% 29/05/18: Fixed issue #245: process "string" inputs just like 'char' inputs
% 13/08/18: Fixed issue #249: correct black axes color to off-black to avoid extra cropping with -transparent
% 27/08/18: Added a possible file-open reason in EPS/PDF write-error message (suggested by "craq" on FEX page)
% 22/09/18: Xpdf website changed to xpdfreader.com
% 23/09/18: Fixed issue #243: only set non-bold font (workaround for issue #69) in R2015b or earlier; warn if changing font
% 23/09/18: Workaround for issue #241: don't use -r864 in EPS/PDF outputs when -native is requested (solves black lines problem)
% 18/11/18: Issue #261: Added informative alert when trying to export a uifigure (which is not currently supported)
% 13/12/18: Issue #261: Fixed last commit for cases of specifying axes/panel handle as input, rather than a figure handle
% 13/01/19: Issue #72: Added basic SVG output support
% 04/02/19: Workaround for issues #207 and #267: -transparent implies -noinvert
% 08/03/19: Issue #269: Added ability to specify format-specific options for PNG,TIF,JPG outputs; fixed help section
% 21/03/19: Fixed the workaround for issues #207 and #267 from 4/2/19 (-transparent now does *NOT* imply -noinvert; -transparent output should now be ok in all formats)
% 12/06/19: Issue #277: Enabled preservation of figure's PaperSize in output PDF/EPS file
% 06/08/19: Remove warning message about obsolete JavaFrame in R2019b
%}
if nargout
[imageData, alpha] = deal([]);
end
hadError = false;
displaySuggestedWorkarounds = true;
% Ensure the figure is rendered correctly _now_ so that properties like axes limits are up-to-date
drawnow;
pause(0.05); % this solves timing issues with Java Swing's EDT (http://undocumentedmatlab.com/blog/solving-a-matlab-hang-problem)
% Parse the input arguments
fig = get(0, 'CurrentFigure');
[fig, options] = parse_args(nargout, fig, varargin{:});
% Ensure that we have a figure handle
if isequal(fig,-1)
return; % silent bail-out
elseif isempty(fig)
error('No figure found');
else
oldWarn = warning('off','MATLAB:HandleGraphics:ObsoletedProperty:JavaFrame');
warning off MATLAB:ui:javaframe:PropertyToBeRemoved
try jf = get(handle(ancestor(fig,'figure')),'JavaFrame'); catch, jf=1; end
warning(oldWarn);
if isempty(jf)
error('Figures created using the uifigure command or App Designer are not supported by export_fig. See <a href="https://github.com/altmany/export_fig/issues/261">issue #261</a> for details.');
end
end
% Isolate the subplot, if it is one
cls = all(ismember(get(fig, 'Type'), {'axes', 'uipanel'}));
if cls
% Given handles of one or more axes, so isolate them from the rest
fig = isolate_axes(fig);
else
% Check we have a figure
if ~isequal(get(fig, 'Type'), 'figure')
error('Handle must be that of a figure, axes or uipanel');
end
% Get the old InvertHardcopy mode
old_mode = get(fig, 'InvertHardcopy');
end
% Hack the font units where necessary (due to a font rendering bug in print?).
% This may not work perfectly in all cases.
% Also it can change the figure layout if reverted, so use a copy.
magnify = options.magnify * options.aa_factor;
if isbitmap(options) && magnify ~= 1
fontu = findall(fig, 'FontUnits', 'normalized');
if ~isempty(fontu)
% Some normalized font units found
if ~cls
fig = copyfig(fig);
set(fig, 'Visible', 'off');
fontu = findall(fig, 'FontUnits', 'normalized');
cls = true;
end
set(fontu, 'FontUnits', 'points');
end
end
try
% MATLAB "feature": axes limits and tick marks can change when printing
Hlims = findall(fig, 'Type', 'axes');
if ~cls
% Record the old axes limit and tick modes
Xlims = make_cell(get(Hlims, 'XLimMode'));
Ylims = make_cell(get(Hlims, 'YLimMode'));
Zlims = make_cell(get(Hlims, 'ZLimMode'));
Xtick = make_cell(get(Hlims, 'XTickMode'));
Ytick = make_cell(get(Hlims, 'YTickMode'));
Ztick = make_cell(get(Hlims, 'ZTickMode'));
Xlabel = make_cell(get(Hlims, 'XTickLabelMode'));
Ylabel = make_cell(get(Hlims, 'YTickLabelMode'));
Zlabel = make_cell(get(Hlims, 'ZTickLabelMode'));
end
% Set all axes limit and tick modes to manual, so the limits and ticks can't change
% Fix Matlab R2014b bug (issue #34): plot markers are not displayed when ZLimMode='manual'
set(Hlims, 'XLimMode', 'manual', 'YLimMode', 'manual');
set_tick_mode(Hlims, 'X');
set_tick_mode(Hlims, 'Y');
if ~using_hg2(fig)
set(Hlims,'ZLimMode', 'manual');
set_tick_mode(Hlims, 'Z');
end
catch
% ignore - fix issue #4 (using HG2 on R2014a and earlier)
end
% Fix issue #21 (bold TeX axes labels/titles in R2014b when exporting to EPS/PDF)
try
if using_hg2(fig) && isvector(options)
% Set the FontWeight of axes labels/titles to 'normal'
% Fix issue #69: set non-bold font only if the string contains symbols (\beta etc.)
% Issue #243: only set non-bold font (workaround for issue #69) in R2015b or earlier
try isPreR2016a = verLessThan('matlab','8.7'); catch, isPreR2016a = true; end
if isPreR2016a
texLabels = findall(fig, 'type','text', 'FontWeight','bold');
symbolIdx = ~cellfun('isempty',strfind({texLabels.String},'\'));
if ~isempty(symbolIdx)
set(texLabels(symbolIdx), 'FontWeight','normal');
warning('export_fig:BoldTexLabels', 'Bold labels with Tex symbols converted into non-bold in export_fig (fix for issue #69)');
end
end
end
catch
% ignore
end
% Fix issue #42: non-normalized annotations on HG1 (internal Matlab bug)
annotationHandles = [];
try
if ~using_hg2(fig)
annotationHandles = findall(fig,'Type','hggroup','-and','-property','Units','-and','-not','Units','norm');
try % suggested by Jesús Pestana Puerta (jespestana) 30/9/2015
originalUnits = get(annotationHandles,'Units');
set(annotationHandles,'Units','norm');
catch
end
end
catch
% should never happen, but ignore in any case - issue #50
end
% Fix issue #46: Ghostscript crash if figure units <> pixels
oldFigUnits = get(fig,'Units');
set(fig,'Units','pixels');
% Set to print exactly what is there
if options.invert_hardcopy
try set(fig, 'InvertHardcopy', 'off'); catch, end % fail silently in uifigures
end
% Set the renderer
switch options.renderer
case 1
renderer = '-opengl';
case 2
renderer = '-zbuffer';
case 3
renderer = '-painters';
otherwise
renderer = '-opengl'; % Default for bitmaps
end
hImages = findall(fig,'type','image');
% Handle transparent patches
hasTransparency = ~isempty(findall(fig,'-property','FaceAlpha','-and','-not','FaceAlpha',1));
hasPatches = ~isempty(findall(fig,'type','patch'));
if hasTransparency
% Alert if trying to export transparent patches/areas to non-supported outputs (issue #108)
% http://www.mathworks.com/matlabcentral/answers/265265-can-export_fig-or-else-draw-vector-graphics-with-transparent-surfaces
% TODO - use transparency when exporting to PDF by not passing via print2eps
msg = 'export_fig currently supports transparent patches/areas only in PNG output. ';
if options.pdf
warning('export_fig:transparency', '%s\nTo export transparent patches/areas to PDF, use the print command:\n print(gcf, ''-dpdf'', ''%s.pdf'');', msg, options.name);
elseif ~options.png && ~options.tif % issue #168
warning('export_fig:transparency', '%s\nTo export the transparency correctly, try using the ScreenCapture utility on the Matlab File Exchange: http://bit.ly/1QFrBip', msg);
end
elseif ~isempty(hImages)
% Fix for issue #230: use OpenGL renderer when exported image contains transparency
for idx = 1 : numel(hImages)
cdata = get(hImages(idx),'CData');
if any(isnan(cdata(:)))
hasTransparency = true;
break
end
end
end
try
% Do the bitmap formats first
if isbitmap(options)
if abs(options.bb_padding) > 1
displaySuggestedWorkarounds = false;
error('For bitmap output (png,jpg,tif,bmp) the padding value (-p) must be between -1<p<1')
end
% Get the background colour
if options.transparent && (options.png || options.alpha)
% Get out an alpha channel
% MATLAB "feature": black colorbar axes can change to white and vice versa!
hCB = findall(fig, 'Type','axes', 'Tag','Colorbar');
if isempty(hCB)
yCol = [];
xCol = [];
else
yCol = get(hCB, 'YColor');
xCol = get(hCB, 'XColor');
if iscell(yCol)
yCol = cell2mat(yCol);
xCol = cell2mat(xCol);
end
yCol = sum(yCol, 2);
xCol = sum(xCol, 2);
end
% MATLAB "feature": apparently figure size can change when changing
% colour in -nodisplay mode
pos = get(fig, 'Position');
% Set the background colour to black, and set size in case it was
% changed internally
tcol = get(fig, 'Color');
set(fig, 'Color', 'k', 'Position', pos);
% Correct the colorbar axes colours
set(hCB(yCol==0), 'YColor', [0 0 0]);
set(hCB(xCol==0), 'XColor', [0 0 0]);
% Correct black axes color to off-black (issue #249)
hAxes = findall(fig, 'Type','axes');
hXs = fixBlackAxle(hAxes, 'XColor');
hYs = fixBlackAxle(hAxes, 'YColor');
hZs = fixBlackAxle(hAxes, 'ZColor');
% The following code might cause out-of-memory errors
try
% Print large version to array
B = print2array(fig, magnify, renderer);
% Downscale the image
B = downsize(single(B), options.aa_factor);
catch
% This is more conservative in memory, but kills transparency (issue #58)
B = single(print2array(fig, magnify/options.aa_factor, renderer));
end
% Set background to white (and set size)
set(fig, 'Color', 'w', 'Position', pos);
% Correct the colorbar axes colours
set(hCB(yCol==3), 'YColor', [1 1 1]);
set(hCB(xCol==3), 'XColor', [1 1 1]);
% Revert the black axes colors
set(hXs, 'XColor', [0,0,0]);
set(hYs, 'YColor', [0,0,0]);
set(hZs, 'ZColor', [0,0,0]);
% The following code might cause out-of-memory errors
try
% Print large version to array
A = print2array(fig, magnify, renderer);
% Downscale the image
A = downsize(single(A), options.aa_factor);
catch
% This is more conservative in memory, but kills transparency (issue #58)
A = single(print2array(fig, magnify/options.aa_factor, renderer));
end
% Set the background colour (and size) back to normal
set(fig, 'Color', tcol, 'Position', pos);
% Compute the alpha map
alpha = round(sum(B - A, 3)) / (255 * 3) + 1;
A = alpha;
A(A==0) = 1;
A = B ./ A(:,:,[1 1 1]);
clear B
% Convert to greyscale
if options.colourspace == 2
A = rgb2grey(A);
end
A = uint8(A);
% Crop the background
if options.crop
%[alpha, v] = crop_borders(alpha, 0, 1, options.crop_amounts);
%A = A(v(1):v(2),v(3):v(4),:);
[alpha, vA, vB] = crop_borders(alpha, 0, options.bb_padding, options.crop_amounts);
if ~any(isnan(vB)) % positive padding
B = repmat(uint8(zeros(1,1,size(A,3))),size(alpha));
B(vB(1):vB(2), vB(3):vB(4), :) = A(vA(1):vA(2), vA(3):vA(4), :); % ADDED BY OH
A = B;
else % negative padding
A = A(vA(1):vA(2), vA(3):vA(4), :);
end
end
if options.png
% Compute the resolution
res = options.magnify * get(0, 'ScreenPixelsPerInch') / 25.4e-3;
% Save the png
[format_options, bitDepth] = getFormatOptions(options, 'png'); %Issue #269
if ~isempty(bitDepth) && bitDepth < 16 && size(A,3) == 3
% BitDepth specification requires using a color-map
[A, map] = rgb2ind(A, 256);
imwrite(A, map, [options.name '.png'], 'Alpha',double(alpha), 'ResolutionUnit','meter', 'XResolution',res, 'YResolution',res, format_options{:});
else
imwrite(A, [options.name '.png'], 'Alpha',double(alpha), 'ResolutionUnit','meter', 'XResolution',res, 'YResolution',res, format_options{:});
end
% Clear the png bit
options.png = false;
end
% Return only one channel for greyscale
if isbitmap(options)
A = check_greyscale(A);
end
if options.alpha
% Store the image
imageData = A;
% Clear the alpha bit
options.alpha = false;
end
% Get the non-alpha image
if isbitmap(options)
alph = alpha(:,:,ones(1, size(A, 3)));
A = uint8(single(A) .* alph + 255 * (1 - alph));
clear alph
end
if options.im
% Store the new image
imageData = A;
end
else
% Print large version to array
if options.transparent
% MATLAB "feature": apparently figure size can change when changing
% colour in -nodisplay mode
pos = get(fig, 'Position');
tcol = get(fig, 'Color');
set(fig, 'Color', 'w', 'Position', pos);
A = print2array(fig, magnify, renderer);
set(fig, 'Color', tcol, 'Position', pos);
tcol = 255;
else
[A, tcol] = print2array(fig, magnify, renderer);
end
% Crop the background
if options.crop
A = crop_borders(A, tcol, options.bb_padding, options.crop_amounts);
end
% Downscale the image
A = downsize(A, options.aa_factor);
if options.colourspace == 2
% Convert to greyscale
A = rgb2grey(A);
else
% Return only one channel for greyscale
A = check_greyscale(A);
end
% Outputs
if options.im
imageData = A;
end
if options.alpha
imageData = A;
alpha = ones(size(A, 1), size(A, 2), 'single');
end
end
% Save the images
if options.png
res = options.magnify * get(0, 'ScreenPixelsPerInch') / 25.4e-3;
[format_options, bitDepth] = getFormatOptions(options, 'png'); %Issue #269
if ~isempty(bitDepth) && bitDepth < 16 && size(A,3) == 3
% BitDepth specification requires using a color-map
[A, map] = rgb2ind(A, 256);
imwrite(A, map, [options.name '.png'], 'ResolutionUnit','meter', 'XResolution',res, 'YResolution',res, format_options{:});
else
imwrite(A, [options.name '.png'], 'ResolutionUnit','meter', 'XResolution',res, 'YResolution',res, format_options{:});
end
end
if options.bmp
imwrite(A, [options.name '.bmp']);
end
% Save jpeg with given quality
if options.jpg
quality = options.quality;
if isempty(quality)
quality = 95;
end
format_options = getFormatOptions(options, 'jpg'); %Issue #269
if quality > 100
imwrite(A, [options.name '.jpg'], 'Mode','lossless', format_options{:});
else
imwrite(A, [options.name '.jpg'], 'Quality',quality, format_options{:});
end
end
% Save tif images in cmyk if wanted (and possible)
if options.tif
if options.colourspace == 1 && size(A, 3) == 3
A = double(255 - A);
K = min(A, [], 3);
K_ = 255 ./ max(255 - K, 1);
C = (A(:,:,1) - K) .* K_;
M = (A(:,:,2) - K) .* K_;
Y = (A(:,:,3) - K) .* K_;
A = uint8(cat(3, C, M, Y, K));
clear C M Y K K_
end
append_mode = {'overwrite', 'append'};
format_options = getFormatOptions(options, 'tif'); %Issue #269
imwrite(A, [options.name '.tif'], 'Resolution',options.magnify*get(0,'ScreenPixelsPerInch'), 'WriteMode',append_mode{options.append+1}, format_options{:});
end
end
% Now do the vector formats
if isvector(options)
% Set the default renderer to painters
if ~options.renderer
if hasTransparency || hasPatches
% This is *MUCH* slower, but more accurate for patches and transparent annotations (issue #39)
renderer = '-opengl';
else
renderer = '-painters';
end
end
options.rendererStr = renderer; % fix for issue #112
% Generate some filenames
tmp_nam = [tempname '.eps'];
try
% Ensure that the temp dir is writable (Javier Paredes 30/1/15)
fid = fopen(tmp_nam,'w');
fwrite(fid,1);
fclose(fid);
delete(tmp_nam);
isTempDirOk = true;
catch
% Temp dir is not writable, so use the user-specified folder
[dummy,fname,fext] = fileparts(tmp_nam); %#ok<ASGLU>
fpath = fileparts(options.name);
tmp_nam = fullfile(fpath,[fname fext]);
isTempDirOk = false;
end
if isTempDirOk
pdf_nam_tmp = [tempname '.pdf'];
else
pdf_nam_tmp = fullfile(fpath,[fname '.pdf']);
end
if options.pdf
pdf_nam = [options.name '.pdf'];
try copyfile(pdf_nam, pdf_nam_tmp, 'f'); catch, end % fix for issue #65
else
pdf_nam = pdf_nam_tmp;
end
% Generate the options for print
printArgs = {renderer};
if ~isempty(options.resolution) % issue #241
printArgs{end+1} = sprintf('-r%d', options.resolution);
end
if options.colourspace == 1 % CMYK
% Issue #33: due to internal bugs in Matlab's print() function, we can't use its -cmyk option
%printArgs{end+1} = '-cmyk';
end
if ~options.crop
% Issue #56: due to internal bugs in Matlab's print() function, we can't use its internal cropping mechanism,
% therefore we always use '-loose' (in print2eps.m) and do our own cropping (in crop_borders)
%printArgs{end+1} = '-loose';
end
if any(strcmpi(varargin,'-depsc'))
% Issue #45: lines in image subplots are exported in invalid color.
% The workaround is to use the -depsc parameter instead of the default -depsc2
printArgs{end+1} = '-depsc';
end
try
% Remove background if requested (issue #207)
originalBgColor = get(fig, 'Color');
[hXs, hYs, hZs] = deal([]);
if options.transparent %&& ~isequal(get(fig, 'Color'), 'none')
if options.renderer == 1 % OpenGL
warning('export_fig:openglTransparentBG', '-opengl sometimes fails to produce transparent backgrounds; in such a case, try to use -painters instead');
end
% Fix for issue #207, #267 (corrected)
set(fig,'Color','none');
% Correct black axes color to off-black (issue #249)
hAxes = findall(fig, 'Type','axes');
hXs = fixBlackAxle(hAxes, 'XColor');
hYs = fixBlackAxle(hAxes, 'YColor');
hZs = fixBlackAxle(hAxes, 'ZColor');
end
% Generate an eps
print2eps(tmp_nam, fig, options, printArgs{:});
% {
% Remove the background, if desired
if options.transparent %&& ~isequal(get(fig, 'Color'), 'none')
eps_remove_background(tmp_nam, 1 + using_hg2(fig));
% Revert the black axes colors
set(hXs, 'XColor', [0,0,0]);
set(hYs, 'YColor', [0,0,0]);
set(hZs, 'ZColor', [0,0,0]);
end
%}
% Restore the figure's previous background color (if modified)
try set(fig,'Color',originalBgColor); drawnow; catch, end
% Fix colorspace to CMYK, if requested (workaround for issue #33)
if options.colourspace == 1 % CMYK
% Issue #33: due to internal bugs in Matlab's print() function, we can't use its -cmyk option
change_rgb_to_cmyk(tmp_nam);
end
% Add a bookmark to the PDF if desired
if options.bookmark
fig_nam = get(fig, 'Name');
if isempty(fig_nam)
warning('export_fig:EmptyBookmark', 'Bookmark requested for figure with no name. Bookmark will be empty.');
end
add_bookmark(tmp_nam, fig_nam);
end
% Generate a pdf
eps2pdf(tmp_nam, pdf_nam_tmp, 1, options.append, options.colourspace==2, options.quality, options.gs_options);
% Ghostscript croaks on % chars in the output PDF file, so use tempname and then rename the file
try
% Rename the file (except if it is already the same)
% Abbie K's comment on the commit for issue #179 (#commitcomment-20173476)
if ~isequal(pdf_nam_tmp, pdf_nam)
movefile(pdf_nam_tmp, pdf_nam, 'f');
end
catch
% Alert in case of error creating output PDF/EPS file (issue #179)
if exist(pdf_nam_tmp, 'file')
errMsg = ['Could not create ' pdf_nam ' - perhaps the folder does not exist, or you do not have write permissions, or the file is open in another application'];
error(errMsg);
else
error('Could not generate the intermediary EPS file.');
end
end
catch ex
% Restore the figure's previous background color (in case it was not already restored)
try set(fig,'Color',originalBgColor); drawnow; catch, end
% Delete the eps
delete(tmp_nam);
% Rethrow the EPS/PDF-generation error
rethrow(ex);
end
% Delete the eps
delete(tmp_nam);
if options.eps || options.linecaps
try
% Generate an eps from the pdf
% since pdftops can't handle relative paths (e.g., '..\'), use a temp file
eps_nam_tmp = strrep(pdf_nam_tmp,'.pdf','.eps');
pdf2eps(pdf_nam, eps_nam_tmp);
% Issue #192: enable rounded line-caps
if options.linecaps
fstrm = read_write_entire_textfile(eps_nam_tmp);
fstrm = regexprep(fstrm, '[02] J', '1 J');
read_write_entire_textfile(eps_nam_tmp, fstrm);
if options.pdf
eps2pdf(eps_nam_tmp, pdf_nam, 1, options.append, options.colourspace==2, options.quality, options.gs_options);
end
end
if options.eps
movefile(eps_nam_tmp, [options.name '.eps'], 'f');
else % if options.pdf
try delete(eps_nam_tmp); catch, end
end
catch ex
if ~options.pdf
% Delete the pdf
delete(pdf_nam);
end
try delete(eps_nam_tmp); catch, end
rethrow(ex);
end
if ~options.pdf
% Delete the pdf
delete(pdf_nam);
end
end
% Issue #206: warn if the figure contains an image
if ~isempty(hImages) && strcmpi(renderer,'-opengl') % see addendum to issue #206
warnMsg = ['exporting images to PDF/EPS may result in blurry images on some viewers. ' ...
'If so, try to change viewer, or increase the image''s CData resolution, or use -opengl renderer, or export via the print function. ' ...
'See <a href="matlab:web(''https://github.com/altmany/export_fig/issues/206'',''-browser'');">issue #206</a> for details.'];
warning('export_fig:pdf_eps:blurry_image', warnMsg);
end
end
% SVG format
if options.svg
oldUnits = get(fig,'Units');
filename = [options.name '.svg'];
% Adapted from Dan Joshea's https://github.com/djoshea/matlab-save-figure :
try %if verLessThan('matlab', '8.4')
% Try using the fig2svg/plot2svg utilities
try
fig2svg(filename, fig); %https://github.com/kupiqu/fig2svg
catch
plot2svg(filename, fig); %https://github.com/jschwizer99/plot2svg
warning('export_fig:SVG:plot2svg', 'export_fig used the plot2svg utility for SVG output. Better results may be gotten via the fig2svg utility (https://github.com/kupiqu/fig2svg).');
end
catch %else % (neither fig2svg nor plot2svg are available)
% Try Matlab's built-in svg engine (from Batik Graphics2D for java)
try
set(fig,'Units','pixels'); % All data in the svg-file is saved in pixels
printArgs = {renderer};
if ~isempty(options.resolution)
printArgs{end+1} = sprintf('-r%d', options.resolution);
end
print(fig, '-dsvg', printArgs{:}, filename);
warning('export_fig:SVG:print', 'export_fig used Matlab''s built-in SVG output engine. Better results may be gotten via the fig2svg utility (https://github.com/kupiqu/fig2svg).');
catch err % built-in print() failed - maybe an old Matlab release (no -dsvg)
set(fig,'Units',oldUnits);
filename = strrep(filename,'export_fig_out','filename');
msg = ['SVG output is not supported for your figure: ' err.message '\n' ...
'Try one of the following alternatives:\n' ...
' 1. saveas(gcf,''' filename ''')\n' ...
' 2. fig2svg utility: https://github.com/kupiqu/fig2svg\n' ... % Note: replaced defunct https://github.com/jschwizer99/plot2svg with up-to-date fork on https://github.com/kupiqu/fig2svg
' 3. export_fig to EPS/PDF, then convert to SVG using non-Matlab tools\n'];
error(sprintf(msg)); %#ok<SPERR>
end
end
% SVG output was successful if we reached this point
% Restore original figure units
set(fig,'Units',oldUnits);
% Add warning about unsupported export_fig options with SVG output
if any(~isnan(options.crop_amounts)) || any(options.bb_padding)
warning('export_fig:SVG:options', 'export_fig''s SVG output does not [currently] support cropping/padding.');
end
end
% Revert the figure or close it (if requested)
if cls || options.closeFig
% Close the created figure
close(fig);
else
% Reset the hardcopy mode
try set(fig, 'InvertHardcopy', old_mode); catch, end % fail silently in uifigures
% Reset the axes limit and tick modes
for a = 1:numel(Hlims)
try
set(Hlims(a), 'XLimMode', Xlims{a}, 'YLimMode', Ylims{a}, 'ZLimMode', Zlims{a},...
'XTickMode', Xtick{a}, 'YTickMode', Ytick{a}, 'ZTickMode', Ztick{a},...
'XTickLabelMode', Xlabel{a}, 'YTickLabelMode', Ylabel{a}, 'ZTickLabelMode', Zlabel{a});
catch
% ignore - fix issue #4 (using HG2 on R2014a and earlier)
end
end
% Revert the tex-labels font weights
try set(texLabels, 'FontWeight','bold'); catch, end
% Revert annotation units
for handleIdx = 1 : numel(annotationHandles)
try
oldUnits = originalUnits{handleIdx};
catch
oldUnits = originalUnits;
end
try set(annotationHandles(handleIdx),'Units',oldUnits); catch, end
end
% Revert figure units
set(fig,'Units',oldFigUnits);
end
% Output to clipboard (if requested)
if options.clipboard
% Delete the output file if unchanged from the default name ('export_fig_out.png')
if strcmpi(options.name,'export_fig_out')
try
fileInfo = dir('export_fig_out.png');
if ~isempty(fileInfo)
timediff = now - fileInfo.datenum;
ONE_SEC = 1/24/60/60;
if timediff < ONE_SEC
delete('export_fig_out.png');
end
end
catch
% never mind...
end
end
% Save the image in the system clipboard
% credit: Jiro Doke's IMCLIPBOARD: http://www.mathworks.com/matlabcentral/fileexchange/28708-imclipboard
try
error(javachk('awt', 'export_fig -clipboard output'));
catch
warning('export_fig:clipboardJava', 'export_fig -clipboard output failed: requires Java to work');
return;
end
try
% Import necessary Java classes
import java.awt.Toolkit
import java.awt.image.BufferedImage
import java.awt.datatransfer.DataFlavor
% Get System Clipboard object (java.awt.Toolkit)
cb = Toolkit.getDefaultToolkit.getSystemClipboard();
% Add java class (ImageSelection) to the path
if ~exist('ImageSelection', 'class')
javaaddpath(fileparts(which(mfilename)), '-end');
end
% Get image size
ht = size(imageData, 1);
wd = size(imageData, 2);
% Convert to Blue-Green-Red format
try
imageData2 = imageData(:, :, [3 2 1]);
catch
% Probably gray-scaled image (2D, without the 3rd [RGB] dimension)
imageData2 = imageData(:, :, [1 1 1]);
end
% Convert to 3xWxH format
imageData2 = permute(imageData2, [3, 2, 1]);
% Append Alpha data (unused - transparency is not supported in clipboard copy)
alphaData2 = uint8(permute(255*alpha,[3,2,1])); %=255*ones(1,wd,ht,'uint8')
imageData2 = cat(1, imageData2, alphaData2);
% Create image buffer
imBuffer = BufferedImage(wd, ht, BufferedImage.TYPE_INT_RGB);
imBuffer.setRGB(0, 0, wd, ht, typecast(imageData2(:), 'int32'), 0, wd);
% Create ImageSelection object from the image buffer
imSelection = ImageSelection(imBuffer);
% Set clipboard content to the image
cb.setContents(imSelection, []);
catch
warning('export_fig:clipboardFailed', 'export_fig -clipboard output failed: %s', lasterr); %#ok<LERR>
end
end
% Don't output the data to console unless requested
if ~nargout
clear imageData alpha
end
catch err
% Display possible workarounds before the error message
if displaySuggestedWorkarounds && ~strcmpi(err.message,'export_fig error')
if ~hadError, fprintf(2, 'export_fig error. '); end
fprintf(2, 'Please ensure:\n');
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');
if isvector(options)
if ismac
fprintf(2, ' and that you have <a href="http://pages.uoregon.edu/koch">Ghostscript</a> installed\n');
else
fprintf(2, ' and that you have <a href="http://www.ghostscript.com">Ghostscript</a> installed\n');
end
end
try
if options.eps
fprintf(2, ' and that you have <a href="http://xpdfreader.com/download.html">pdftops</a> installed\n');
end
catch
% ignore - probably an error in parse_args
end
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');
fprintf(2, ' and that you did not made a mistake in the <a href="matlab:help export_fig">expected input arguments</a>\n');
try
% Alert per issue #149
if ~strncmpi(get(0,'Units'),'pixel',5)
fprintf(2, ' or try to set groot''s Units property back to its default value of ''pixels'' (<a href="matlab:web(''https://github.com/altmany/export_fig/issues/149'',''-browser'');">details</a>)\n');
end
catch
% ignore - maybe an old MAtlab release
end
fprintf(2, '\nIf the problem persists, then please <a href="https://github.com/altmany/export_fig/issues">report a new issue</a>.\n\n');
end
rethrow(err)
end
end
function options = default_options()
% Default options used by export_fig
options = struct(...
'name', 'export_fig_out', ...
'crop', true, ...
'crop_amounts', nan(1,4), ... % auto-crop all 4 image sides
'transparent', false, ...
'renderer', 0, ... % 0: default, 1: OpenGL, 2: ZBuffer, 3: Painters
'pdf', false, ...
'eps', false, ...
'svg', false, ...
'png', false, ...
'tif', false, ...
'jpg', false, ...
'bmp', false, ...
'clipboard', false, ...
'colourspace', 0, ... % 0: RGB/gray, 1: CMYK, 2: gray
'append', false, ...
'im', false, ...
'alpha', false, ...
'aa_factor', 0, ...
'bb_padding', 0, ...
'magnify', [], ...
'resolution', [], ...
'bookmark', false, ...
'closeFig', false, ...
'quality', [], ...
'update', false, ...
'fontswap', true, ...
'font_space', '', ...
'linecaps', false, ...
'invert_hardcopy', true, ...
'format_options', struct, ...
'preserve_size', false, ...
'gs_options', {{}});
end
function [fig, options] = parse_args(nout, fig, varargin)
% Parse the input arguments
% Convert strings => chars
varargin = cellfun(@str2char,varargin,'un',false);
% Set the defaults
native = false; % Set resolution to native of an image
options = default_options();
options.im = (nout == 1); % user requested imageData output
options.alpha = (nout == 2); % user requested alpha output
% Go through the other arguments
skipNext = false;
for a = 1:nargin-2
if skipNext
skipNext = false;
continue;
end
if all(ishandle(varargin{a}))
fig = varargin{a};
elseif ischar(varargin{a}) && ~isempty(varargin{a})
if varargin{a}(1) == '-'
switch lower(varargin{a}(2:end))
case 'nocrop'
options.crop = false;
options.crop_amounts = [0,0,0,0];
case {'trans', 'transparent'}
options.transparent = true;
case 'opengl'
options.renderer = 1;
case 'zbuffer'
options.renderer = 2;
case 'painters'
options.renderer = 3;
case 'pdf'
options.pdf = true;
case 'eps'
options.eps = true;
case 'svg'
options.svg = true;
case 'png'
options.png = true;
case {'tif', 'tiff'}
options.tif = true;
case {'jpg', 'jpeg'}
options.jpg = true;
case 'bmp'
options.bmp = true;
case 'rgb'
options.colourspace = 0;
case 'cmyk'
options.colourspace = 1;
case {'gray', 'grey'}
options.colourspace = 2;
case {'a1', 'a2', 'a3', 'a4'}
options.aa_factor = str2double(varargin{a}(3));
case 'append'
options.append = true;
case 'bookmark'
options.bookmark = true;
case 'native'
native = true;
case 'clipboard'
options.clipboard = true;
options.im = true;
options.alpha = true;
case 'update'
% Download the latest version of export_fig into the export_fig folder
try
zipFileName = 'https://github.com/altmany/export_fig/archive/master.zip';
folderName = fileparts(which(mfilename('fullpath')));
targetFileName = fullfile(folderName, datestr(now,'yyyy-mm-dd.zip'));
urlwrite(zipFileName,targetFileName); %#ok<URLWR>
catch
error('Could not download %s into %s\n',zipFileName,targetFileName);
end
% Unzip the downloaded zip file in the export_fig folder
try
unzip(targetFileName,folderName);
catch
error('Could not unzip %s\n',targetFileName);
end
case 'nofontswap'
options.fontswap = false;
case 'font_space'
options.font_space = varargin{a+1};
skipNext = true;
case 'linecaps'
options.linecaps = true;
case 'noinvert'
options.invert_hardcopy = false;
case 'preserve_size'
options.preserve_size = true;
case 'options'
% Issue #269: format-specific options
inputOptions = varargin{a+1};
%options.format_options = inputOptions;
if isempty(inputOptions), continue, end
formats = fieldnames(inputOptions(1));
for idx = 1 : numel(formats)
optionsStruct = inputOptions.(formats{idx});
%optionsCells = [fieldnames(optionsStruct) struct2cell(optionsStruct)]';
formatName = regexprep(lower(formats{idx}),{'tiff','jpeg'},{'tif','jpg'});
options.format_options.(formatName) = optionsStruct; %=optionsCells(:)';
end
skipNext = true;
otherwise
try
wasError = false;
if strcmpi(varargin{a}(1:2),'-d')
varargin{a}(2) = 'd'; % ensure lowercase 'd'
options.gs_options{end+1} = varargin{a};
elseif strcmpi(varargin{a}(1:2),'-c')
if numel(varargin{a})==2
skipNext = true;
vals = str2num(varargin{a+1}); %#ok<ST2NM>
else
vals = str2num(varargin{a}(3:end)); %#ok<ST2NM>
end
if numel(vals)~=4
wasError = true;
error('option -c cannot be parsed: must be a 4-element numeric vector');
end
options.crop_amounts = vals;
options.crop = true;
else % scalar parameter value
val = str2double(regexp(varargin{a}, '(?<=-(m|M|r|R|q|Q|p|P))-?\d*.?\d+', 'match'));
if isempty(val) || isnan(val)
% Issue #51: improved processing of input args (accept space between param name & value)
val = str2double(varargin{a+1});
if isscalar(val) && ~isnan(val)
skipNext = true;
end
end
if ~isscalar(val) || isnan(val)
wasError = true;
error('option %s is not recognised or cannot be parsed', varargin{a});
end
switch lower(varargin{a}(2))
case 'm'
% Magnification may never be negative
if val <= 0
wasError = true;
error('Bad magnification value: %g (must be positive)', val);
end
options.magnify = val;
case 'r'
options.resolution = val;
case 'q'
options.quality = max(val, 0);
case 'p'
options.bb_padding = val;
end
end
catch err
% We might have reached here by raising an intentional error
if wasError % intentional raise
rethrow(err)
else % unintentional
error(['Unrecognized export_fig input option: ''' varargin{a} '''']);
end
end
end
else
[p, options.name, ext] = fileparts(varargin{a});
if ~isempty(p)
% Issue #221: alert if the requested folder does not exist
if ~exist(p,'dir'), error(['Folder ' p ' does not exist!']); end
options.name = [p filesep options.name];
end
switch lower(ext)
case {'.tif', '.tiff'}
options.tif = true;
case {'.jpg', '.jpeg'}
options.jpg = true;
case '.png'
options.png = true;
case '.bmp'
options.bmp = true;
case '.eps'
options.eps = true;
case '.pdf'
options.pdf = true;
case '.fig'
% If no open figure, then load the specified .fig file and continue
if isempty(fig)
fig = openfig(varargin{a},'invisible');
varargin{a} = fig;
options.closeFig = true;
else
% save the current figure as the specified .fig file and exit
saveas(fig(1),varargin{a});
fig = -1;
return
end
case '.svg'
options.svg = true;
otherwise
options.name = varargin{a};
end
end
end
end
% Quick bail-out if no figure found
if isempty(fig), return; end
% Do border padding with repsect to a cropped image
if options.bb_padding
options.crop = true;
end
% Set default anti-aliasing now we know the renderer
if options.aa_factor == 0
try isAA = strcmp(get(ancestor(fig, 'figure'), 'GraphicsSmoothing'), 'on'); catch, isAA = false; end
options.aa_factor = 1 + 2 * (~(using_hg2(fig) && isAA) | (options.renderer == 3));
end
% Convert user dir '~' to full path
if numel(options.name) > 2 && options.name(1) == '~' && (options.name(2) == '/' || options.name(2) == '\')
options.name = fullfile(char(java.lang.System.getProperty('user.home')), options.name(2:end));
end
% Compute the magnification and resolution
if isempty(options.magnify)
if isempty(options.resolution)
options.magnify = 1;
options.resolution = 864;
else
options.magnify = options.resolution ./ get(0, 'ScreenPixelsPerInch');
end
elseif isempty(options.resolution)
options.resolution = 864;
end
% Set the default format
if ~isvector(options) && ~isbitmap(options)
options.png = true;
end
% Check whether transparent background is wanted (old way)
if isequal(get(ancestor(fig(1), 'figure'), 'Color'), 'none')
options.transparent = true;
end
% If requested, set the resolution to the native vertical resolution of the
% first suitable image found
if native
if isbitmap(options)
% Find a suitable image
list = findall(fig, 'Type','image', 'Tag','export_fig_native');
if isempty(list)
list = findall(fig, 'Type','image', 'Visible','on');
end
for hIm = list(:)'
% Check height is >= 2
height = size(get(hIm, 'CData'), 1);
if height < 2
continue
end
% Account for the image filling only part of the axes, or vice versa
yl = get(hIm, 'YData');
if isscalar(yl)
yl = [yl(1)-0.5 yl(1)+height+0.5];
else
yl = [min(yl), max(yl)]; % fix issue #151 (case of yl containing more than 2 elements)
if ~diff(yl)
continue
end
yl = yl + [-0.5 0.5] * (diff(yl) / (height - 1));
end
hAx = get(hIm, 'Parent');
yl2 = get(hAx, 'YLim');
% Find the pixel height of the axes
oldUnits = get(hAx, 'Units');
set(hAx, 'Units', 'pixels');
pos = get(hAx, 'Position');
set(hAx, 'Units', oldUnits);
if ~pos(4)
continue
end
% Found a suitable image
% Account for stretch-to-fill being disabled
pbar = get(hAx, 'PlotBoxAspectRatio');
pos = min(pos(4), pbar(2)*pos(3)/pbar(1));
% Set the magnification to give native resolution
options.magnify = abs((height * diff(yl2)) / (pos * diff(yl))); % magnification must never be negative: issue #103
break
end
elseif options.resolution == 864 % don't use -r864 in vector mode if user asked for -native
options.resolution = []; % issue #241 (internal Matlab bug produces black lines with -r864)
end
end
end
% Convert a possible string => char (issue #245)
function value = str2char(value)
if isa(value,'string')
value = char(value);
end
end
function A = downsize(A, factor)
% Downsample an image
if factor == 1
% Nothing to do
return
end
try
% Faster, but requires image processing toolbox
A = imresize(A, 1/factor, 'bilinear');
catch
% No image processing toolbox - resize manually
% Lowpass filter - use Gaussian as is separable, so faster
% Compute the 1d Gaussian filter
filt = (-factor-1:factor+1) / (factor * 0.6);
filt = exp(-filt .* filt);
% Normalize the filter
filt = single(filt / sum(filt));
% Filter the image
padding = floor(numel(filt) / 2);
for a = 1:size(A, 3)
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');
end
% Subsample
A = A(1+floor(mod(end-1, factor)/2):factor:end,1+floor(mod(end-1, factor)/2):factor:end,:);
end
end
function A = rgb2grey(A)
A = cast(reshape(reshape(single(A), [], 3) * single([0.299; 0.587; 0.114]), size(A, 1), size(A, 2)), class(A)); % #ok<ZEROLIKE>
end
function A = check_greyscale(A)
% Check if the image is greyscale
if size(A, 3) == 3 && ...
all(reshape(A(:,:,1) == A(:,:,2), [], 1)) && ...
all(reshape(A(:,:,2) == A(:,:,3), [], 1))
A = A(:,:,1); % Save only one channel for 8-bit output
end
end
function eps_remove_background(fname, count)
% Remove the background of an eps file
% Open the file
fh = fopen(fname, 'r+');
if fh == -1
error('Not able to open file %s.', fname);
end
% Read the file line by line
while count
% Get the next line
l = fgets(fh);
if isequal(l, -1)
break; % Quit, no rectangle found
end
% Check if the line contains the background rectangle
if isequal(regexp(l, ' *0 +0 +\d+ +\d+ +r[fe] *[\n\r]+', 'start'), 1)
% Set the line to whitespace and quit
l(1:regexp(l, '[\n\r]', 'start', 'once')-1) = ' ';
fseek(fh, -numel(l), 0);
fprintf(fh, l);
% Reduce the count
count = count - 1;
end
end
% Close the file
fclose(fh);
end
function b = isvector(options)
b = options.pdf || options.eps;
end
function b = isbitmap(options)
b = options.png || options.tif || options.jpg || options.bmp || options.im || options.alpha;
end
% Helper function
function A = make_cell(A)
if ~iscell(A)
A = {A};
end
end
function add_bookmark(fname, bookmark_text)
% Adds a bookmark to the temporary EPS file after %%EndPageSetup
% Read in the file
fh = fopen(fname, 'r');
if fh == -1
error('File %s not found.', fname);
end
try
fstrm = fread(fh, '*char')';
catch ex
fclose(fh);
rethrow(ex);
end
fclose(fh);
% Include standard pdfmark prolog to maximize compatibility
fstrm = strrep(fstrm, '%%BeginProlog', sprintf('%%%%BeginProlog\n/pdfmark where {pop} {userdict /pdfmark /cleartomark load put} ifelse'));
% Add page bookmark
fstrm = strrep(fstrm, '%%EndPageSetup', sprintf('%%%%EndPageSetup\n[ /Title (%s) /OUT pdfmark',bookmark_text));
% Write out the updated file
fh = fopen(fname, 'w');
if fh == -1
error('Unable to open %s for writing.', fname);
end
try
fwrite(fh, fstrm, 'char*1');
catch ex
fclose(fh);
rethrow(ex);
end
fclose(fh);
end
function set_tick_mode(Hlims, ax)
% Set the tick mode of linear axes to manual
% Leave log axes alone as these are tricky
M = get(Hlims, [ax 'Scale']);
if ~iscell(M)
M = {M};
end
%idx = cellfun(@(c) strcmp(c, 'linear'), M);
idx = find(strcmp(M,'linear'));
%set(Hlims(idx), [ax 'TickMode'], 'manual'); % issue #187
%set(Hlims(idx), [ax 'TickLabelMode'], 'manual'); % this hides exponent label in HG2!
for idx2 = 1 : numel(idx)
try
% Fix for issue #187 - only set manual ticks when no exponent is present
hAxes = Hlims(idx(idx2));
props = {[ax 'TickMode'],'manual', [ax 'TickLabelMode'],'manual'};
tickVals = get(hAxes,[ax 'Tick']);
tickStrs = get(hAxes,[ax 'TickLabel']);
try % Fix issue #236
exponents = [hAxes.([ax 'Axis']).SecondaryLabel];
catch
exponents = [hAxes.([ax 'Ruler']).SecondaryLabel];
end
if isempty([exponents.String])
% Fix for issue #205 - only set manual ticks when the Ticks number match the TickLabels number
if numel(tickVals) == numel(tickStrs)
set(hAxes, props{:}); % no exponent and matching ticks, so update both ticks and tick labels to manual
end
end
catch % probably HG1
% Fix for issue #220 - exponent is removed in HG1 when TickMode is 'manual' (internal Matlab bug)
if isequal(tickVals, str2num(tickStrs)') %#ok<ST2NM>
set(hAxes, props{:}); % revert back to old behavior
end
end
end
end
function change_rgb_to_cmyk(fname) % convert RGB => CMYK within an EPS file
% Do post-processing on the eps file
try
% Read the EPS file into memory
fstrm = read_write_entire_textfile(fname);
% Replace all gray-scale colors
fstrm = regexprep(fstrm, '\n([\d.]+) +GC\n', '\n0 0 0 ${num2str(1-str2num($1))} CC\n');
% Replace all RGB colors
fstrm = regexprep(fstrm, '\n[0.]+ +[0.]+ +[0.]+ +RC\n', '\n0 0 0 1 CC\n'); % pure black
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');
% Overwrite the file with the modified contents
read_write_entire_textfile(fname, fstrm);
catch
% never mind - leave as is...
end
end
function hBlackAxles = fixBlackAxle(hAxes, axleName)
hBlackAxles = [];
for idx = 1 : numel(hAxes)
ax = hAxes(idx);
axleColor = get(ax, axleName);
if isequal(axleColor,[0,0,0]) || isequal(axleColor,'k')
hBlackAxles(end+1) = ax; %#ok<AGROW>
end
end
set(hBlackAxles, axleName, [0,0,0.01]); % off-black
end
% Issue #269: format-specific options
function [optionsCells, bitDepth] = getFormatOptions(options, formatName)
bitDepth = [];
try
optionsStruct = options.format_options.(lower(formatName));
catch
% User did not specify any extra parameters for this format
optionsCells = {};
return
end
optionNames = fieldnames(optionsStruct);
optionVals = struct2cell(optionsStruct);
optionsCells = [optionNames, optionVals]';
if nargout < 2, return, end % bail out if BitDepth is not required
try
idx = find(strcmpi(optionNames,'BitDepth'), 1, 'last');
if ~isempty(idx)
bitDepth = optionVals{idx};
end
catch
% never mind - ignore
end
end