[24460] | 1 | function [imageData, alpha] = export_fig(varargin) %#ok<*STRCL1>
|
---|
[21315] | 2 | %EXPORT_FIG Exports figures in a publication-quality format
|
---|
[7182] | 3 | %
|
---|
| 4 | % Examples:
|
---|
[21315] | 5 | % imageData = export_fig
|
---|
| 6 | % [imageData, alpha] = export_fig
|
---|
[7182] | 7 | % export_fig filename
|
---|
| 8 | % export_fig filename -format1 -format2
|
---|
| 9 | % export_fig ... -nocrop
|
---|
[21315] | 10 | % export_fig ... -c[<val>,<val>,<val>,<val>]
|
---|
[10635] | 11 | % export_fig ... -transparent
|
---|
[7182] | 12 | % export_fig ... -native
|
---|
| 13 | % export_fig ... -m<val>
|
---|
| 14 | % export_fig ... -r<val>
|
---|
| 15 | % export_fig ... -a<val>
|
---|
| 16 | % export_fig ... -q<val>
|
---|
[18904] | 17 | % export_fig ... -p<val>
|
---|
[21315] | 18 | % export_fig ... -d<gs_option>
|
---|
| 19 | % export_fig ... -depsc
|
---|
[7182] | 20 | % export_fig ... -<renderer>
|
---|
| 21 | % export_fig ... -<colorspace>
|
---|
| 22 | % export_fig ... -append
|
---|
[12407] | 23 | % export_fig ... -bookmark
|
---|
[21315] | 24 | % export_fig ... -clipboard
|
---|
| 25 | % export_fig ... -update
|
---|
| 26 | % export_fig ... -nofontswap
|
---|
[24460] | 27 | % export_fig ... -font_space <char>
|
---|
[21671] | 28 | % export_fig ... -linecaps
|
---|
[24460] | 29 | % export_fig ... -noinvert
|
---|
| 30 | % export_fig ... -preserve_size
|
---|
| 31 | % export_fig ... -options <optionsStruct>
|
---|
[7182] | 32 | % export_fig(..., handle)
|
---|
| 33 | %
|
---|
| 34 | % This function saves a figure or single axes to one or more vector and/or
|
---|
[21315] | 35 | % bitmap file formats, and/or outputs a rasterized version to the workspace,
|
---|
| 36 | % with the following properties:
|
---|
[7182] | 37 | % - Figure/axes reproduced as it appears on screen
|
---|
| 38 | % - Cropped borders (optional)
|
---|
| 39 | % - Embedded fonts (vector formats)
|
---|
| 40 | % - Improved line and grid line styles
|
---|
| 41 | % - Anti-aliased graphics (bitmap formats)
|
---|
| 42 | % - Render images at native resolution (optional for bitmap formats)
|
---|
[21315] | 43 | % - Transparent background supported (pdf, eps, png, tif)
|
---|
[24460] | 44 | % - Semi-transparent patch objects supported (png, tif)
|
---|
| 45 | % - RGB, CMYK or grayscale output (CMYK only with pdf, eps, tif)
|
---|
[7182] | 46 | % - Variable image compression, including lossless (pdf, eps, jpg)
|
---|
[24460] | 47 | % - Optional rounded line-caps (pdf, eps)
|
---|
| 48 | % - Optionally append to file (pdf, tif)
|
---|
| 49 | % - Vector formats: pdf, eps, svg
|
---|
| 50 | % - Bitmap formats: png, tif, jpg, bmp, export to workspace
|
---|
[21315] | 51 | %
|
---|
[7182] | 52 | % This function is especially suited to exporting figures for use in
|
---|
| 53 | % publications and presentations, because of the high quality and
|
---|
| 54 | % portability of media produced.
|
---|
| 55 | %
|
---|
| 56 | % Note that the background color and figure dimensions are reproduced
|
---|
| 57 | % (the latter approximately, and ignoring cropping & magnification) in the
|
---|
| 58 | % output file. For transparent background (and semi-transparent patch
|
---|
[10635] | 59 | % objects), use the -transparent option or set the figure 'Color' property
|
---|
| 60 | % to 'none'. To make axes transparent set the axes 'Color' property to
|
---|
[21315] | 61 | % 'none'. PDF, EPS, TIF & PNG are the only formats that support a transparent
|
---|
| 62 | % background; only TIF & PNG formats support transparency of patch objects.
|
---|
[7182] | 63 | %
|
---|
[24460] | 64 | % The choice of renderer (opengl/zbuffer/painters) has a large impact on the
|
---|
| 65 | % output quality. The default value (opengl for bitmaps, painters for vector
|
---|
| 66 | % formats) generally gives good results, but if you aren't satisfied
|
---|
| 67 | % then try another renderer. Notes:
|
---|
| 68 | % 1) For vector formats (EPS,PDF), only painters generates vector graphics
|
---|
| 69 | % 2) For bitmap formats, only opengl correctly renders transparent patches
|
---|
| 70 | % 3) For bitmap formats, only painters correctly scales line dash and dot
|
---|
| 71 | % lengths when magnifying or anti-aliasing
|
---|
| 72 | % 4) Fonts may be substitued with Courier when using painters
|
---|
[7182] | 73 | %
|
---|
[21315] | 74 | % When exporting to vector format (PDF & EPS) and bitmap format using the
|
---|
[7182] | 75 | % painters renderer, this function requires that ghostscript is installed
|
---|
| 76 | % on your system. You can download this from:
|
---|
| 77 | % http://www.ghostscript.com
|
---|
[24460] | 78 | % When exporting to EPS it additionally requires pdftops, from the Xpdf
|
---|
| 79 | % suite of functions. You can download this from: http://xpdfreader.com
|
---|
[7182] | 80 | %
|
---|
[24460] | 81 | % SVG output uses the fig2svg (https://github.com/kupiqu/fig2svg) or plot2svg
|
---|
| 82 | % (https://github.com/jschwizer99/plot2svg) utilities, or Matlab's built-in
|
---|
| 83 | % SVG export if neither of these utilities are available on Matlab's path.
|
---|
| 84 | % Note: cropping/padding are not supported in export_fig's SVG output.
|
---|
| 85 | %
|
---|
[21315] | 86 | % Inputs:
|
---|
[7182] | 87 | % filename - string containing the name (optionally including full or
|
---|
[24460] | 88 | % relative path) of the file the figure is to be saved as. If
|
---|
| 89 | % a path is not specified, the figure is saved in the current
|
---|
| 90 | % directory. If no name and no output arguments are specified,
|
---|
| 91 | % the default name, 'export_fig_out', is used. If neither a
|
---|
| 92 | % file extension nor a format are specified, a ".png" is added
|
---|
| 93 | % and the figure saved in that format.
|
---|
| 94 | % -<format> - string(s) containing the output file extension(s). Options:
|
---|
| 95 | % '-pdf', '-eps', '-svg', '-png', '-tif', '-jpg' and '-bmp'.
|
---|
| 96 | % Multiple formats can be specified, without restriction.
|
---|
| 97 | % For example: export_fig('-jpg', '-pdf', '-png', ...)
|
---|
| 98 | % Either '-tif','-tiff' can be specified, and either '-jpg','-jpeg'.
|
---|
| 99 | % -nocrop - option indicating that empty margins should not be cropped.
|
---|
[21315] | 100 | % -c[<val>,<val>,<val>,<val>] - option indicating crop amounts. Must be
|
---|
| 101 | % a 4-element vector of numeric values: [top,right,bottom,left]
|
---|
| 102 | % where NaN/Inf indicate auto-cropping, 0 means no cropping,
|
---|
| 103 | % and any other value mean cropping in pixel amounts.
|
---|
[24460] | 104 | % -transparent - option indicating that the figure background is to be made
|
---|
| 105 | % transparent (PNG,PDF,TIF,EPS formats only). Implies -noinvert.
|
---|
[7182] | 106 | % -m<val> - option where val indicates the factor to magnify the
|
---|
[18904] | 107 | % on-screen figure pixel dimensions by when generating bitmap
|
---|
[21315] | 108 | % outputs (does not affect vector formats). Default: '-m1'.
|
---|
[7182] | 109 | % -r<val> - option val indicates the resolution (in pixels per inch) to
|
---|
[18904] | 110 | % export bitmap and vector outputs at, keeping the dimensions
|
---|
| 111 | % of the on-screen figure. Default: '-r864' (for vector output
|
---|
| 112 | % only). Note that the -m option overides the -r option for
|
---|
| 113 | % bitmap outputs only.
|
---|
[7182] | 114 | % -native - option indicating that the output resolution (when outputting
|
---|
| 115 | % a bitmap format) should be such that the vertical resolution
|
---|
| 116 | % of the first suitable image found in the figure is at the
|
---|
| 117 | % native resolution of that image. To specify a particular
|
---|
| 118 | % image to use, give it the tag 'export_fig_native'. Notes:
|
---|
| 119 | % This overrides any value set with the -m and -r options. It
|
---|
| 120 | % also assumes that the image is displayed front-to-parallel
|
---|
| 121 | % with the screen. The output resolution is approximate and
|
---|
| 122 | % should not be relied upon. Anti-aliasing can have adverse
|
---|
| 123 | % effects on image quality (disable with the -a1 option).
|
---|
| 124 | % -a1, -a2, -a3, -a4 - option indicating the amount of anti-aliasing to
|
---|
[24460] | 125 | % use for bitmap outputs. '-a1' means no anti-aliasing;
|
---|
| 126 | % '-a4' is the maximum amount (default).
|
---|
[21315] | 127 | % -<renderer> - option to force a particular renderer (painters, opengl or
|
---|
[24460] | 128 | % zbuffer). Default value: opengl for bitmap formats or
|
---|
| 129 | % figures with patches and/or transparent annotations;
|
---|
| 130 | % painters for vector formats without patches/transparencies.
|
---|
[7182] | 131 | % -<colorspace> - option indicating which colorspace color figures should
|
---|
[24460] | 132 | % be saved in: RGB (default), CMYK or gray. Usage example: '-gray'.
|
---|
| 133 | % Note: CMYK is only supported in PDF, EPS and TIF formats.
|
---|
| 134 | % -q<val> - option to vary bitmap image quality (PDF, EPS, JPG formats only).
|
---|
| 135 | % A larger val, in the range 0-100, produces higher quality and
|
---|
| 136 | % lower compression. val > 100 results in lossless compression.
|
---|
| 137 | % Default: '-q95' for JPG, ghostscript prepress default for PDF,EPS.
|
---|
| 138 | % Note: lossless compression can sometimes give a smaller file size
|
---|
| 139 | % than the default lossy compression, depending on the image type.
|
---|
[21315] | 140 | % -p<val> - option to pad a border of width val to exported files, where
|
---|
| 141 | % val is either a relative size with respect to cropped image
|
---|
| 142 | % size (i.e. p=0.01 adds a 1% border). For EPS & PDF formats,
|
---|
| 143 | % val can also be integer in units of 1/72" points (abs(val)>1).
|
---|
| 144 | % val can be positive (padding) or negative (extra cropping).
|
---|
| 145 | % If used, the -nocrop flag will be ignored, i.e. the image will
|
---|
| 146 | % always be cropped and then padded. Default: 0 (i.e. no padding).
|
---|
[24460] | 147 | % -append - option indicating that if the file already exists the figure is to
|
---|
| 148 | % be appended as a new page, instead of being overwritten (default).
|
---|
| 149 | % PDF & TIF output formats only.
|
---|
[12407] | 150 | % -bookmark - option to indicate that a bookmark with the name of the
|
---|
[24460] | 151 | % figure is to be created in the output file (PDF format only).
|
---|
[21315] | 152 | % -clipboard - option to save output as an image on the system clipboard.
|
---|
[24460] | 153 | % Note: background transparency is not preserved in clipboard
|
---|
[21315] | 154 | % -d<gs_option> - option to indicate a ghostscript setting. For example,
|
---|
[24460] | 155 | % -dMaxBitmap=0 or -dNoOutputFonts (Ghostscript 9.15+).
|
---|
[21315] | 156 | % -depsc - option to use EPS level-3 rather than the default level-2 print
|
---|
| 157 | % device. This solves some bugs with Matlab's default -depsc2 device
|
---|
| 158 | % such as discolored subplot lines on images (vector formats only).
|
---|
| 159 | % -update - option to download and install the latest version of export_fig
|
---|
| 160 | % -nofontswap - option to avoid font swapping. Font swapping is automatically
|
---|
| 161 | % done in vector formats (only): 11 standard Matlab fonts are
|
---|
| 162 | % replaced by the original figure fonts. This option prevents this.
|
---|
[24460] | 163 | % -font_space <char> - option to set a spacer character for font-names that
|
---|
| 164 | % contain spaces, used by EPS/PDF. Default: ''
|
---|
[21671] | 165 | % -linecaps - option to create rounded line-caps (vector formats only).
|
---|
[24460] | 166 | % -noinvert - option to avoid setting figure's InvertHardcopy property to
|
---|
| 167 | % 'off' during output (this solves some problems of empty outputs).
|
---|
| 168 | % -preserve_size - option to preserve the figure's PaperSize property in output
|
---|
| 169 | % file (PDF/EPS formats only; default is to not preserve it).
|
---|
| 170 | % -options <optionsStruct> - format-specific parameters as defined in Matlab's
|
---|
| 171 | % documentation of the imwrite function, contained in a struct under
|
---|
| 172 | % the format name. For example to specify the JPG Comment parameter,
|
---|
| 173 | % pass a struct such as this: options.JPG.Comment='abc'. Similarly,
|
---|
| 174 | % options.PNG.BitDepth=4. Valid only for PNG,TIF,JPG output formats.
|
---|
[21315] | 175 | % handle - The handle of the figure, axes or uipanels (can be an array of
|
---|
[24460] | 176 | % handles, but the objects must be in the same figure) which is
|
---|
| 177 | % to be saved. Default: gcf (handle of current figure).
|
---|
[7182] | 178 | %
|
---|
[21315] | 179 | % Outputs:
|
---|
| 180 | % imageData - MxNxC uint8 image array of the exported image.
|
---|
| 181 | % alpha - MxN single array of alphamatte values in the range [0,1],
|
---|
| 182 | % for the case when the background is transparent.
|
---|
[7182] | 183 | %
|
---|
| 184 | % Some helpful examples and tips can be found at:
|
---|
[21315] | 185 | % https://github.com/altmany/export_fig
|
---|
[7182] | 186 | %
|
---|
[21315] | 187 | % See also PRINT, SAVEAS, ScreenCapture (on the Matlab File Exchange)
|
---|
[7182] | 188 |
|
---|
[21315] | 189 | %{
|
---|
| 190 | % Copyright (C) Oliver Woodford 2008-2014, Yair Altman 2015-
|
---|
[7182] | 191 |
|
---|
| 192 | % The idea of using ghostscript is inspired by Peder Axensten's SAVEFIG
|
---|
| 193 | % (fex id: 10889) which is itself inspired by EPS2PDF (fex id: 5782).
|
---|
| 194 | % The idea for using pdftops came from the MATLAB newsgroup (id: 168171).
|
---|
| 195 | % The idea of editing the EPS file to change line styles comes from Jiro
|
---|
| 196 | % Doke's FIXPSLINESTYLE (fex id: 17928).
|
---|
| 197 | % The idea of changing dash length with line width came from comments on
|
---|
| 198 | % fex id: 5743, but the implementation is mine :)
|
---|
| 199 | % The idea of anti-aliasing bitmaps came from Anders Brun's MYAA (fex id:
|
---|
| 200 | % 20979).
|
---|
| 201 | % The idea of appending figures in pdfs came from Matt C in comments on the
|
---|
| 202 | % FEX (id: 23629)
|
---|
| 203 |
|
---|
| 204 | % Thanks to Roland Martin for pointing out the colour MATLAB
|
---|
| 205 | % bug/feature with colorbar axes and transparent backgrounds.
|
---|
| 206 | % Thanks also to Andrew Matthews for describing a bug to do with the figure
|
---|
| 207 | % size changing in -nodisplay mode. I couldn't reproduce it, but included a
|
---|
| 208 | % fix anyway.
|
---|
| 209 | % Thanks to Tammy Threadgill for reporting a bug where an axes is not
|
---|
| 210 | % isolated from gui objects.
|
---|
[21315] | 211 | %}
|
---|
| 212 | %{
|
---|
[11803] | 213 | % 23/02/12: Ensure that axes limits don't change during printing
|
---|
[21315] | 214 | % 14/03/12: Fix bug in fixing the axes limits (thanks to Tobias Lamour for reporting it).
|
---|
| 215 | % 02/05/12: Incorporate patch of Petr Nechaev (many thanks), enabling bookmarking of figures in pdf files.
|
---|
| 216 | % 09/05/12: Incorporate patch of Arcelia Arrieta (many thanks), to keep tick marks fixed.
|
---|
| 217 | % 12/12/12: Add support for isolating uipanels. Thanks to michael for suggesting it.
|
---|
| 218 | % 25/09/13: Add support for changing resolution in vector formats. Thanks to Jan Jaap Meijer for suggesting it.
|
---|
| 219 | % 07/05/14: Add support for '~' at start of path. Thanks to Sally Warner for suggesting it.
|
---|
| 220 | % 24/02/15: Fix Matlab R2014b bug (issue #34): plot markers are not displayed when ZLimMode='manual'
|
---|
| 221 | % 25/02/15: Fix issue #4 (using HG2 on R2014a and earlier)
|
---|
| 222 | % 25/02/15: Fix issue #21 (bold TeX axes labels/titles in R2014b)
|
---|
| 223 | % 26/02/15: If temp dir is not writable, use the user-specified folder for temporary EPS/PDF files (Javier Paredes)
|
---|
| 224 | % 27/02/15: Modified repository URL from github.com/ojwoodford to /altmany
|
---|
| 225 | % Indented main function
|
---|
| 226 | % Added top-level try-catch block to display useful workarounds
|
---|
| 227 | % 28/02/15: Enable users to specify optional ghostscript options (issue #36)
|
---|
| 228 | % 06/03/15: Improved image padding & cropping thanks to Oscar Hartogensis
|
---|
| 229 | % 26/03/15: Fixed issue #49 (bug with transparent grayscale images); fixed out-of-memory issue
|
---|
| 230 | % 26/03/15: Fixed issue #42: non-normalized annotations on HG1
|
---|
| 231 | % 26/03/15: Fixed issue #46: Ghostscript crash if figure units <> pixels
|
---|
| 232 | % 27/03/15: Fixed issue #39: bad export of transparent annotations/patches
|
---|
| 233 | % 28/03/15: Fixed issue #50: error on some Matlab versions with the fix for issue #42
|
---|
| 234 | % 29/03/15: Fixed issue #33: bugs in Matlab's print() function with -cmyk
|
---|
| 235 | % 29/03/15: Improved processing of input args (accept space between param name & value, related to issue #51)
|
---|
| 236 | % 30/03/15: When exporting *.fig files, then saveas *.fig if figure is open, otherwise export the specified fig file
|
---|
| 237 | % 30/03/15: Fixed edge case bug introduced yesterday (commit #ae1755bd2e11dc4e99b95a7681f6e211b3fa9358)
|
---|
| 238 | % 09/04/15: Consolidated header comment sections; initialize output vars only if requested (nargout>0)
|
---|
| 239 | % 14/04/15: Workaround for issue #45: lines in image subplots are exported in invalid color
|
---|
| 240 | % 15/04/15: Fixed edge-case in parsing input parameters; fixed help section to show the -depsc option (issue #45)
|
---|
| 241 | % 21/04/15: Bug fix: Ghostscript croaks on % chars in output PDF file (reported by Sven on FEX page, 15-Jul-2014)
|
---|
| 242 | % 22/04/15: Bug fix: Pdftops croaks on relative paths (reported by Tintin Milou on FEX page, 19-Jan-2015)
|
---|
| 243 | % 04/05/15: Merged fix #63 (Kevin Mattheus Moerman): prevent tick-label changes during export
|
---|
| 244 | % 07/05/15: Partial fix for issue #65: PDF export used painters rather than opengl renderer (thanks Nguyenr)
|
---|
| 245 | % 08/05/15: Fixed issue #65: bad PDF append since commit #e9f3cdf 21/04/15 (thanks Robert Nguyen)
|
---|
| 246 | % 12/05/15: Fixed issue #67: exponent labels cropped in export, since fix #63 (04/05/15)
|
---|
| 247 | % 28/05/15: Fixed issue #69: set non-bold label font only if the string contains symbols (\beta etc.), followup to issue #21
|
---|
| 248 | % 29/05/15: Added informative error message in case user requested SVG output (issue #72)
|
---|
| 249 | % 09/06/15: Fixed issue #58: -transparent removed anti-aliasing when exporting to PNG
|
---|
| 250 | % 19/06/15: Added -update option to download and install the latest version of export_fig
|
---|
| 251 | % 07/07/15: Added -nofontswap option to avoid font-swapping in EPS/PDF
|
---|
| 252 | % 16/07/15: Fixed problem with anti-aliasing on old Matlab releases
|
---|
| 253 | % 11/09/15: Fixed issue #103: magnification must never become negative; also fixed reported error msg in parsing input params
|
---|
| 254 | % 26/09/15: Alert if trying to export transparent patches/areas to non-PNG outputs (issue #108)
|
---|
| 255 | % 04/10/15: Do not suggest workarounds for certain errors that have already been handled previously
|
---|
[24460] | 256 | % 01/11/15: Fixed issue #112: use same renderer in print2eps as export_fig (thanks to Jesús Pestana Puerta)
|
---|
[21315] | 257 | % 10/11/15: Custom GS installation webpage for MacOS. Thanks to Andy Hueni via FEX
|
---|
| 258 | % 19/11/15: Fixed clipboard export in R2015b (thanks to Dan K via FEX)
|
---|
| 259 | % 21/02/16: Added -c option for indicating specific crop amounts (idea by Cedric Noordam on FEX)
|
---|
| 260 | % 08/05/16: Added message about possible error reason when groot.Units~=pixels (issue #149)
|
---|
| 261 | % 17/05/16: Fixed case of image YData containing more than 2 elements (issue #151)
|
---|
| 262 | % 08/08/16: Enabled exporting transparency to TIF, in addition to PNG/PDF (issue #168)
|
---|
[21671] | 263 | % 11/12/16: Added alert in case of error creating output PDF/EPS file (issue #179)
|
---|
| 264 | % 13/12/16: Minor fix to the commit for issue #179 from 2 days ago
|
---|
| 265 | % 22/03/17: Fixed issue #187: only set manual ticks when no exponent is present
|
---|
| 266 | % 09/04/17: Added -linecaps option (idea by Baron Finer, issue #192)
|
---|
[24460] | 267 | % 15/09/17: Fixed issue #205: incorrect tick-labels when Ticks number don't match the TickLabels number
|
---|
| 268 | % 15/09/17: Fixed issue #210: initialize alpha map to ones instead of zeros when -transparent is not used
|
---|
| 269 | % 18/09/17: Added -font_space option to replace font-name spaces in EPS/PDF (workaround for issue #194)
|
---|
| 270 | % 18/09/17: Added -noinvert option to solve some export problems with some graphic cards (workaround for issue #197)
|
---|
| 271 | % 08/11/17: Fixed issue #220: axes exponent is removed in HG1 when TickMode is 'manual' (internal Matlab bug)
|
---|
| 272 | % 08/11/17: Fixed issue #221: alert if the requested folder does not exist
|
---|
| 273 | % 19/11/17: Workaround for issue #207: alert when trying to use transparent bgcolor with -opengl
|
---|
| 274 | % 29/11/17: Workaround for issue #206: warn if exporting PDF/EPS for a figure that contains an image
|
---|
| 275 | % 11/12/17: Fixed issue #230: use OpenGL renderer when exported image contains transparency (also see issue #206)
|
---|
| 276 | % 30/01/18: Updated SVG message to point to https://github.com/kupiqu/plot2svg and display user-selected filename if available
|
---|
| 277 | % 27/02/18: Fixed issue #236: axes exponent cropped from output if on right-hand axes
|
---|
| 278 | % 29/05/18: Fixed issue #245: process "string" inputs just like 'char' inputs
|
---|
| 279 | % 13/08/18: Fixed issue #249: correct black axes color to off-black to avoid extra cropping with -transparent
|
---|
| 280 | % 27/08/18: Added a possible file-open reason in EPS/PDF write-error message (suggested by "craq" on FEX page)
|
---|
| 281 | % 22/09/18: Xpdf website changed to xpdfreader.com
|
---|
| 282 | % 23/09/18: Fixed issue #243: only set non-bold font (workaround for issue #69) in R2015b or earlier; warn if changing font
|
---|
| 283 | % 23/09/18: Workaround for issue #241: don't use -r864 in EPS/PDF outputs when -native is requested (solves black lines problem)
|
---|
| 284 | % 18/11/18: Issue #261: Added informative alert when trying to export a uifigure (which is not currently supported)
|
---|
| 285 | % 13/12/18: Issue #261: Fixed last commit for cases of specifying axes/panel handle as input, rather than a figure handle
|
---|
| 286 | % 13/01/19: Issue #72: Added basic SVG output support
|
---|
| 287 | % 04/02/19: Workaround for issues #207 and #267: -transparent implies -noinvert
|
---|
| 288 | % 08/03/19: Issue #269: Added ability to specify format-specific options for PNG,TIF,JPG outputs; fixed help section
|
---|
| 289 | % 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)
|
---|
| 290 | % 12/06/19: Issue #277: Enabled preservation of figure's PaperSize in output PDF/EPS file
|
---|
| 291 | % 06/08/19: Remove warning message about obsolete JavaFrame in R2019b
|
---|
| 292 | % 30/10/19: Fixed issue #261: added support for exporting uifigures and uiaxes (thanks to idea by @MarvinILA)
|
---|
[21315] | 293 | %}
|
---|
[11803] | 294 |
|
---|
[21315] | 295 | if nargout
|
---|
| 296 | [imageData, alpha] = deal([]);
|
---|
[14174] | 297 | end
|
---|
[21315] | 298 | hadError = false;
|
---|
| 299 | displaySuggestedWorkarounds = true;
|
---|
| 300 |
|
---|
| 301 | % Ensure the figure is rendered correctly _now_ so that properties like axes limits are up-to-date
|
---|
| 302 | drawnow;
|
---|
| 303 | pause(0.05); % this solves timing issues with Java Swing's EDT (http://undocumentedmatlab.com/blog/solving-a-matlab-hang-problem)
|
---|
| 304 |
|
---|
| 305 | % Parse the input arguments
|
---|
| 306 | fig = get(0, 'CurrentFigure');
|
---|
| 307 | [fig, options] = parse_args(nargout, fig, varargin{:});
|
---|
| 308 |
|
---|
| 309 | % Ensure that we have a figure handle
|
---|
| 310 | if isequal(fig,-1)
|
---|
[24460] | 311 | return % silent bail-out
|
---|
[21315] | 312 | elseif isempty(fig)
|
---|
| 313 | error('No figure found');
|
---|
[24460] | 314 | else
|
---|
| 315 | oldWarn = warning('off','MATLAB:HandleGraphics:ObsoletedProperty:JavaFrame');
|
---|
| 316 | warning off MATLAB:ui:javaframe:PropertyToBeRemoved
|
---|
| 317 | uifig = handle(ancestor(fig,'figure'));
|
---|
| 318 | try jf = get(uifig,'JavaFrame'); catch, jf=1; end
|
---|
| 319 | warning(oldWarn);
|
---|
| 320 | if isempty(jf) % this is a uifigure
|
---|
| 321 | %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.');
|
---|
| 322 | if numel(fig) > 1
|
---|
| 323 | error('export_fig:uifigure:multipleHandles', 'export_fig only supports exporting a single uifigure handle at a time; array of handles is not currently supported.')
|
---|
| 324 | elseif ~any(strcmpi(fig.Type,{'figure','axes'}))
|
---|
| 325 | error('export_fig:uifigure:notFigureOrAxes', 'export_fig only supports exporting a uifigure or uiaxes handle; other handles of a uifigure are not currently supported.')
|
---|
| 326 | end
|
---|
| 327 | % fig is either a uifigure or uiaxes handle
|
---|
| 328 | isUiaxes = strcmpi(fig.Type,'axes');
|
---|
| 329 | if isUiaxes
|
---|
| 330 | % Label the specified axes so that we can find it in the legacy figure
|
---|
| 331 | oldUserData = fig.UserData;
|
---|
| 332 | tempStr = tempname;
|
---|
| 333 | fig.UserData = tempStr;
|
---|
| 334 | end
|
---|
| 335 | try
|
---|
| 336 | % Create an invisible legacy figure at the same position/size as the uifigure
|
---|
| 337 | hNewFig = figure('Units',uifig.Units, 'Position',uifig.Position, 'MenuBar','none', 'ToolBar','none', 'Visible','off');
|
---|
| 338 | % Copy the uifigure contents onto the new invisible legacy figure
|
---|
| 339 | try
|
---|
| 340 | hChildren = allchild(uifig); %=uifig.Children;
|
---|
| 341 | copyobj(hChildren,hNewFig);
|
---|
| 342 | catch
|
---|
| 343 | warning('export_fig:uifigure:controls', 'Some uifigure controls cannot be exported by export_fig and will not appear in the generated output.');
|
---|
| 344 | end
|
---|
| 345 | try fig.UserData = oldUserData; catch, end % restore axes UserData, if modified above
|
---|
| 346 | % Replace the uihandle in the input args with the legacy handle
|
---|
| 347 | if isUiaxes % uiaxes
|
---|
| 348 | % Locate the corresponding axes handle in the new legacy figure
|
---|
| 349 | hAxes = findall(hNewFig,'type','axes','UserData',tempStr);
|
---|
| 350 | if isempty(hAxes) % should never happen, check just in case
|
---|
| 351 | hNewHandle = hNewFig; % export the figure instead of the axes
|
---|
| 352 | else
|
---|
| 353 | hNewHandle = hAxes; % new axes handle found: use it instead of the uiaxes
|
---|
| 354 | end
|
---|
| 355 | else % uifigure
|
---|
| 356 | hNewHandle = hNewFig;
|
---|
| 357 | end
|
---|
| 358 | varargin(cellfun(@(c)isequal(c,fig),varargin)) = {hNewHandle};
|
---|
| 359 | % Rerun export_fig on the legacy figure (with the replaced handle)
|
---|
| 360 | [imageData, alpha] = export_fig(varargin{:});
|
---|
| 361 | % Delete the temp legacy figure and bail out
|
---|
| 362 | try delete(hNewFig); catch, end
|
---|
| 363 | return
|
---|
| 364 | catch err
|
---|
| 365 | % Clean up the temp legacy figure and report the error
|
---|
| 366 | try delete(hNewFig); catch, end
|
---|
| 367 | rethrow(err)
|
---|
| 368 | end
|
---|
| 369 | end
|
---|
[21315] | 370 | end
|
---|
| 371 |
|
---|
| 372 | % Isolate the subplot, if it is one
|
---|
| 373 | cls = all(ismember(get(fig, 'Type'), {'axes', 'uipanel'}));
|
---|
| 374 | if cls
|
---|
| 375 | % Given handles of one or more axes, so isolate them from the rest
|
---|
| 376 | fig = isolate_axes(fig);
|
---|
| 377 | else
|
---|
| 378 | % Check we have a figure
|
---|
[21671] | 379 | if ~isequal(get(fig, 'Type'), 'figure')
|
---|
[21315] | 380 | error('Handle must be that of a figure, axes or uipanel');
|
---|
[7182] | 381 | end
|
---|
[21315] | 382 | % Get the old InvertHardcopy mode
|
---|
| 383 | old_mode = get(fig, 'InvertHardcopy');
|
---|
[7182] | 384 | end
|
---|
[21315] | 385 |
|
---|
| 386 | % Hack the font units where necessary (due to a font rendering bug in print?).
|
---|
| 387 | % This may not work perfectly in all cases.
|
---|
| 388 | % Also it can change the figure layout if reverted, so use a copy.
|
---|
| 389 | magnify = options.magnify * options.aa_factor;
|
---|
| 390 | if isbitmap(options) && magnify ~= 1
|
---|
| 391 | fontu = findall(fig, 'FontUnits', 'normalized');
|
---|
| 392 | if ~isempty(fontu)
|
---|
| 393 | % Some normalized font units found
|
---|
| 394 | if ~cls
|
---|
| 395 | fig = copyfig(fig);
|
---|
| 396 | set(fig, 'Visible', 'off');
|
---|
| 397 | fontu = findall(fig, 'FontUnits', 'normalized');
|
---|
| 398 | cls = true;
|
---|
[7182] | 399 | end
|
---|
[21315] | 400 | set(fontu, 'FontUnits', 'points');
|
---|
[7182] | 401 | end
|
---|
| 402 | end
|
---|
[21315] | 403 |
|
---|
| 404 | try
|
---|
| 405 | % MATLAB "feature": axes limits and tick marks can change when printing
|
---|
| 406 | Hlims = findall(fig, 'Type', 'axes');
|
---|
| 407 | if ~cls
|
---|
| 408 | % Record the old axes limit and tick modes
|
---|
| 409 | Xlims = make_cell(get(Hlims, 'XLimMode'));
|
---|
| 410 | Ylims = make_cell(get(Hlims, 'YLimMode'));
|
---|
| 411 | Zlims = make_cell(get(Hlims, 'ZLimMode'));
|
---|
| 412 | Xtick = make_cell(get(Hlims, 'XTickMode'));
|
---|
| 413 | Ytick = make_cell(get(Hlims, 'YTickMode'));
|
---|
| 414 | Ztick = make_cell(get(Hlims, 'ZTickMode'));
|
---|
| 415 | Xlabel = make_cell(get(Hlims, 'XTickLabelMode'));
|
---|
| 416 | Ylabel = make_cell(get(Hlims, 'YTickLabelMode'));
|
---|
| 417 | Zlabel = make_cell(get(Hlims, 'ZTickLabelMode'));
|
---|
[7182] | 418 | end
|
---|
[21315] | 419 |
|
---|
| 420 | % Set all axes limit and tick modes to manual, so the limits and ticks can't change
|
---|
| 421 | % Fix Matlab R2014b bug (issue #34): plot markers are not displayed when ZLimMode='manual'
|
---|
| 422 | set(Hlims, 'XLimMode', 'manual', 'YLimMode', 'manual');
|
---|
| 423 | set_tick_mode(Hlims, 'X');
|
---|
| 424 | set_tick_mode(Hlims, 'Y');
|
---|
| 425 | if ~using_hg2(fig)
|
---|
| 426 | set(Hlims,'ZLimMode', 'manual');
|
---|
| 427 | set_tick_mode(Hlims, 'Z');
|
---|
[19993] | 428 | end
|
---|
[21315] | 429 | catch
|
---|
| 430 | % ignore - fix issue #4 (using HG2 on R2014a and earlier)
|
---|
[7182] | 431 | end
|
---|
[21315] | 432 |
|
---|
| 433 | % Fix issue #21 (bold TeX axes labels/titles in R2014b when exporting to EPS/PDF)
|
---|
| 434 | try
|
---|
| 435 | if using_hg2(fig) && isvector(options)
|
---|
| 436 | % Set the FontWeight of axes labels/titles to 'normal'
|
---|
| 437 | % Fix issue #69: set non-bold font only if the string contains symbols (\beta etc.)
|
---|
[24460] | 438 | % Issue #243: only set non-bold font (workaround for issue #69) in R2015b or earlier
|
---|
| 439 | try isPreR2016a = verLessThan('matlab','8.7'); catch, isPreR2016a = true; end
|
---|
| 440 | if isPreR2016a
|
---|
| 441 | texLabels = findall(fig, 'type','text', 'FontWeight','bold');
|
---|
| 442 | symbolIdx = ~cellfun('isempty',strfind({texLabels.String},'\'));
|
---|
| 443 | if ~isempty(symbolIdx)
|
---|
| 444 | set(texLabels(symbolIdx), 'FontWeight','normal');
|
---|
| 445 | warning('export_fig:BoldTexLabels', 'Bold labels with Tex symbols converted into non-bold in export_fig (fix for issue #69)');
|
---|
| 446 | end
|
---|
| 447 | end
|
---|
[7182] | 448 | end
|
---|
[21315] | 449 | catch
|
---|
| 450 | % ignore
|
---|
[7182] | 451 | end
|
---|
[21315] | 452 |
|
---|
| 453 | % Fix issue #42: non-normalized annotations on HG1 (internal Matlab bug)
|
---|
| 454 | annotationHandles = [];
|
---|
[7182] | 455 | try
|
---|
[21315] | 456 | if ~using_hg2(fig)
|
---|
| 457 | annotationHandles = findall(fig,'Type','hggroup','-and','-property','Units','-and','-not','Units','norm');
|
---|
[24460] | 458 | try % suggested by Jesús Pestana Puerta (jespestana) 30/9/2015
|
---|
[21315] | 459 | originalUnits = get(annotationHandles,'Units');
|
---|
| 460 | set(annotationHandles,'Units','norm');
|
---|
| 461 | catch
|
---|
[12407] | 462 | end
|
---|
[19993] | 463 | end
|
---|
[21315] | 464 | catch
|
---|
| 465 | % should never happen, but ignore in any case - issue #50
|
---|
[19993] | 466 | end
|
---|
[21315] | 467 |
|
---|
| 468 | % Fix issue #46: Ghostscript crash if figure units <> pixels
|
---|
| 469 | oldFigUnits = get(fig,'Units');
|
---|
| 470 | set(fig,'Units','pixels');
|
---|
| 471 |
|
---|
| 472 | % Set to print exactly what is there
|
---|
[24460] | 473 | if options.invert_hardcopy
|
---|
| 474 | try set(fig, 'InvertHardcopy', 'off'); catch, end % fail silently in uifigures
|
---|
| 475 | end
|
---|
| 476 |
|
---|
[21315] | 477 | % Set the renderer
|
---|
| 478 | switch options.renderer
|
---|
| 479 | case 1
|
---|
| 480 | renderer = '-opengl';
|
---|
| 481 | case 2
|
---|
| 482 | renderer = '-zbuffer';
|
---|
| 483 | case 3
|
---|
| 484 | renderer = '-painters';
|
---|
| 485 | otherwise
|
---|
| 486 | renderer = '-opengl'; % Default for bitmaps
|
---|
| 487 | end
|
---|
| 488 |
|
---|
[24460] | 489 | hImages = findall(fig,'type','image');
|
---|
| 490 |
|
---|
[21315] | 491 | % Handle transparent patches
|
---|
| 492 | hasTransparency = ~isempty(findall(fig,'-property','FaceAlpha','-and','-not','FaceAlpha',1));
|
---|
| 493 | hasPatches = ~isempty(findall(fig,'type','patch'));
|
---|
| 494 | if hasTransparency
|
---|
| 495 | % Alert if trying to export transparent patches/areas to non-supported outputs (issue #108)
|
---|
| 496 | % http://www.mathworks.com/matlabcentral/answers/265265-can-export_fig-or-else-draw-vector-graphics-with-transparent-surfaces
|
---|
| 497 | % TODO - use transparency when exporting to PDF by not passing via print2eps
|
---|
| 498 | msg = 'export_fig currently supports transparent patches/areas only in PNG output. ';
|
---|
| 499 | if options.pdf
|
---|
| 500 | 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);
|
---|
| 501 | elseif ~options.png && ~options.tif % issue #168
|
---|
| 502 | 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);
|
---|
[7182] | 503 | end
|
---|
[24460] | 504 | elseif ~isempty(hImages)
|
---|
| 505 | % Fix for issue #230: use OpenGL renderer when exported image contains transparency
|
---|
| 506 | for idx = 1 : numel(hImages)
|
---|
| 507 | cdata = get(hImages(idx),'CData');
|
---|
| 508 | if any(isnan(cdata(:)))
|
---|
| 509 | hasTransparency = true;
|
---|
| 510 | break
|
---|
| 511 | end
|
---|
| 512 | end
|
---|
[19993] | 513 | end
|
---|
[7182] | 514 |
|
---|
[21315] | 515 | try
|
---|
| 516 | % Do the bitmap formats first
|
---|
| 517 | if isbitmap(options)
|
---|
| 518 | if abs(options.bb_padding) > 1
|
---|
| 519 | displaySuggestedWorkarounds = false;
|
---|
| 520 | error('For bitmap output (png,jpg,tif,bmp) the padding value (-p) must be between -1<p<1')
|
---|
| 521 | end
|
---|
| 522 | % Get the background colour
|
---|
| 523 | if options.transparent && (options.png || options.alpha)
|
---|
| 524 | % Get out an alpha channel
|
---|
| 525 | % MATLAB "feature": black colorbar axes can change to white and vice versa!
|
---|
| 526 | hCB = findall(fig, 'Type','axes', 'Tag','Colorbar');
|
---|
| 527 | if isempty(hCB)
|
---|
| 528 | yCol = [];
|
---|
| 529 | xCol = [];
|
---|
| 530 | else
|
---|
| 531 | yCol = get(hCB, 'YColor');
|
---|
| 532 | xCol = get(hCB, 'XColor');
|
---|
| 533 | if iscell(yCol)
|
---|
| 534 | yCol = cell2mat(yCol);
|
---|
| 535 | xCol = cell2mat(xCol);
|
---|
| 536 | end
|
---|
| 537 | yCol = sum(yCol, 2);
|
---|
| 538 | xCol = sum(xCol, 2);
|
---|
| 539 | end
|
---|
| 540 | % MATLAB "feature": apparently figure size can change when changing
|
---|
| 541 | % colour in -nodisplay mode
|
---|
| 542 | pos = get(fig, 'Position');
|
---|
| 543 | % Set the background colour to black, and set size in case it was
|
---|
| 544 | % changed internally
|
---|
| 545 | tcol = get(fig, 'Color');
|
---|
| 546 | set(fig, 'Color', 'k', 'Position', pos);
|
---|
| 547 | % Correct the colorbar axes colours
|
---|
| 548 | set(hCB(yCol==0), 'YColor', [0 0 0]);
|
---|
| 549 | set(hCB(xCol==0), 'XColor', [0 0 0]);
|
---|
[24460] | 550 | % Correct black axes color to off-black (issue #249)
|
---|
| 551 | hAxes = findall(fig, 'Type','axes');
|
---|
| 552 | hXs = fixBlackAxle(hAxes, 'XColor');
|
---|
| 553 | hYs = fixBlackAxle(hAxes, 'YColor');
|
---|
| 554 | hZs = fixBlackAxle(hAxes, 'ZColor');
|
---|
[19993] | 555 |
|
---|
[21315] | 556 | % The following code might cause out-of-memory errors
|
---|
| 557 | try
|
---|
| 558 | % Print large version to array
|
---|
| 559 | B = print2array(fig, magnify, renderer);
|
---|
| 560 | % Downscale the image
|
---|
| 561 | B = downsize(single(B), options.aa_factor);
|
---|
| 562 | catch
|
---|
| 563 | % This is more conservative in memory, but kills transparency (issue #58)
|
---|
| 564 | B = single(print2array(fig, magnify/options.aa_factor, renderer));
|
---|
| 565 | end
|
---|
| 566 |
|
---|
| 567 | % Set background to white (and set size)
|
---|
| 568 | set(fig, 'Color', 'w', 'Position', pos);
|
---|
| 569 | % Correct the colorbar axes colours
|
---|
| 570 | set(hCB(yCol==3), 'YColor', [1 1 1]);
|
---|
| 571 | set(hCB(xCol==3), 'XColor', [1 1 1]);
|
---|
[24460] | 572 | % Revert the black axes colors
|
---|
| 573 | set(hXs, 'XColor', [0,0,0]);
|
---|
| 574 | set(hYs, 'YColor', [0,0,0]);
|
---|
| 575 | set(hZs, 'ZColor', [0,0,0]);
|
---|
[21315] | 576 |
|
---|
| 577 | % The following code might cause out-of-memory errors
|
---|
| 578 | try
|
---|
| 579 | % Print large version to array
|
---|
| 580 | A = print2array(fig, magnify, renderer);
|
---|
| 581 | % Downscale the image
|
---|
| 582 | A = downsize(single(A), options.aa_factor);
|
---|
| 583 | catch
|
---|
| 584 | % This is more conservative in memory, but kills transparency (issue #58)
|
---|
| 585 | A = single(print2array(fig, magnify/options.aa_factor, renderer));
|
---|
| 586 | end
|
---|
| 587 |
|
---|
| 588 | % Set the background colour (and size) back to normal
|
---|
| 589 | set(fig, 'Color', tcol, 'Position', pos);
|
---|
| 590 | % Compute the alpha map
|
---|
| 591 | alpha = round(sum(B - A, 3)) / (255 * 3) + 1;
|
---|
| 592 | A = alpha;
|
---|
| 593 | A(A==0) = 1;
|
---|
| 594 | A = B ./ A(:,:,[1 1 1]);
|
---|
| 595 | clear B
|
---|
| 596 | % Convert to greyscale
|
---|
| 597 | if options.colourspace == 2
|
---|
| 598 | A = rgb2grey(A);
|
---|
| 599 | end
|
---|
| 600 | A = uint8(A);
|
---|
| 601 | % Crop the background
|
---|
| 602 | if options.crop
|
---|
| 603 | %[alpha, v] = crop_borders(alpha, 0, 1, options.crop_amounts);
|
---|
| 604 | %A = A(v(1):v(2),v(3):v(4),:);
|
---|
| 605 | [alpha, vA, vB] = crop_borders(alpha, 0, options.bb_padding, options.crop_amounts);
|
---|
| 606 | if ~any(isnan(vB)) % positive padding
|
---|
| 607 | B = repmat(uint8(zeros(1,1,size(A,3))),size(alpha));
|
---|
| 608 | B(vB(1):vB(2), vB(3):vB(4), :) = A(vA(1):vA(2), vA(3):vA(4), :); % ADDED BY OH
|
---|
| 609 | A = B;
|
---|
| 610 | else % negative padding
|
---|
| 611 | A = A(vA(1):vA(2), vA(3):vA(4), :);
|
---|
[7182] | 612 | end
|
---|
[21315] | 613 | end
|
---|
| 614 | if options.png
|
---|
| 615 | % Compute the resolution
|
---|
| 616 | res = options.magnify * get(0, 'ScreenPixelsPerInch') / 25.4e-3;
|
---|
| 617 | % Save the png
|
---|
[24460] | 618 | [format_options, bitDepth] = getFormatOptions(options, 'png'); %Issue #269
|
---|
| 619 | if ~isempty(bitDepth) && bitDepth < 16 && size(A,3) == 3
|
---|
| 620 | % BitDepth specification requires using a color-map
|
---|
| 621 | [A, map] = rgb2ind(A, 256);
|
---|
| 622 | imwrite(A, map, [options.name '.png'], 'Alpha',double(alpha), 'ResolutionUnit','meter', 'XResolution',res, 'YResolution',res, format_options{:});
|
---|
| 623 | else
|
---|
| 624 | imwrite(A, [options.name '.png'], 'Alpha',double(alpha), 'ResolutionUnit','meter', 'XResolution',res, 'YResolution',res, format_options{:});
|
---|
| 625 | end
|
---|
[21315] | 626 | % Clear the png bit
|
---|
| 627 | options.png = false;
|
---|
| 628 | end
|
---|
| 629 | % Return only one channel for greyscale
|
---|
| 630 | if isbitmap(options)
|
---|
| 631 | A = check_greyscale(A);
|
---|
| 632 | end
|
---|
| 633 | if options.alpha
|
---|
| 634 | % Store the image
|
---|
| 635 | imageData = A;
|
---|
| 636 | % Clear the alpha bit
|
---|
| 637 | options.alpha = false;
|
---|
| 638 | end
|
---|
| 639 | % Get the non-alpha image
|
---|
| 640 | if isbitmap(options)
|
---|
| 641 | alph = alpha(:,:,ones(1, size(A, 3)));
|
---|
| 642 | A = uint8(single(A) .* alph + 255 * (1 - alph));
|
---|
| 643 | clear alph
|
---|
| 644 | end
|
---|
| 645 | if options.im
|
---|
| 646 | % Store the new image
|
---|
| 647 | imageData = A;
|
---|
| 648 | end
|
---|
| 649 | else
|
---|
| 650 | % Print large version to array
|
---|
| 651 | if options.transparent
|
---|
| 652 | % MATLAB "feature": apparently figure size can change when changing
|
---|
| 653 | % colour in -nodisplay mode
|
---|
| 654 | pos = get(fig, 'Position');
|
---|
| 655 | tcol = get(fig, 'Color');
|
---|
| 656 | set(fig, 'Color', 'w', 'Position', pos);
|
---|
| 657 | A = print2array(fig, magnify, renderer);
|
---|
| 658 | set(fig, 'Color', tcol, 'Position', pos);
|
---|
| 659 | tcol = 255;
|
---|
| 660 | else
|
---|
| 661 | [A, tcol] = print2array(fig, magnify, renderer);
|
---|
| 662 | end
|
---|
| 663 | % Crop the background
|
---|
| 664 | if options.crop
|
---|
| 665 | A = crop_borders(A, tcol, options.bb_padding, options.crop_amounts);
|
---|
| 666 | end
|
---|
| 667 | % Downscale the image
|
---|
| 668 | A = downsize(A, options.aa_factor);
|
---|
| 669 | if options.colourspace == 2
|
---|
| 670 | % Convert to greyscale
|
---|
| 671 | A = rgb2grey(A);
|
---|
| 672 | else
|
---|
| 673 | % Return only one channel for greyscale
|
---|
| 674 | A = check_greyscale(A);
|
---|
| 675 | end
|
---|
| 676 | % Outputs
|
---|
| 677 | if options.im
|
---|
| 678 | imageData = A;
|
---|
| 679 | end
|
---|
| 680 | if options.alpha
|
---|
| 681 | imageData = A;
|
---|
[24460] | 682 | alpha = ones(size(A, 1), size(A, 2), 'single');
|
---|
[21315] | 683 | end
|
---|
| 684 | end
|
---|
| 685 | % Save the images
|
---|
| 686 | if options.png
|
---|
| 687 | res = options.magnify * get(0, 'ScreenPixelsPerInch') / 25.4e-3;
|
---|
[24460] | 688 | [format_options, bitDepth] = getFormatOptions(options, 'png'); %Issue #269
|
---|
| 689 | if ~isempty(bitDepth) && bitDepth < 16 && size(A,3) == 3
|
---|
| 690 | % BitDepth specification requires using a color-map
|
---|
| 691 | [A, map] = rgb2ind(A, 256);
|
---|
| 692 | imwrite(A, map, [options.name '.png'], 'ResolutionUnit','meter', 'XResolution',res, 'YResolution',res, format_options{:});
|
---|
| 693 | else
|
---|
| 694 | imwrite(A, [options.name '.png'], 'ResolutionUnit','meter', 'XResolution',res, 'YResolution',res, format_options{:});
|
---|
| 695 | end
|
---|
[21315] | 696 | end
|
---|
| 697 | if options.bmp
|
---|
| 698 | imwrite(A, [options.name '.bmp']);
|
---|
| 699 | end
|
---|
| 700 | % Save jpeg with given quality
|
---|
| 701 | if options.jpg
|
---|
| 702 | quality = options.quality;
|
---|
| 703 | if isempty(quality)
|
---|
| 704 | quality = 95;
|
---|
| 705 | end
|
---|
[24460] | 706 | format_options = getFormatOptions(options, 'jpg'); %Issue #269
|
---|
[21315] | 707 | if quality > 100
|
---|
[24460] | 708 | imwrite(A, [options.name '.jpg'], 'Mode','lossless', format_options{:});
|
---|
[21315] | 709 | else
|
---|
[24460] | 710 | imwrite(A, [options.name '.jpg'], 'Quality',quality, format_options{:});
|
---|
[21315] | 711 | end
|
---|
| 712 | end
|
---|
| 713 | % Save tif images in cmyk if wanted (and possible)
|
---|
| 714 | if options.tif
|
---|
| 715 | if options.colourspace == 1 && size(A, 3) == 3
|
---|
| 716 | A = double(255 - A);
|
---|
| 717 | K = min(A, [], 3);
|
---|
| 718 | K_ = 255 ./ max(255 - K, 1);
|
---|
| 719 | C = (A(:,:,1) - K) .* K_;
|
---|
| 720 | M = (A(:,:,2) - K) .* K_;
|
---|
| 721 | Y = (A(:,:,3) - K) .* K_;
|
---|
| 722 | A = uint8(cat(3, C, M, Y, K));
|
---|
| 723 | clear C M Y K K_
|
---|
| 724 | end
|
---|
| 725 | append_mode = {'overwrite', 'append'};
|
---|
[24460] | 726 | format_options = getFormatOptions(options, 'tif'); %Issue #269
|
---|
| 727 | imwrite(A, [options.name '.tif'], 'Resolution',options.magnify*get(0,'ScreenPixelsPerInch'), 'WriteMode',append_mode{options.append+1}, format_options{:});
|
---|
[21315] | 728 | end
|
---|
| 729 | end
|
---|
| 730 |
|
---|
| 731 | % Now do the vector formats
|
---|
| 732 | if isvector(options)
|
---|
| 733 | % Set the default renderer to painters
|
---|
| 734 | if ~options.renderer
|
---|
| 735 | if hasTransparency || hasPatches
|
---|
| 736 | % This is *MUCH* slower, but more accurate for patches and transparent annotations (issue #39)
|
---|
[24460] | 737 | renderer = '-opengl';
|
---|
[21315] | 738 | else
|
---|
| 739 | renderer = '-painters';
|
---|
| 740 | end
|
---|
| 741 | end
|
---|
| 742 | options.rendererStr = renderer; % fix for issue #112
|
---|
| 743 | % Generate some filenames
|
---|
| 744 | tmp_nam = [tempname '.eps'];
|
---|
| 745 | try
|
---|
| 746 | % Ensure that the temp dir is writable (Javier Paredes 30/1/15)
|
---|
| 747 | fid = fopen(tmp_nam,'w');
|
---|
| 748 | fwrite(fid,1);
|
---|
| 749 | fclose(fid);
|
---|
| 750 | delete(tmp_nam);
|
---|
| 751 | isTempDirOk = true;
|
---|
| 752 | catch
|
---|
| 753 | % Temp dir is not writable, so use the user-specified folder
|
---|
| 754 | [dummy,fname,fext] = fileparts(tmp_nam); %#ok<ASGLU>
|
---|
| 755 | fpath = fileparts(options.name);
|
---|
| 756 | tmp_nam = fullfile(fpath,[fname fext]);
|
---|
| 757 | isTempDirOk = false;
|
---|
| 758 | end
|
---|
| 759 | if isTempDirOk
|
---|
| 760 | pdf_nam_tmp = [tempname '.pdf'];
|
---|
| 761 | else
|
---|
| 762 | pdf_nam_tmp = fullfile(fpath,[fname '.pdf']);
|
---|
| 763 | end
|
---|
| 764 | if options.pdf
|
---|
| 765 | pdf_nam = [options.name '.pdf'];
|
---|
| 766 | try copyfile(pdf_nam, pdf_nam_tmp, 'f'); catch, end % fix for issue #65
|
---|
| 767 | else
|
---|
| 768 | pdf_nam = pdf_nam_tmp;
|
---|
| 769 | end
|
---|
| 770 | % Generate the options for print
|
---|
[24460] | 771 | printArgs = {renderer};
|
---|
| 772 | if ~isempty(options.resolution) % issue #241
|
---|
| 773 | printArgs{end+1} = sprintf('-r%d', options.resolution);
|
---|
| 774 | end
|
---|
[21315] | 775 | if options.colourspace == 1 % CMYK
|
---|
| 776 | % Issue #33: due to internal bugs in Matlab's print() function, we can't use its -cmyk option
|
---|
[24460] | 777 | %printArgs{end+1} = '-cmyk';
|
---|
[21315] | 778 | end
|
---|
| 779 | if ~options.crop
|
---|
| 780 | % Issue #56: due to internal bugs in Matlab's print() function, we can't use its internal cropping mechanism,
|
---|
| 781 | % therefore we always use '-loose' (in print2eps.m) and do our own cropping (in crop_borders)
|
---|
[24460] | 782 | %printArgs{end+1} = '-loose';
|
---|
[21315] | 783 | end
|
---|
| 784 | if any(strcmpi(varargin,'-depsc'))
|
---|
| 785 | % Issue #45: lines in image subplots are exported in invalid color.
|
---|
| 786 | % The workaround is to use the -depsc parameter instead of the default -depsc2
|
---|
[24460] | 787 | printArgs{end+1} = '-depsc';
|
---|
[21315] | 788 | end
|
---|
| 789 | try
|
---|
[24460] | 790 | % Remove background if requested (issue #207)
|
---|
| 791 | originalBgColor = get(fig, 'Color');
|
---|
| 792 | [hXs, hYs, hZs] = deal([]);
|
---|
| 793 | if options.transparent %&& ~isequal(get(fig, 'Color'), 'none')
|
---|
| 794 | if options.renderer == 1 % OpenGL
|
---|
| 795 | warning('export_fig:openglTransparentBG', '-opengl sometimes fails to produce transparent backgrounds; in such a case, try to use -painters instead');
|
---|
| 796 | end
|
---|
| 797 |
|
---|
| 798 | % Fix for issue #207, #267 (corrected)
|
---|
| 799 | set(fig,'Color','none');
|
---|
| 800 |
|
---|
| 801 | % Correct black axes color to off-black (issue #249)
|
---|
| 802 | hAxes = findall(fig, 'Type','axes');
|
---|
| 803 | hXs = fixBlackAxle(hAxes, 'XColor');
|
---|
| 804 | hYs = fixBlackAxle(hAxes, 'YColor');
|
---|
| 805 | hZs = fixBlackAxle(hAxes, 'ZColor');
|
---|
| 806 | end
|
---|
[21315] | 807 | % Generate an eps
|
---|
[24460] | 808 | print2eps(tmp_nam, fig, options, printArgs{:});
|
---|
| 809 | % {
|
---|
[21315] | 810 | % Remove the background, if desired
|
---|
[24460] | 811 | if options.transparent %&& ~isequal(get(fig, 'Color'), 'none')
|
---|
[21315] | 812 | eps_remove_background(tmp_nam, 1 + using_hg2(fig));
|
---|
[24460] | 813 |
|
---|
| 814 | % Revert the black axes colors
|
---|
| 815 | set(hXs, 'XColor', [0,0,0]);
|
---|
| 816 | set(hYs, 'YColor', [0,0,0]);
|
---|
| 817 | set(hZs, 'ZColor', [0,0,0]);
|
---|
[21315] | 818 | end
|
---|
[24460] | 819 | %}
|
---|
| 820 | % Restore the figure's previous background color (if modified)
|
---|
| 821 | try set(fig,'Color',originalBgColor); drawnow; catch, end
|
---|
[21315] | 822 | % Fix colorspace to CMYK, if requested (workaround for issue #33)
|
---|
| 823 | if options.colourspace == 1 % CMYK
|
---|
| 824 | % Issue #33: due to internal bugs in Matlab's print() function, we can't use its -cmyk option
|
---|
| 825 | change_rgb_to_cmyk(tmp_nam);
|
---|
| 826 | end
|
---|
| 827 | % Add a bookmark to the PDF if desired
|
---|
| 828 | if options.bookmark
|
---|
| 829 | fig_nam = get(fig, 'Name');
|
---|
| 830 | if isempty(fig_nam)
|
---|
| 831 | warning('export_fig:EmptyBookmark', 'Bookmark requested for figure with no name. Bookmark will be empty.');
|
---|
[7182] | 832 | end
|
---|
[21315] | 833 | add_bookmark(tmp_nam, fig_nam);
|
---|
| 834 | end
|
---|
| 835 | % Generate a pdf
|
---|
| 836 | eps2pdf(tmp_nam, pdf_nam_tmp, 1, options.append, options.colourspace==2, options.quality, options.gs_options);
|
---|
| 837 | % Ghostscript croaks on % chars in the output PDF file, so use tempname and then rename the file
|
---|
[21671] | 838 | try
|
---|
| 839 | % Rename the file (except if it is already the same)
|
---|
| 840 | % Abbie K's comment on the commit for issue #179 (#commitcomment-20173476)
|
---|
| 841 | if ~isequal(pdf_nam_tmp, pdf_nam)
|
---|
| 842 | movefile(pdf_nam_tmp, pdf_nam, 'f');
|
---|
| 843 | end
|
---|
| 844 | catch
|
---|
| 845 | % Alert in case of error creating output PDF/EPS file (issue #179)
|
---|
| 846 | if exist(pdf_nam_tmp, 'file')
|
---|
[24460] | 847 | 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'];
|
---|
| 848 | error(errMsg);
|
---|
[21671] | 849 | else
|
---|
| 850 | error('Could not generate the intermediary EPS file.');
|
---|
| 851 | end
|
---|
| 852 | end
|
---|
[21315] | 853 | catch ex
|
---|
[24460] | 854 | % Restore the figure's previous background color (in case it was not already restored)
|
---|
| 855 | try set(fig,'Color',originalBgColor); drawnow; catch, end
|
---|
[21315] | 856 | % Delete the eps
|
---|
| 857 | delete(tmp_nam);
|
---|
[24460] | 858 | % Rethrow the EPS/PDF-generation error
|
---|
[21315] | 859 | rethrow(ex);
|
---|
[7182] | 860 | end
|
---|
[21315] | 861 | % Delete the eps
|
---|
| 862 | delete(tmp_nam);
|
---|
[21671] | 863 | if options.eps || options.linecaps
|
---|
[21315] | 864 | try
|
---|
| 865 | % Generate an eps from the pdf
|
---|
| 866 | % since pdftops can't handle relative paths (e.g., '..\'), use a temp file
|
---|
| 867 | eps_nam_tmp = strrep(pdf_nam_tmp,'.pdf','.eps');
|
---|
| 868 | pdf2eps(pdf_nam, eps_nam_tmp);
|
---|
[21671] | 869 |
|
---|
| 870 | % Issue #192: enable rounded line-caps
|
---|
| 871 | if options.linecaps
|
---|
| 872 | fstrm = read_write_entire_textfile(eps_nam_tmp);
|
---|
| 873 | fstrm = regexprep(fstrm, '[02] J', '1 J');
|
---|
| 874 | read_write_entire_textfile(eps_nam_tmp, fstrm);
|
---|
| 875 | if options.pdf
|
---|
| 876 | eps2pdf(eps_nam_tmp, pdf_nam, 1, options.append, options.colourspace==2, options.quality, options.gs_options);
|
---|
| 877 | end
|
---|
| 878 | end
|
---|
| 879 |
|
---|
| 880 | if options.eps
|
---|
| 881 | movefile(eps_nam_tmp, [options.name '.eps'], 'f');
|
---|
| 882 | else % if options.pdf
|
---|
| 883 | try delete(eps_nam_tmp); catch, end
|
---|
| 884 | end
|
---|
[21315] | 885 | catch ex
|
---|
| 886 | if ~options.pdf
|
---|
| 887 | % Delete the pdf
|
---|
| 888 | delete(pdf_nam);
|
---|
| 889 | end
|
---|
| 890 | try delete(eps_nam_tmp); catch, end
|
---|
| 891 | rethrow(ex);
|
---|
| 892 | end
|
---|
| 893 | if ~options.pdf
|
---|
| 894 | % Delete the pdf
|
---|
| 895 | delete(pdf_nam);
|
---|
| 896 | end
|
---|
| 897 | end
|
---|
[24460] | 898 | % Issue #206: warn if the figure contains an image
|
---|
| 899 | if ~isempty(hImages) && strcmpi(renderer,'-opengl') % see addendum to issue #206
|
---|
| 900 | warnMsg = ['exporting images to PDF/EPS may result in blurry images on some viewers. ' ...
|
---|
| 901 | 'If so, try to change viewer, or increase the image''s CData resolution, or use -opengl renderer, or export via the print function. ' ...
|
---|
| 902 | 'See <a href="matlab:web(''https://github.com/altmany/export_fig/issues/206'',''-browser'');">issue #206</a> for details.'];
|
---|
| 903 | warning('export_fig:pdf_eps:blurry_image', warnMsg);
|
---|
| 904 | end
|
---|
[21315] | 905 | end
|
---|
| 906 |
|
---|
[24460] | 907 | % SVG format
|
---|
| 908 | if options.svg
|
---|
| 909 | oldUnits = get(fig,'Units');
|
---|
| 910 | filename = [options.name '.svg'];
|
---|
| 911 | % Adapted from Dan Joshea's https://github.com/djoshea/matlab-save-figure :
|
---|
| 912 | try %if verLessThan('matlab', '8.4')
|
---|
| 913 | % Try using the fig2svg/plot2svg utilities
|
---|
| 914 | try
|
---|
| 915 | fig2svg(filename, fig); %https://github.com/kupiqu/fig2svg
|
---|
| 916 | catch
|
---|
| 917 | plot2svg(filename, fig); %https://github.com/jschwizer99/plot2svg
|
---|
| 918 | 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).');
|
---|
| 919 | end
|
---|
| 920 | catch %else % (neither fig2svg nor plot2svg are available)
|
---|
| 921 | % Try Matlab's built-in svg engine (from Batik Graphics2D for java)
|
---|
| 922 | try
|
---|
| 923 | set(fig,'Units','pixels'); % All data in the svg-file is saved in pixels
|
---|
| 924 | printArgs = {renderer};
|
---|
| 925 | if ~isempty(options.resolution)
|
---|
| 926 | printArgs{end+1} = sprintf('-r%d', options.resolution);
|
---|
| 927 | end
|
---|
| 928 | print(fig, '-dsvg', printArgs{:}, filename);
|
---|
| 929 | 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).');
|
---|
| 930 | catch err % built-in print() failed - maybe an old Matlab release (no -dsvg)
|
---|
| 931 | set(fig,'Units',oldUnits);
|
---|
| 932 | filename = strrep(filename,'export_fig_out','filename');
|
---|
| 933 | msg = ['SVG output is not supported for your figure: ' err.message '\n' ...
|
---|
| 934 | 'Try one of the following alternatives:\n' ...
|
---|
| 935 | ' 1. saveas(gcf,''' filename ''')\n' ...
|
---|
| 936 | ' 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
|
---|
| 937 | ' 3. export_fig to EPS/PDF, then convert to SVG using non-Matlab tools\n'];
|
---|
| 938 | error(sprintf(msg)); %#ok<SPERR>
|
---|
| 939 | end
|
---|
| 940 | end
|
---|
| 941 | % SVG output was successful if we reached this point
|
---|
| 942 | % Restore original figure units
|
---|
| 943 | set(fig,'Units',oldUnits);
|
---|
| 944 | % Add warning about unsupported export_fig options with SVG output
|
---|
| 945 | if any(~isnan(options.crop_amounts)) || any(options.bb_padding)
|
---|
| 946 | warning('export_fig:SVG:options', 'export_fig''s SVG output does not [currently] support cropping/padding.');
|
---|
| 947 | end
|
---|
| 948 | end
|
---|
| 949 |
|
---|
[21315] | 950 | % Revert the figure or close it (if requested)
|
---|
| 951 | if cls || options.closeFig
|
---|
| 952 | % Close the created figure
|
---|
| 953 | close(fig);
|
---|
[7182] | 954 | else
|
---|
[21315] | 955 | % Reset the hardcopy mode
|
---|
[24460] | 956 | try set(fig, 'InvertHardcopy', old_mode); catch, end % fail silently in uifigures
|
---|
[21315] | 957 | % Reset the axes limit and tick modes
|
---|
| 958 | for a = 1:numel(Hlims)
|
---|
| 959 | try
|
---|
| 960 | set(Hlims(a), 'XLimMode', Xlims{a}, 'YLimMode', Ylims{a}, 'ZLimMode', Zlims{a},...
|
---|
| 961 | 'XTickMode', Xtick{a}, 'YTickMode', Ytick{a}, 'ZTickMode', Ztick{a},...
|
---|
| 962 | 'XTickLabelMode', Xlabel{a}, 'YTickLabelMode', Ylabel{a}, 'ZTickLabelMode', Zlabel{a});
|
---|
| 963 | catch
|
---|
| 964 | % ignore - fix issue #4 (using HG2 on R2014a and earlier)
|
---|
| 965 | end
|
---|
[7182] | 966 | end
|
---|
[21315] | 967 | % Revert the tex-labels font weights
|
---|
| 968 | try set(texLabels, 'FontWeight','bold'); catch, end
|
---|
| 969 | % Revert annotation units
|
---|
| 970 | for handleIdx = 1 : numel(annotationHandles)
|
---|
| 971 | try
|
---|
| 972 | oldUnits = originalUnits{handleIdx};
|
---|
| 973 | catch
|
---|
| 974 | oldUnits = originalUnits;
|
---|
| 975 | end
|
---|
| 976 | try set(annotationHandles(handleIdx),'Units',oldUnits); catch, end
|
---|
[10635] | 977 | end
|
---|
[21315] | 978 | % Revert figure units
|
---|
| 979 | set(fig,'Units',oldFigUnits);
|
---|
[7182] | 980 | end
|
---|
[21315] | 981 |
|
---|
| 982 | % Output to clipboard (if requested)
|
---|
| 983 | if options.clipboard
|
---|
| 984 | % Delete the output file if unchanged from the default name ('export_fig_out.png')
|
---|
| 985 | if strcmpi(options.name,'export_fig_out')
|
---|
| 986 | try
|
---|
| 987 | fileInfo = dir('export_fig_out.png');
|
---|
| 988 | if ~isempty(fileInfo)
|
---|
| 989 | timediff = now - fileInfo.datenum;
|
---|
| 990 | ONE_SEC = 1/24/60/60;
|
---|
| 991 | if timediff < ONE_SEC
|
---|
| 992 | delete('export_fig_out.png');
|
---|
| 993 | end
|
---|
| 994 | end
|
---|
| 995 | catch
|
---|
| 996 | % never mind...
|
---|
| 997 | end
|
---|
| 998 | end
|
---|
| 999 |
|
---|
| 1000 | % Save the image in the system clipboard
|
---|
| 1001 | % credit: Jiro Doke's IMCLIPBOARD: http://www.mathworks.com/matlabcentral/fileexchange/28708-imclipboard
|
---|
| 1002 | try
|
---|
| 1003 | error(javachk('awt', 'export_fig -clipboard output'));
|
---|
| 1004 | catch
|
---|
[24460] | 1005 | warning('export_fig:clipboardJava', 'export_fig -clipboard output failed: requires Java to work');
|
---|
[21315] | 1006 | return;
|
---|
| 1007 | end
|
---|
| 1008 | try
|
---|
| 1009 | % Import necessary Java classes
|
---|
| 1010 | import java.awt.Toolkit
|
---|
| 1011 | import java.awt.image.BufferedImage
|
---|
| 1012 | import java.awt.datatransfer.DataFlavor
|
---|
| 1013 |
|
---|
| 1014 | % Get System Clipboard object (java.awt.Toolkit)
|
---|
| 1015 | cb = Toolkit.getDefaultToolkit.getSystemClipboard();
|
---|
| 1016 |
|
---|
| 1017 | % Add java class (ImageSelection) to the path
|
---|
| 1018 | if ~exist('ImageSelection', 'class')
|
---|
| 1019 | javaaddpath(fileparts(which(mfilename)), '-end');
|
---|
| 1020 | end
|
---|
| 1021 |
|
---|
| 1022 | % Get image size
|
---|
| 1023 | ht = size(imageData, 1);
|
---|
| 1024 | wd = size(imageData, 2);
|
---|
| 1025 |
|
---|
| 1026 | % Convert to Blue-Green-Red format
|
---|
| 1027 | try
|
---|
| 1028 | imageData2 = imageData(:, :, [3 2 1]);
|
---|
| 1029 | catch
|
---|
| 1030 | % Probably gray-scaled image (2D, without the 3rd [RGB] dimension)
|
---|
| 1031 | imageData2 = imageData(:, :, [1 1 1]);
|
---|
| 1032 | end
|
---|
| 1033 |
|
---|
| 1034 | % Convert to 3xWxH format
|
---|
| 1035 | imageData2 = permute(imageData2, [3, 2, 1]);
|
---|
| 1036 |
|
---|
| 1037 | % Append Alpha data (unused - transparency is not supported in clipboard copy)
|
---|
| 1038 | alphaData2 = uint8(permute(255*alpha,[3,2,1])); %=255*ones(1,wd,ht,'uint8')
|
---|
| 1039 | imageData2 = cat(1, imageData2, alphaData2);
|
---|
| 1040 |
|
---|
| 1041 | % Create image buffer
|
---|
| 1042 | imBuffer = BufferedImage(wd, ht, BufferedImage.TYPE_INT_RGB);
|
---|
| 1043 | imBuffer.setRGB(0, 0, wd, ht, typecast(imageData2(:), 'int32'), 0, wd);
|
---|
| 1044 |
|
---|
| 1045 | % Create ImageSelection object from the image buffer
|
---|
| 1046 | imSelection = ImageSelection(imBuffer);
|
---|
| 1047 |
|
---|
| 1048 | % Set clipboard content to the image
|
---|
| 1049 | cb.setContents(imSelection, []);
|
---|
| 1050 | catch
|
---|
[24460] | 1051 | warning('export_fig:clipboardFailed', 'export_fig -clipboard output failed: %s', lasterr); %#ok<LERR>
|
---|
[21315] | 1052 | end
|
---|
| 1053 | end
|
---|
| 1054 |
|
---|
| 1055 | % Don't output the data to console unless requested
|
---|
| 1056 | if ~nargout
|
---|
| 1057 | clear imageData alpha
|
---|
| 1058 | end
|
---|
| 1059 | catch err
|
---|
| 1060 | % Display possible workarounds before the error message
|
---|
| 1061 | if displaySuggestedWorkarounds && ~strcmpi(err.message,'export_fig error')
|
---|
| 1062 | if ~hadError, fprintf(2, 'export_fig error. '); end
|
---|
| 1063 | fprintf(2, 'Please ensure:\n');
|
---|
| 1064 | 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');
|
---|
[24460] | 1065 | if isvector(options)
|
---|
| 1066 | if ismac
|
---|
| 1067 | fprintf(2, ' and that you have <a href="http://pages.uoregon.edu/koch">Ghostscript</a> installed\n');
|
---|
| 1068 | else
|
---|
| 1069 | fprintf(2, ' and that you have <a href="http://www.ghostscript.com">Ghostscript</a> installed\n');
|
---|
| 1070 | end
|
---|
[21315] | 1071 | end
|
---|
| 1072 | try
|
---|
| 1073 | if options.eps
|
---|
[24460] | 1074 | fprintf(2, ' and that you have <a href="http://xpdfreader.com/download.html">pdftops</a> installed\n');
|
---|
[21315] | 1075 | end
|
---|
| 1076 | catch
|
---|
| 1077 | % ignore - probably an error in parse_args
|
---|
| 1078 | end
|
---|
| 1079 | 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');
|
---|
| 1080 | fprintf(2, ' and that you did not made a mistake in the <a href="matlab:help export_fig">expected input arguments</a>\n');
|
---|
| 1081 | try
|
---|
| 1082 | % Alert per issue #149
|
---|
| 1083 | if ~strncmpi(get(0,'Units'),'pixel',5)
|
---|
| 1084 | 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');
|
---|
| 1085 | end
|
---|
| 1086 | catch
|
---|
| 1087 | % ignore - maybe an old MAtlab release
|
---|
| 1088 | end
|
---|
| 1089 | fprintf(2, '\nIf the problem persists, then please <a href="https://github.com/altmany/export_fig/issues">report a new issue</a>.\n\n');
|
---|
| 1090 | end
|
---|
| 1091 | rethrow(err)
|
---|
[7182] | 1092 | end
|
---|
| 1093 | end
|
---|
| 1094 |
|
---|
[21315] | 1095 | function options = default_options()
|
---|
| 1096 | % Default options used by export_fig
|
---|
| 1097 | options = struct(...
|
---|
[24460] | 1098 | 'name', 'export_fig_out', ...
|
---|
| 1099 | 'crop', true, ...
|
---|
| 1100 | 'crop_amounts', nan(1,4), ... % auto-crop all 4 image sides
|
---|
| 1101 | 'transparent', false, ...
|
---|
| 1102 | 'renderer', 0, ... % 0: default, 1: OpenGL, 2: ZBuffer, 3: Painters
|
---|
| 1103 | 'pdf', false, ...
|
---|
| 1104 | 'eps', false, ...
|
---|
| 1105 | 'svg', false, ...
|
---|
| 1106 | 'png', false, ...
|
---|
| 1107 | 'tif', false, ...
|
---|
| 1108 | 'jpg', false, ...
|
---|
| 1109 | 'bmp', false, ...
|
---|
| 1110 | 'clipboard', false, ...
|
---|
| 1111 | 'colourspace', 0, ... % 0: RGB/gray, 1: CMYK, 2: gray
|
---|
| 1112 | 'append', false, ...
|
---|
| 1113 | 'im', false, ...
|
---|
| 1114 | 'alpha', false, ...
|
---|
| 1115 | 'aa_factor', 0, ...
|
---|
| 1116 | 'bb_padding', 0, ...
|
---|
| 1117 | 'magnify', [], ...
|
---|
| 1118 | 'resolution', [], ...
|
---|
| 1119 | 'bookmark', false, ...
|
---|
| 1120 | 'closeFig', false, ...
|
---|
| 1121 | 'quality', [], ...
|
---|
| 1122 | 'update', false, ...
|
---|
| 1123 | 'fontswap', true, ...
|
---|
| 1124 | 'font_space', '', ...
|
---|
| 1125 | 'linecaps', false, ...
|
---|
| 1126 | 'invert_hardcopy', true, ...
|
---|
| 1127 | 'format_options', struct, ...
|
---|
| 1128 | 'preserve_size', false, ...
|
---|
| 1129 | 'gs_options', {{}});
|
---|
[19993] | 1130 | end
|
---|
[18904] | 1131 |
|
---|
[21315] | 1132 | function [fig, options] = parse_args(nout, fig, varargin)
|
---|
| 1133 | % Parse the input arguments
|
---|
[18904] | 1134 |
|
---|
[24460] | 1135 | % Convert strings => chars
|
---|
| 1136 | varargin = cellfun(@str2char,varargin,'un',false);
|
---|
| 1137 |
|
---|
[21315] | 1138 | % Set the defaults
|
---|
| 1139 | native = false; % Set resolution to native of an image
|
---|
| 1140 | options = default_options();
|
---|
| 1141 | options.im = (nout == 1); % user requested imageData output
|
---|
| 1142 | options.alpha = (nout == 2); % user requested alpha output
|
---|
| 1143 |
|
---|
| 1144 | % Go through the other arguments
|
---|
| 1145 | skipNext = false;
|
---|
| 1146 | for a = 1:nargin-2
|
---|
| 1147 | if skipNext
|
---|
| 1148 | skipNext = false;
|
---|
| 1149 | continue;
|
---|
| 1150 | end
|
---|
| 1151 | if all(ishandle(varargin{a}))
|
---|
| 1152 | fig = varargin{a};
|
---|
| 1153 | elseif ischar(varargin{a}) && ~isempty(varargin{a})
|
---|
| 1154 | if varargin{a}(1) == '-'
|
---|
| 1155 | switch lower(varargin{a}(2:end))
|
---|
| 1156 | case 'nocrop'
|
---|
| 1157 | options.crop = false;
|
---|
| 1158 | options.crop_amounts = [0,0,0,0];
|
---|
| 1159 | case {'trans', 'transparent'}
|
---|
| 1160 | options.transparent = true;
|
---|
| 1161 | case 'opengl'
|
---|
| 1162 | options.renderer = 1;
|
---|
| 1163 | case 'zbuffer'
|
---|
| 1164 | options.renderer = 2;
|
---|
| 1165 | case 'painters'
|
---|
| 1166 | options.renderer = 3;
|
---|
| 1167 | case 'pdf'
|
---|
| 1168 | options.pdf = true;
|
---|
| 1169 | case 'eps'
|
---|
| 1170 | options.eps = true;
|
---|
[24460] | 1171 | case 'svg'
|
---|
| 1172 | options.svg = true;
|
---|
[21315] | 1173 | case 'png'
|
---|
| 1174 | options.png = true;
|
---|
| 1175 | case {'tif', 'tiff'}
|
---|
| 1176 | options.tif = true;
|
---|
| 1177 | case {'jpg', 'jpeg'}
|
---|
| 1178 | options.jpg = true;
|
---|
| 1179 | case 'bmp'
|
---|
| 1180 | options.bmp = true;
|
---|
| 1181 | case 'rgb'
|
---|
| 1182 | options.colourspace = 0;
|
---|
| 1183 | case 'cmyk'
|
---|
| 1184 | options.colourspace = 1;
|
---|
| 1185 | case {'gray', 'grey'}
|
---|
| 1186 | options.colourspace = 2;
|
---|
| 1187 | case {'a1', 'a2', 'a3', 'a4'}
|
---|
| 1188 | options.aa_factor = str2double(varargin{a}(3));
|
---|
| 1189 | case 'append'
|
---|
| 1190 | options.append = true;
|
---|
| 1191 | case 'bookmark'
|
---|
| 1192 | options.bookmark = true;
|
---|
| 1193 | case 'native'
|
---|
| 1194 | native = true;
|
---|
| 1195 | case 'clipboard'
|
---|
| 1196 | options.clipboard = true;
|
---|
| 1197 | options.im = true;
|
---|
| 1198 | options.alpha = true;
|
---|
| 1199 | case 'update'
|
---|
| 1200 | % Download the latest version of export_fig into the export_fig folder
|
---|
| 1201 | try
|
---|
| 1202 | zipFileName = 'https://github.com/altmany/export_fig/archive/master.zip';
|
---|
| 1203 | folderName = fileparts(which(mfilename('fullpath')));
|
---|
| 1204 | targetFileName = fullfile(folderName, datestr(now,'yyyy-mm-dd.zip'));
|
---|
[24460] | 1205 | urlwrite(zipFileName,targetFileName); %#ok<URLWR>
|
---|
[21315] | 1206 | catch
|
---|
| 1207 | error('Could not download %s into %s\n',zipFileName,targetFileName);
|
---|
| 1208 | end
|
---|
| 1209 |
|
---|
| 1210 | % Unzip the downloaded zip file in the export_fig folder
|
---|
| 1211 | try
|
---|
| 1212 | unzip(targetFileName,folderName);
|
---|
| 1213 | catch
|
---|
| 1214 | error('Could not unzip %s\n',targetFileName);
|
---|
| 1215 | end
|
---|
| 1216 | case 'nofontswap'
|
---|
| 1217 | options.fontswap = false;
|
---|
[24460] | 1218 | case 'font_space'
|
---|
| 1219 | options.font_space = varargin{a+1};
|
---|
| 1220 | skipNext = true;
|
---|
[21671] | 1221 | case 'linecaps'
|
---|
| 1222 | options.linecaps = true;
|
---|
[24460] | 1223 | case 'noinvert'
|
---|
| 1224 | options.invert_hardcopy = false;
|
---|
| 1225 | case 'preserve_size'
|
---|
| 1226 | options.preserve_size = true;
|
---|
| 1227 | case 'options'
|
---|
| 1228 | % Issue #269: format-specific options
|
---|
| 1229 | inputOptions = varargin{a+1};
|
---|
| 1230 | %options.format_options = inputOptions;
|
---|
| 1231 | if isempty(inputOptions), continue, end
|
---|
| 1232 | formats = fieldnames(inputOptions(1));
|
---|
| 1233 | for idx = 1 : numel(formats)
|
---|
| 1234 | optionsStruct = inputOptions.(formats{idx});
|
---|
| 1235 | %optionsCells = [fieldnames(optionsStruct) struct2cell(optionsStruct)]';
|
---|
| 1236 | formatName = regexprep(lower(formats{idx}),{'tiff','jpeg'},{'tif','jpg'});
|
---|
| 1237 | options.format_options.(formatName) = optionsStruct; %=optionsCells(:)';
|
---|
| 1238 | end
|
---|
| 1239 | skipNext = true;
|
---|
[21315] | 1240 | otherwise
|
---|
| 1241 | try
|
---|
| 1242 | wasError = false;
|
---|
| 1243 | if strcmpi(varargin{a}(1:2),'-d')
|
---|
| 1244 | varargin{a}(2) = 'd'; % ensure lowercase 'd'
|
---|
| 1245 | options.gs_options{end+1} = varargin{a};
|
---|
| 1246 | elseif strcmpi(varargin{a}(1:2),'-c')
|
---|
| 1247 | if numel(varargin{a})==2
|
---|
| 1248 | skipNext = true;
|
---|
| 1249 | vals = str2num(varargin{a+1}); %#ok<ST2NM>
|
---|
| 1250 | else
|
---|
| 1251 | vals = str2num(varargin{a}(3:end)); %#ok<ST2NM>
|
---|
| 1252 | end
|
---|
| 1253 | if numel(vals)~=4
|
---|
| 1254 | wasError = true;
|
---|
| 1255 | error('option -c cannot be parsed: must be a 4-element numeric vector');
|
---|
| 1256 | end
|
---|
| 1257 | options.crop_amounts = vals;
|
---|
| 1258 | options.crop = true;
|
---|
| 1259 | else % scalar parameter value
|
---|
| 1260 | val = str2double(regexp(varargin{a}, '(?<=-(m|M|r|R|q|Q|p|P))-?\d*.?\d+', 'match'));
|
---|
| 1261 | if isempty(val) || isnan(val)
|
---|
| 1262 | % Issue #51: improved processing of input args (accept space between param name & value)
|
---|
| 1263 | val = str2double(varargin{a+1});
|
---|
| 1264 | if isscalar(val) && ~isnan(val)
|
---|
| 1265 | skipNext = true;
|
---|
| 1266 | end
|
---|
| 1267 | end
|
---|
| 1268 | if ~isscalar(val) || isnan(val)
|
---|
| 1269 | wasError = true;
|
---|
| 1270 | error('option %s is not recognised or cannot be parsed', varargin{a});
|
---|
| 1271 | end
|
---|
| 1272 | switch lower(varargin{a}(2))
|
---|
| 1273 | case 'm'
|
---|
| 1274 | % Magnification may never be negative
|
---|
| 1275 | if val <= 0
|
---|
| 1276 | wasError = true;
|
---|
| 1277 | error('Bad magnification value: %g (must be positive)', val);
|
---|
| 1278 | end
|
---|
| 1279 | options.magnify = val;
|
---|
| 1280 | case 'r'
|
---|
| 1281 | options.resolution = val;
|
---|
| 1282 | case 'q'
|
---|
| 1283 | options.quality = max(val, 0);
|
---|
| 1284 | case 'p'
|
---|
| 1285 | options.bb_padding = val;
|
---|
| 1286 | end
|
---|
| 1287 | end
|
---|
| 1288 | catch err
|
---|
| 1289 | % We might have reached here by raising an intentional error
|
---|
| 1290 | if wasError % intentional raise
|
---|
| 1291 | rethrow(err)
|
---|
| 1292 | else % unintentional
|
---|
| 1293 | error(['Unrecognized export_fig input option: ''' varargin{a} '''']);
|
---|
| 1294 | end
|
---|
| 1295 | end
|
---|
| 1296 | end
|
---|
| 1297 | else
|
---|
| 1298 | [p, options.name, ext] = fileparts(varargin{a});
|
---|
| 1299 | if ~isempty(p)
|
---|
[24460] | 1300 | % Issue #221: alert if the requested folder does not exist
|
---|
| 1301 | if ~exist(p,'dir'), error(['Folder ' p ' does not exist!']); end
|
---|
[21315] | 1302 | options.name = [p filesep options.name];
|
---|
| 1303 | end
|
---|
| 1304 | switch lower(ext)
|
---|
| 1305 | case {'.tif', '.tiff'}
|
---|
| 1306 | options.tif = true;
|
---|
| 1307 | case {'.jpg', '.jpeg'}
|
---|
| 1308 | options.jpg = true;
|
---|
| 1309 | case '.png'
|
---|
| 1310 | options.png = true;
|
---|
| 1311 | case '.bmp'
|
---|
| 1312 | options.bmp = true;
|
---|
| 1313 | case '.eps'
|
---|
| 1314 | options.eps = true;
|
---|
| 1315 | case '.pdf'
|
---|
| 1316 | options.pdf = true;
|
---|
| 1317 | case '.fig'
|
---|
| 1318 | % If no open figure, then load the specified .fig file and continue
|
---|
| 1319 | if isempty(fig)
|
---|
| 1320 | fig = openfig(varargin{a},'invisible');
|
---|
| 1321 | varargin{a} = fig;
|
---|
| 1322 | options.closeFig = true;
|
---|
| 1323 | else
|
---|
| 1324 | % save the current figure as the specified .fig file and exit
|
---|
| 1325 | saveas(fig(1),varargin{a});
|
---|
| 1326 | fig = -1;
|
---|
| 1327 | return
|
---|
| 1328 | end
|
---|
| 1329 | case '.svg'
|
---|
[24460] | 1330 | options.svg = true;
|
---|
[21315] | 1331 | otherwise
|
---|
| 1332 | options.name = varargin{a};
|
---|
| 1333 | end
|
---|
| 1334 | end
|
---|
| 1335 | end
|
---|
[18904] | 1336 | end
|
---|
| 1337 |
|
---|
[21315] | 1338 | % Quick bail-out if no figure found
|
---|
| 1339 | if isempty(fig), return; end
|
---|
[7182] | 1340 |
|
---|
[21315] | 1341 | % Do border padding with repsect to a cropped image
|
---|
| 1342 | if options.bb_padding
|
---|
| 1343 | options.crop = true;
|
---|
| 1344 | end
|
---|
[7182] | 1345 |
|
---|
[21315] | 1346 | % Set default anti-aliasing now we know the renderer
|
---|
| 1347 | if options.aa_factor == 0
|
---|
| 1348 | try isAA = strcmp(get(ancestor(fig, 'figure'), 'GraphicsSmoothing'), 'on'); catch, isAA = false; end
|
---|
| 1349 | options.aa_factor = 1 + 2 * (~(using_hg2(fig) && isAA) | (options.renderer == 3));
|
---|
| 1350 | end
|
---|
[10635] | 1351 |
|
---|
[21315] | 1352 | % Convert user dir '~' to full path
|
---|
| 1353 | if numel(options.name) > 2 && options.name(1) == '~' && (options.name(2) == '/' || options.name(2) == '\')
|
---|
| 1354 | options.name = fullfile(char(java.lang.System.getProperty('user.home')), options.name(2:end));
|
---|
[7182] | 1355 | end
|
---|
[21315] | 1356 |
|
---|
| 1357 | % Compute the magnification and resolution
|
---|
| 1358 | if isempty(options.magnify)
|
---|
| 1359 | if isempty(options.resolution)
|
---|
| 1360 | options.magnify = 1;
|
---|
| 1361 | options.resolution = 864;
|
---|
| 1362 | else
|
---|
| 1363 | options.magnify = options.resolution ./ get(0, 'ScreenPixelsPerInch');
|
---|
[19993] | 1364 | end
|
---|
[21315] | 1365 | elseif isempty(options.resolution)
|
---|
| 1366 | options.resolution = 864;
|
---|
| 1367 | end
|
---|
| 1368 |
|
---|
| 1369 | % Set the default format
|
---|
| 1370 | if ~isvector(options) && ~isbitmap(options)
|
---|
| 1371 | options.png = true;
|
---|
| 1372 | end
|
---|
| 1373 |
|
---|
| 1374 | % Check whether transparent background is wanted (old way)
|
---|
| 1375 | if isequal(get(ancestor(fig(1), 'figure'), 'Color'), 'none')
|
---|
| 1376 | options.transparent = true;
|
---|
| 1377 | end
|
---|
| 1378 |
|
---|
| 1379 | % If requested, set the resolution to the native vertical resolution of the
|
---|
| 1380 | % first suitable image found
|
---|
[24460] | 1381 | if native
|
---|
| 1382 | if isbitmap(options)
|
---|
| 1383 | % Find a suitable image
|
---|
| 1384 | list = findall(fig, 'Type','image', 'Tag','export_fig_native');
|
---|
| 1385 | if isempty(list)
|
---|
| 1386 | list = findall(fig, 'Type','image', 'Visible','on');
|
---|
[7182] | 1387 | end
|
---|
[24460] | 1388 | for hIm = list(:)'
|
---|
| 1389 | % Check height is >= 2
|
---|
| 1390 | height = size(get(hIm, 'CData'), 1);
|
---|
| 1391 | if height < 2
|
---|
[21315] | 1392 | continue
|
---|
| 1393 | end
|
---|
[24460] | 1394 | % Account for the image filling only part of the axes, or vice versa
|
---|
| 1395 | yl = get(hIm, 'YData');
|
---|
| 1396 | if isscalar(yl)
|
---|
| 1397 | yl = [yl(1)-0.5 yl(1)+height+0.5];
|
---|
| 1398 | else
|
---|
| 1399 | yl = [min(yl), max(yl)]; % fix issue #151 (case of yl containing more than 2 elements)
|
---|
| 1400 | if ~diff(yl)
|
---|
| 1401 | continue
|
---|
| 1402 | end
|
---|
| 1403 | yl = yl + [-0.5 0.5] * (diff(yl) / (height - 1));
|
---|
| 1404 | end
|
---|
| 1405 | hAx = get(hIm, 'Parent');
|
---|
| 1406 | yl2 = get(hAx, 'YLim');
|
---|
| 1407 | % Find the pixel height of the axes
|
---|
| 1408 | oldUnits = get(hAx, 'Units');
|
---|
| 1409 | set(hAx, 'Units', 'pixels');
|
---|
| 1410 | pos = get(hAx, 'Position');
|
---|
| 1411 | set(hAx, 'Units', oldUnits);
|
---|
| 1412 | if ~pos(4)
|
---|
| 1413 | continue
|
---|
| 1414 | end
|
---|
| 1415 | % Found a suitable image
|
---|
| 1416 | % Account for stretch-to-fill being disabled
|
---|
| 1417 | pbar = get(hAx, 'PlotBoxAspectRatio');
|
---|
| 1418 | pos = min(pos(4), pbar(2)*pos(3)/pbar(1));
|
---|
| 1419 | % Set the magnification to give native resolution
|
---|
| 1420 | options.magnify = abs((height * diff(yl2)) / (pos * diff(yl))); % magnification must never be negative: issue #103
|
---|
| 1421 | break
|
---|
[21315] | 1422 | end
|
---|
[24460] | 1423 | elseif options.resolution == 864 % don't use -r864 in vector mode if user asked for -native
|
---|
| 1424 | options.resolution = []; % issue #241 (internal Matlab bug produces black lines with -r864)
|
---|
[7182] | 1425 | end
|
---|
| 1426 | end
|
---|
| 1427 | end
|
---|
| 1428 |
|
---|
[24460] | 1429 | % Convert a possible string => char (issue #245)
|
---|
| 1430 | function value = str2char(value)
|
---|
| 1431 | if isa(value,'string')
|
---|
| 1432 | value = char(value);
|
---|
| 1433 | end
|
---|
| 1434 | end
|
---|
| 1435 |
|
---|
[10635] | 1436 | function A = downsize(A, factor)
|
---|
[21315] | 1437 | % Downsample an image
|
---|
| 1438 | if factor == 1
|
---|
| 1439 | % Nothing to do
|
---|
| 1440 | return
|
---|
[7182] | 1441 | end
|
---|
[21315] | 1442 | try
|
---|
| 1443 | % Faster, but requires image processing toolbox
|
---|
| 1444 | A = imresize(A, 1/factor, 'bilinear');
|
---|
| 1445 | catch
|
---|
| 1446 | % No image processing toolbox - resize manually
|
---|
| 1447 | % Lowpass filter - use Gaussian as is separable, so faster
|
---|
| 1448 | % Compute the 1d Gaussian filter
|
---|
| 1449 | filt = (-factor-1:factor+1) / (factor * 0.6);
|
---|
| 1450 | filt = exp(-filt .* filt);
|
---|
| 1451 | % Normalize the filter
|
---|
| 1452 | filt = single(filt / sum(filt));
|
---|
| 1453 | % Filter the image
|
---|
| 1454 | padding = floor(numel(filt) / 2);
|
---|
| 1455 | for a = 1:size(A, 3)
|
---|
| 1456 | 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');
|
---|
| 1457 | end
|
---|
| 1458 | % Subsample
|
---|
| 1459 | A = A(1+floor(mod(end-1, factor)/2):factor:end,1+floor(mod(end-1, factor)/2):factor:end,:);
|
---|
| 1460 | end
|
---|
[7182] | 1461 | end
|
---|
| 1462 |
|
---|
| 1463 | function A = rgb2grey(A)
|
---|
[21671] | 1464 | A = cast(reshape(reshape(single(A), [], 3) * single([0.299; 0.587; 0.114]), size(A, 1), size(A, 2)), class(A)); % #ok<ZEROLIKE>
|
---|
[18904] | 1465 | end
|
---|
[7182] | 1466 |
|
---|
| 1467 | function A = check_greyscale(A)
|
---|
[21315] | 1468 | % Check if the image is greyscale
|
---|
| 1469 | if size(A, 3) == 3 && ...
|
---|
| 1470 | all(reshape(A(:,:,1) == A(:,:,2), [], 1)) && ...
|
---|
| 1471 | all(reshape(A(:,:,2) == A(:,:,3), [], 1))
|
---|
| 1472 | A = A(:,:,1); % Save only one channel for 8-bit output
|
---|
| 1473 | end
|
---|
[7182] | 1474 | end
|
---|
| 1475 |
|
---|
[18904] | 1476 | function eps_remove_background(fname, count)
|
---|
[21315] | 1477 | % Remove the background of an eps file
|
---|
| 1478 | % Open the file
|
---|
| 1479 | fh = fopen(fname, 'r+');
|
---|
| 1480 | if fh == -1
|
---|
| 1481 | error('Not able to open file %s.', fname);
|
---|
[10635] | 1482 | end
|
---|
[21315] | 1483 | % Read the file line by line
|
---|
| 1484 | while count
|
---|
| 1485 | % Get the next line
|
---|
| 1486 | l = fgets(fh);
|
---|
| 1487 | if isequal(l, -1)
|
---|
| 1488 | break; % Quit, no rectangle found
|
---|
| 1489 | end
|
---|
| 1490 | % Check if the line contains the background rectangle
|
---|
| 1491 | if isequal(regexp(l, ' *0 +0 +\d+ +\d+ +r[fe] *[\n\r]+', 'start'), 1)
|
---|
| 1492 | % Set the line to whitespace and quit
|
---|
| 1493 | l(1:regexp(l, '[\n\r]', 'start', 'once')-1) = ' ';
|
---|
| 1494 | fseek(fh, -numel(l), 0);
|
---|
| 1495 | fprintf(fh, l);
|
---|
| 1496 | % Reduce the count
|
---|
| 1497 | count = count - 1;
|
---|
| 1498 | end
|
---|
[10635] | 1499 | end
|
---|
[21315] | 1500 | % Close the file
|
---|
| 1501 | fclose(fh);
|
---|
[10635] | 1502 | end
|
---|
| 1503 |
|
---|
[7182] | 1504 | function b = isvector(options)
|
---|
[21315] | 1505 | b = options.pdf || options.eps;
|
---|
[18904] | 1506 | end
|
---|
[7182] | 1507 |
|
---|
| 1508 | function b = isbitmap(options)
|
---|
[21315] | 1509 | b = options.png || options.tif || options.jpg || options.bmp || options.im || options.alpha;
|
---|
[18904] | 1510 | end
|
---|
[11803] | 1511 |
|
---|
| 1512 | % Helper function
|
---|
| 1513 | function A = make_cell(A)
|
---|
[21315] | 1514 | if ~iscell(A)
|
---|
| 1515 | A = {A};
|
---|
| 1516 | end
|
---|
[12407] | 1517 | end
|
---|
| 1518 |
|
---|
| 1519 | function add_bookmark(fname, bookmark_text)
|
---|
[21315] | 1520 | % Adds a bookmark to the temporary EPS file after %%EndPageSetup
|
---|
| 1521 | % Read in the file
|
---|
| 1522 | fh = fopen(fname, 'r');
|
---|
| 1523 | if fh == -1
|
---|
| 1524 | error('File %s not found.', fname);
|
---|
| 1525 | end
|
---|
| 1526 | try
|
---|
| 1527 | fstrm = fread(fh, '*char')';
|
---|
| 1528 | catch ex
|
---|
| 1529 | fclose(fh);
|
---|
| 1530 | rethrow(ex);
|
---|
| 1531 | end
|
---|
[12407] | 1532 | fclose(fh);
|
---|
| 1533 |
|
---|
[21315] | 1534 | % Include standard pdfmark prolog to maximize compatibility
|
---|
| 1535 | fstrm = strrep(fstrm, '%%BeginProlog', sprintf('%%%%BeginProlog\n/pdfmark where {pop} {userdict /pdfmark /cleartomark load put} ifelse'));
|
---|
| 1536 | % Add page bookmark
|
---|
| 1537 | fstrm = strrep(fstrm, '%%EndPageSetup', sprintf('%%%%EndPageSetup\n[ /Title (%s) /OUT pdfmark',bookmark_text));
|
---|
[12407] | 1538 |
|
---|
[21315] | 1539 | % Write out the updated file
|
---|
| 1540 | fh = fopen(fname, 'w');
|
---|
| 1541 | if fh == -1
|
---|
| 1542 | error('Unable to open %s for writing.', fname);
|
---|
| 1543 | end
|
---|
| 1544 | try
|
---|
| 1545 | fwrite(fh, fstrm, 'char*1');
|
---|
| 1546 | catch ex
|
---|
| 1547 | fclose(fh);
|
---|
| 1548 | rethrow(ex);
|
---|
| 1549 | end
|
---|
[12407] | 1550 | fclose(fh);
|
---|
| 1551 | end
|
---|
[18904] | 1552 |
|
---|
| 1553 | function set_tick_mode(Hlims, ax)
|
---|
[21315] | 1554 | % Set the tick mode of linear axes to manual
|
---|
| 1555 | % Leave log axes alone as these are tricky
|
---|
| 1556 | M = get(Hlims, [ax 'Scale']);
|
---|
| 1557 | if ~iscell(M)
|
---|
| 1558 | M = {M};
|
---|
| 1559 | end
|
---|
[21671] | 1560 | %idx = cellfun(@(c) strcmp(c, 'linear'), M);
|
---|
| 1561 | idx = find(strcmp(M,'linear'));
|
---|
| 1562 | %set(Hlims(idx), [ax 'TickMode'], 'manual'); % issue #187
|
---|
| 1563 | %set(Hlims(idx), [ax 'TickLabelMode'], 'manual'); % this hides exponent label in HG2!
|
---|
| 1564 | for idx2 = 1 : numel(idx)
|
---|
| 1565 | try
|
---|
| 1566 | % Fix for issue #187 - only set manual ticks when no exponent is present
|
---|
| 1567 | hAxes = Hlims(idx(idx2));
|
---|
| 1568 | props = {[ax 'TickMode'],'manual', [ax 'TickLabelMode'],'manual'};
|
---|
[24460] | 1569 | tickVals = get(hAxes,[ax 'Tick']);
|
---|
| 1570 | tickStrs = get(hAxes,[ax 'TickLabel']);
|
---|
| 1571 | try % Fix issue #236
|
---|
| 1572 | exponents = [hAxes.([ax 'Axis']).SecondaryLabel];
|
---|
| 1573 | catch
|
---|
| 1574 | exponents = [hAxes.([ax 'Ruler']).SecondaryLabel];
|
---|
[21671] | 1575 | end
|
---|
[24460] | 1576 | if isempty([exponents.String])
|
---|
| 1577 | % Fix for issue #205 - only set manual ticks when the Ticks number match the TickLabels number
|
---|
| 1578 | if numel(tickVals) == numel(tickStrs)
|
---|
| 1579 | set(hAxes, props{:}); % no exponent and matching ticks, so update both ticks and tick labels to manual
|
---|
| 1580 | end
|
---|
| 1581 | end
|
---|
[21671] | 1582 | catch % probably HG1
|
---|
[24460] | 1583 | % Fix for issue #220 - exponent is removed in HG1 when TickMode is 'manual' (internal Matlab bug)
|
---|
| 1584 | if isequal(tickVals, str2num(tickStrs)') %#ok<ST2NM>
|
---|
| 1585 | set(hAxes, props{:}); % revert back to old behavior
|
---|
| 1586 | end
|
---|
[21671] | 1587 | end
|
---|
| 1588 | end
|
---|
[18904] | 1589 | end
|
---|
[21315] | 1590 |
|
---|
| 1591 | function change_rgb_to_cmyk(fname) % convert RGB => CMYK within an EPS file
|
---|
| 1592 | % Do post-processing on the eps file
|
---|
| 1593 | try
|
---|
| 1594 | % Read the EPS file into memory
|
---|
| 1595 | fstrm = read_write_entire_textfile(fname);
|
---|
| 1596 |
|
---|
| 1597 | % Replace all gray-scale colors
|
---|
| 1598 | fstrm = regexprep(fstrm, '\n([\d.]+) +GC\n', '\n0 0 0 ${num2str(1-str2num($1))} CC\n');
|
---|
| 1599 |
|
---|
| 1600 | % Replace all RGB colors
|
---|
| 1601 | fstrm = regexprep(fstrm, '\n[0.]+ +[0.]+ +[0.]+ +RC\n', '\n0 0 0 1 CC\n'); % pure black
|
---|
| 1602 | 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');
|
---|
| 1603 |
|
---|
| 1604 | % Overwrite the file with the modified contents
|
---|
| 1605 | read_write_entire_textfile(fname, fstrm);
|
---|
| 1606 | catch
|
---|
| 1607 | % never mind - leave as is...
|
---|
| 1608 | end
|
---|
[18904] | 1609 | end
|
---|
[24460] | 1610 |
|
---|
| 1611 | function hBlackAxles = fixBlackAxle(hAxes, axleName)
|
---|
| 1612 | hBlackAxles = [];
|
---|
| 1613 | for idx = 1 : numel(hAxes)
|
---|
| 1614 | ax = hAxes(idx);
|
---|
| 1615 | axleColor = get(ax, axleName);
|
---|
| 1616 | if isequal(axleColor,[0,0,0]) || isequal(axleColor,'k')
|
---|
| 1617 | hBlackAxles(end+1) = ax; %#ok<AGROW>
|
---|
| 1618 | end
|
---|
| 1619 | end
|
---|
| 1620 | set(hBlackAxles, axleName, [0,0,0.01]); % off-black
|
---|
| 1621 | end
|
---|
| 1622 |
|
---|
| 1623 | % Issue #269: format-specific options
|
---|
| 1624 | function [optionsCells, bitDepth] = getFormatOptions(options, formatName)
|
---|
| 1625 | bitDepth = [];
|
---|
| 1626 | try
|
---|
| 1627 | optionsStruct = options.format_options.(lower(formatName));
|
---|
| 1628 | catch
|
---|
| 1629 | % User did not specify any extra parameters for this format
|
---|
| 1630 | optionsCells = {};
|
---|
| 1631 | return
|
---|
| 1632 | end
|
---|
| 1633 | optionNames = fieldnames(optionsStruct);
|
---|
| 1634 | optionVals = struct2cell(optionsStruct);
|
---|
| 1635 | optionsCells = [optionNames, optionVals]';
|
---|
| 1636 | if nargout < 2, return, end % bail out if BitDepth is not required
|
---|
| 1637 | try
|
---|
| 1638 | idx = find(strcmpi(optionNames,'BitDepth'), 1, 'last');
|
---|
| 1639 | if ~isempty(idx)
|
---|
| 1640 | bitDepth = optionVals{idx};
|
---|
| 1641 | end
|
---|
| 1642 | catch
|
---|
| 1643 | % never mind - ignore
|
---|
| 1644 | end
|
---|
| 1645 | end
|
---|